7 |
8 | ## Install
9 |
10 | 1. Install the `rcloud.rmd` package and this package on RCloud, using
11 | `devtools::install_github()` or `install-github.me`:
12 | ```R
13 | source("https://install-github.me/att/rcloud.rmd")
14 | source("https://install-github.me/att/rcloud.flexdashboard")
15 | ```
16 | 2. In the RCloud *Settings* menu, in the *Enable Extensions* line, add
17 | `rcloud.flexdashboard`, so that the package is loaded automatically.
18 | 3. Reload RCloud in the browser. This loads the package, and you should
19 | have the `flexdashboard.html` item in the special pages menu, right
20 | beside the RCloud logo in the top left corner
21 |
22 | ## Usage
23 |
24 | R Markdown code chunks correspond to `R` notebook cells, and R Markdown
25 | text corresponds to `markdown` notebook cells.
26 |
27 | To show the dashboard, select the `flexdashboard.html` special page, and
28 | then open it. `rcloud.flexdashboard` writes out an R Markdown file, calls
29 | `rmarkdown::render` on it, and then sends the outputted standalone HTML,
30 | embedded into an `iframe` to the browser.
31 |
32 | ## Developer notes
33 |
34 | The package uses `rcloud.rmd` to export the notebook to R Markdown.
35 |
36 | The only tricky part of the implementation is loading the `rcloud.flexdashboard`
37 | package when in the dashboard. The `call_notebook` OCAP could be used to
38 | evaluate the notebook, but this would require that the user loads the
39 | `rcloud.flexdashboard` package manually in the notebook, and also that the user
40 | calls a special function in the last cell to transfer the formatted notebook
41 | to the browser. This is a solution that is used in the `rcloud.rcap` package.
42 |
43 | Instead of this, we use a trick to trigger the loading of the package from JS.
44 | For this we call `rcloud._ocaps.load_module_package()` which loads the package
45 | as a side effect. We also need to define
46 | ```r
47 | .rcloud.export.ocaps <- function() { list() }
48 | ```
49 | in the R package to avoid an error, because `load_module_package()` evaluates
50 | this.
51 |
52 | When the package loads, we set up an OCAP in `.onLoad()`, and also assign it to
53 | `window.RCloudFlexDashboard`, so that we can call it from JS:
54 | ```js
55 | rcloud._ocaps.load_module_package(
56 | "rcloud.flexdashboard",
57 | function(x) {
58 | window.RCloudFlexDashboard.renderFlexDashboard(
59 | notebook,
60 | version,
61 | function(x) { console.log(x); }
62 | );
63 | }
64 | );
65 | ```
66 |
67 | The OCAP that we call simply saves the notebook to an R Markdown file (without
68 | actually evaluating it), and then calls `rmarkdown::render()` on it to create
69 | a standalone HTML file, which is then transmitted to the browser.
70 |
71 | While this implementation works for authenticated users, it does not currently
72 | work for anonymous users, and it might be rewritten completely, see e.g.
73 | https://github.com/att/rcloud.flexdashboard/issues/13
74 |
--------------------------------------------------------------------------------
/inst/www/js/rcloud-flexdashboard.js:
--------------------------------------------------------------------------------
1 | // jshint ignore: start
2 | function main() {
3 | function getURLParameter(name) {
4 | return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search)||[,""])[1].replace(/\+/g, '%20'))||null;
5 | }
6 |
7 | function getQueryArgs() {
8 | var r, res = {}, s = location.search;
9 | while ((r = (new RegExp('[?|&]([^=&]+?)=([^&;#]+)(.*)').exec(s))) !== null) {
10 | res[decodeURIComponent(r[1])] = decodeURIComponent(r[2]);
11 | s = r[3];
12 | }
13 | return res;
14 | }
15 |
16 | function onError(e) {
17 | $('#rcloud-flexdashboard-loading').remove();
18 | RCloud.UI.fatal_dialog(e.message, "Close");
19 | }
20 |
21 | rclient = RClient.create({
22 | debug: false,
23 | mode: "client", // "IDE" = edit (separated), "call" = API (one process), "client" = JS (currently one process but may change)
24 | host: location.href.replace(/^http/,"ws").replace(/#.*$/,""),
25 | on_connect: function(ocaps) {
26 | rcloud = RCloud.create(ocaps.rcloud);
27 | var promise;
28 | if (rcloud.authenticated) {
29 | promise = rcloud.session_init(rcloud.username(), rcloud.github_token());
30 | } else {
31 | promise = rcloud.anonymous_session_init();
32 | }
33 | promise = promise.then(function(hello) {
34 | rclient.post_response(hello);
35 | });
36 |
37 | // resolve(rcloud.init_client_side_data()); // what was this for?!?
38 |
39 | var notebook = getURLParameter("notebook"),
40 | version = getURLParameter("version");
41 | var tag = getURLParameter("tag");
42 | if(!version && tag) {
43 | promise = promise.then(function() {
44 | return rcloud.get_version_by_tag(notebook, tag)
45 | .then(function(v) {
46 | version = v;
47 | });
48 | });
49 | };
50 | promise = promise.then(function() {
51 | // Just tell R to load the rcloud.flexdashboard package,
52 | // and the packag will do the rest
53 | rcloud._ocaps.load_module_package(
54 | "rcloud.flexdashboard",
55 | function(x) {
56 | window.RCloudFlexDashboard.renderFlexDashboard(
57 | notebook,
58 | version,
59 | function(x) { console.log(x); }
60 | );
61 | }
62 | );
63 | });
64 | promise = promise.catch(onError);
65 | return true;
66 | },
67 | on_data: RCloud.session.on_data,
68 | on_oob_message: RCloud.session.on_oob_message,
69 | on_error: function(msg, status_code) {
70 | // debugger;
71 | if (msg == 'Login failed. Shutting down!') {
72 | window.location =
73 | (window.location.protocol +
74 | '//' + window.location.host +
75 | '/login.R?redirect=' +
76 | encodeURIComponent(window.location.pathname + window.location.search));
77 | return true;
78 | } else
79 | return false;
80 | }
81 | });
82 | }
83 |
--------------------------------------------------------------------------------
/inst/www/RCloud-flexo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------