diff --git a/index.html b/index.html index 493ede2b..105fab08 100644 --- a/index.html +++ b/index.html @@ -158,6 +158,9 @@

Events

Upcoming

Would you like to learn about Rhino hands-on? Join our events! Upcoming events will be added to this section - stay tuned.

+

Past diff --git a/pkgdown.yml b/pkgdown.yml index 58f97f39..4573c578 100644 --- a/pkgdown.yml +++ b/pkgdown.yml @@ -31,7 +31,7 @@ articles: create-your-first-rhino-app: tutorial/create-your-first-rhino-app.html use-react-in-rhino: tutorial/use-react-in-rhino.html write-end-to-end-tests-with-cypress: tutorial/write-end-to-end-tests-with-cypress.html -last_built: 2024-01-25T07:57Z +last_built: 2024-02-20T09:13Z urls: reference: https://appsilon.github.io/rhino/reference article: https://appsilon.github.io/rhino/articles diff --git a/search.json b/search.json index a6a68e8c..29b7a0a7 100644 --- a/search.json +++ b/search.json @@ -1 +1 @@ -[{"path":"https://appsilon.github.io/rhino/CONTRIBUTING.html","id":null,"dir":"","previous_headings":"","what":"Contributing guidelines","title":"Contributing guidelines","text":"document contains guidelines specific Rhino. Appsilon’s general contributing guidelines still apply.","code":""},{"path":"https://appsilon.github.io/rhino/CONTRIBUTING.html","id":"development-tools","dir":"","previous_headings":"","what":"Development tools","title":"Contributing guidelines","text":"R CMD checkdevtools::check() rcmdcheck::rcmdcheck() Run linterdevtools::lint() lintr::lint_package() Run unit testsdevtools::test()testthat::test_local() Check spellingdevtools::spell_check() spelling::spell_check_package() Build documentationdevtools::build_site() pkgdown::build_site() Build packagedevtools::build() pkgbuild::build()","code":""},{"path":"https://appsilon.github.io/rhino/CONTRIBUTING.html","id":"app-push-test","dir":"","previous_headings":"","what":"App Push Test","title":"Contributing guidelines","text":"Rhino comes CI setup box. rhino::init() creates rhino-test.yml file, GitHub Actions workflow automatically runs linters tests project pushed GitHub. test rhino-test.yml , app-push-test.yml workflow. initializes fresh Rhino application pushes bot/app-push-test branch. rhino-test.yml application runs results can viewed list workflow runs. App Push Test triggered automatically pushes main can also triggered manually branch via Actions tab. workflow requires fine-grained personal access token write access code workflows. saved APP_PUSH_TEST_PAT repository secret.","code":""},{"path":"https://appsilon.github.io/rhino/CONTRIBUTING.html","id":"website","dir":"","previous_headings":"","what":"Website","title":"Contributing guidelines","text":"documentation site built deployed automatically pkgdown.yml workflow. workflow triggered release published, pre-release changed release. also possible manually run selected tag/branch Actions tab.","code":""},{"path":[]},{"path":"https://appsilon.github.io/rhino/CONTRIBUTING.html","id":"preparation","dir":"","previous_headings":"Release process","what":"Preparation","title":"Contributing guidelines","text":"Announce planned release #proj-rhino (approximate date scope). Plan promotion (social media, blog post, …). Coordinate efforts marketing team. Ensure App Push Test passes (latest run main branch green). Create task track progress. Test upgrade installing Rhino current main branch. Continue release process. upgrade can completed task closed package accepted CRAN. Create release-X.Y.Z branch main. Bump package version according SemVer. Drop development version (last component, e.g. .9001). Replace (development version) X.Y.Z header. add link GitHub releases yet - link won’t work fail CRAN checks. Edit list changes make useful understandable users. See keep changelog guidelines. Submit changes pull request titled “Release X.Y.Z”. Get approved merged.","code":""},{"path":"https://appsilon.github.io/rhino/CONTRIBUTING.html","id":"submitting-to-cran","dir":"","previous_headings":"Release process","what":"Submitting to CRAN","title":"Contributing guidelines","text":"Checkout main branch ensure date. Build package devtools::build(). Test package R CMD check ---cran rhino_X.Y.Z.tar.gz. errors, warnings notes. Create new vX.Y.Z-rc.1 tag main branch (rc stands release candidate). Use tag name title. Leave description blank. Check “Set pre-release”. Click “Publish release”. Use name email. Click “Choose File” select rhino_X.Y.Z.tar.gz step 1. Click “Upload package”. Click “Submit package”. Click confirmation link sent opensource@appsilon.com. CRAN reviewers ask changes, implement return step 1. Use rc.2, rc.3 subsequent submissions.","code":""},{"path":"https://appsilon.github.io/rhino/CONTRIBUTING.html","id":"once-accepted-to-cran","dir":"","previous_headings":"Release process","what":"Once accepted to CRAN","title":"Contributing guidelines","text":"Create new vX.Y.Z tag main branch. Use tag name title. Fill description NEWS.md. Check “Set latest release”. Click “Publish release”. Add development version .9000 DESCRIPTION. Add # rhino (development version) header NEWS.md. Link # rhino X.Y.Z header GitHub release NEWS.md. Announce release #proj-rhino.","code":""},{"path":"https://appsilon.github.io/rhino/CONTRIBUTING.html","id":"development-process","dir":"","previous_headings":"","what":"Development process","title":"Contributing guidelines","text":"changes introduced pull requests main branch, must always kept “potentially shippable” state. Pull requests must peer-reviewed. reviewer inspects code, tests changes checks DoD approving. follow Semantic Versioning scheme. Starting 1.0.0, versions released CRAN.","code":""},{"path":"https://appsilon.github.io/rhino/CONTRIBUTING.html","id":"definition-of-done","dir":"","previous_headings":"","what":"Definition of Done","title":"Contributing guidelines","text":"PR least 1 approval 0 change requests. CI passes (R CMD check, linter, unit tests, spelling). change thoroughly documented.","code":""},{"path":"https://appsilon.github.io/rhino/PULL_REQUEST_TEMPLATE.html","id":"changes","dir":"","previous_headings":"","what":"Changes","title":"NA","text":"Closes #","code":""},{"path":[]},{"path":"https://appsilon.github.io/rhino/articles/explanation/application-structure.html","id":"philosophy","dir":"Articles > Explanation","previous_headings":"","what":"Philosophy","title":"Explanation: Application structure","text":"Shiny comes powerful reactive programming model rich set functions creating UI widgets custom HTML structure. features make possible quickly build impressive, interactive applications, can also make harder test reuse code. address issue, recommend separating code depends Shiny logic can expressed without . experience, division crucial building robust maintainable applications. support separation, Rhino encourages specific structure R sources application: main.R: entry point application. logic: Application code independent Shiny. view: Shiny modules related code.","code":""},{"path":"https://appsilon.github.io/rhino/articles/explanation/application-structure.html","id":"logic","dir":"Articles > Explanation","previous_headings":"Philosophy","what":"Logic","title":"Explanation: Application structure","text":"Use logic directory code can expressed without Shiny. Every Shiny app may different end goal, generally contain isolatable sections code can expressed normal R functions. data manipulation, generating non-interactive plots graphs, connecting external data source, outside definable inputs, doesn’t interact rely Shiny way. Code relies upon reactivity UI builder/markup functions can problematic test difficult reuse. proper design understanding concept, possible express application logic using plain R functions data structures (like lists, data frames).","code":""},{"path":"https://appsilon.github.io/rhino/articles/explanation/application-structure.html","id":"view","dir":"Articles > Explanation","previous_headings":"Philosophy","what":"View","title":"Explanation: Application structure","text":"view directory contain code describes user interface application relies upon reactive capabilities Shiny. use functions defined logic, core app functionality defined. familiar Shiny modules, please take time read concept. short, using modules can isolate paired Shiny UI/Server code, prevent overlap reactivity wrapping input/output value names ns() function. allows us “namespace” running module use multiple times application. important concept shortly summarize, new just remember want reference UI element server, needs namespaced. typical module structured like :","code":"box::use( shiny[moduleServer, NS, renderText, tagList, textInput, textOutput], ) box::use( app/logic/messages[hello_message], ) #' @export ui <- function(id) { ns <- NS(id) tagList( textInput(ns(\"name\"), \"Name\"), textOutput(ns(\"message\")) ) } #' @export server <- function(id) { moduleServer(id, function(input, output, session) { output$message <- renderText(hello_message(input$name)) }) }"},{"path":"https://appsilon.github.io/rhino/articles/explanation/application-structure.html","id":"minimal-app-r","dir":"Articles > Explanation","previous_headings":"","what":"Minimal app.R","title":"Explanation: Application structure","text":"Rhino application comes minimal app.R: important edit file use like global.R file, instead write top-level code app/main.R. also important note thanks shinyApp string comment, RStudio recognizes file Shiny application displays “Run” “Publish” buttons. approach gives Rhino full control startup processes application. Steps performed rhino::app() include: Purge box cache, app can reloaded without restarting R session. Configure logger (log level, log file). Configure static files. Load main module / legacy entrypoint. Add head tags (favicon, CSS & JS). fair question ask really need separate main.R file. Couldn’t just define top-level ui server app.R pass rhino::app() arguments normal shiny::shinyApp() call? reasoning behind structure enforce consistent use box modules throughout application. file loaded box::use() can load modules/packages box::use(). short, means use library() source() functions app. important distinction traditional Shiny structure, simply sourcing app.R app loaded. entire Rhino application loaded box::use(app/main), sources must properly structured box modules.","code":"# Rhino / shinyApp entrypoint. Do not edit. rhino::app()"},{"path":"https://appsilon.github.io/rhino/articles/explanation/box-modules.html","id":"rationale","dir":"Articles > Explanation","previous_headings":"","what":"Rationale","title":"Explanation: Box modules","text":"large applications critical maintainability properly structure code using files directories. R comes library() source() functions, functionality limited comes dividing code modules expressing dependencies. address , Rhino uses box R package, allows modularize code similar way languages like Python Java: Box modules force explicit dependencies files packages. graph dependencies visible glance app developed box, traditional approach (global.R, library(), source()) makes easy build app author understands. Introduction box existing apps written without helped improve code structure find bugs.","code":"box::use( dplyr, # Import dplyr. Its functions can be used via `$`, e.g. `dplyr$filter`. shiny[reactive], # Import the `reactive()` function from shiny package. ) box::use( logic/data_validation, # Import the `logic/data_validation.R` module. )"},{"path":"https://appsilon.github.io/rhino/articles/explanation/box-modules.html","id":"usage","dir":"Articles > Explanation","previous_headings":"","what":"Usage","title":"Explanation: Box modules","text":"best place learn box official documentation. discussion mainly focus use box inside Rhino. Rhino suggests use app/logic app/view. Rhino creates directories default. Code independent Shiny kept app/logic code using related Shiny modules kept app/view. structure makes easy make nested hierarchy code help box. say_hello() say_bye() can exported app/logic/messages.R. Note box::use() allows explicit attaching function names module shown . Modules can also imported across directories; use code app/logic app/view. explicit attaching function names, clear code uses shiny.semantic::textInput() shiny::textInput(). main.R, Shiny modules can attached without attaching function names. Shiny module functions accessed via $.","code":"# app/logic/messages.R #' @export say_hello <- function(name) { paste0(\"Hello, \", name, \"!\") } #' @export say_bye <- function(name) { paste0(\"Goodbye, \", name, \"!\") } box::use(app/logic/messages[say_hello, say_bye]) #' @export greet <- function(name) { paste( say_hello(name), say_bye(name) ) } # app/view/greet_module.R box::use( shiny[moduleServer, NS, renderText, div, textOutput, req], shiny.semantic[textInput], ) box::use( app/logic/greet[greet], ) #' @export ui <- function(id) { ns <- NS(id) div( textInput(ns(\"name\"), \"Name\"), textOutput(ns(\"message\")) ) } #' @export server <- function(id) { moduleServer(id, function(input, output, session) { output$message <- renderText({ req(input$name) greet(input$name) }) }) } # app/main.R box::use( shiny[moduleServer, NS], shiny.semantic[semanticPage] ) box::use(app/view/greet_module) #' @export ui <- function(id) { ns <- NS(id) semanticPage( greet_module$ui(ns(\"message\")) ) } #' @export server <- function(id) { moduleServer(id, function(input, output, session) { greet_module$server(\"message\") }) }"},{"path":"https://appsilon.github.io/rhino/articles/explanation/box-modules.html","id":"advanced-features","dir":"Articles > Explanation","previous_headings":"","what":"Advanced Features","title":"Explanation: Box modules","text":"useful box features also explained sections .","code":""},{"path":"https://appsilon.github.io/rhino/articles/explanation/box-modules.html","id":"init-files","dir":"Articles > Explanation","previous_headings":"Advanced Features","what":"Init files","title":"Explanation: Box modules","text":"Objects exported __init__.R file can imported parent directory.","code":""},{"path":"https://appsilon.github.io/rhino/articles/explanation/box-modules.html","id":"example","dir":"Articles > Explanation","previous_headings":"Advanced Features > Init files","what":"Example","title":"Explanation: Box modules","text":"Assume app/foo/__init__.R file following content: can now import bar defined app/foo.R: mechanism can used combination reexports make easier import multiple modules single directory.","code":"#' @export bar <- \"Hello!\" box::use( app/foo[bar] )"},{"path":"https://appsilon.github.io/rhino/articles/explanation/box-modules.html","id":"reexports","dir":"Articles > Explanation","previous_headings":"Advanced Features","what":"Reexports","title":"Explanation: Box modules","text":"module can reexport objects imported different module applying #' @export box::use() statement.","code":""},{"path":"https://appsilon.github.io/rhino/articles/explanation/box-modules.html","id":"example-1","dir":"Articles > Explanation","previous_headings":"Advanced Features > Reexports","what":"Example","title":"Explanation: Box modules","text":"Assume modules analysis_tab.R download_tab.R app/view directory. can reexport app/view/__init__.R like : following box::use() statements now equivalent:","code":"#' @export box::use( app/view/analysis_tab, app/view/download_tab ) box::use( app/view/analysis_tab, app/view/download_tab, ) box::use( app/view[analysis_tab, download_tab], )"},{"path":"https://appsilon.github.io/rhino/articles/explanation/box-modules.html","id":"known-issues","dir":"Articles > Explanation","previous_headings":"","what":"Known issues","title":"Explanation: Box modules","text":"following issues fixed box v1.1.3, required Rhino starting v1.4.0. section left reference.","code":""},{"path":"https://appsilon.github.io/rhino/articles/explanation/box-modules.html","id":"lazy-loaded-data","dir":"Articles > Explanation","previous_headings":"Known issues","what":"Lazy-loaded data","title":"Explanation: Box modules","text":"Prior v1.1.3 box didn’t support lazy-loaded data, e.g. box::use(datasets[mtcars]) wouldn’t work (see issue). possible workaround using datasets::mtcars instead.","code":""},{"path":"https://appsilon.github.io/rhino/articles/explanation/box-modules.html","id":"trailing-commas","dir":"Articles > Explanation","previous_headings":"Known issues","what":"Trailing commas","title":"Explanation: Box modules","text":"Box allows trailing commas box::use() statements code, prior v1.1.3 cause problems circumstances: Reexports (issue). Functions accessed via $ (issue).","code":""},{"path":"https://appsilon.github.io/rhino/articles/explanation/node-js-javascript-and-sass-tools.html","id":"about","dir":"Articles > Explanation","previous_headings":"","what":"About","title":"Explanation: Node.js - JavaScript and Sass tools","text":"Node.js runtime environment can execute JavaScript code outside web browser. used widely web development. package manager, npm, makes easy install virtually JavaScript library. can use package managers bun pnpm compatible npm. switch default npm usage, set global environment variable named RHINO_NPM. instance, want use bun instead npm, add export RHINO_NPM=bun shell startup file (e.g. .bashrc). Rhino uses Node.js provide state art tools working JavaScript Sass. following functions require Node.js work: build_js() build_sass() (sass: node configuration rhino.yml) lint_js() lint_sass() test_e2e()","code":""},{"path":"https://appsilon.github.io/rhino/articles/explanation/node-js-javascript-and-sass-tools.html","id":"node-directory","dir":"Articles > Explanation","previous_headings":"About","what":"Node directory","title":"Explanation: Node.js - JavaScript and Sass tools","text":"hood Rhino create .rhino directory project store specific libraries needed tools. directory git-ignored default safe remove.","code":""},{"path":"https://appsilon.github.io/rhino/articles/explanation/node-js-javascript-and-sass-tools.html","id":"node-installation-via-nvm","dir":"Articles > Explanation","previous_headings":"About","what":"Node installation via nvm","title":"Explanation: Node.js - JavaScript and Sass tools","text":"Node can installed various ways. One relies nvm (Node Version Manager). ’s known issue using multiple versions Node installed nvm causes RStudio recognize properly chosen version. ’s caused nvm RStudio can easily mitigated starting RStudio terminal: Ubuntu/Debian Open terminal choice (.e. Bash) run Windows Open Windows terminal choice (.e. Terminal, PowerShell, Git Bash) run: Mac Open Mac terminal choice (.e. default Terminal) run:","code":"rstudio path/to/your/rstudio/folder/Rstudio.exe open -na Rstudio"},{"path":"https://appsilon.github.io/rhino/articles/explanation/node-js-javascript-and-sass-tools.html","id":"build_sass-function","dir":"Articles > Explanation","previous_headings":"About","what":"build_sass() function","title":"Explanation: Node.js - JavaScript and Sass tools","text":"build_sass() function worth additional comment. Depending configuration rhino.yml can use either sass Node.js package sass R package. recommend Node.js version, primary, actively developed implementation Sass. contrast, R package uses deprecated LibSass implementation.","code":""},{"path":"https://appsilon.github.io/rhino/articles/explanation/renv-configuration.html","id":"snapshot-types","dir":"Articles > Explanation","previous_headings":"","what":"Snapshot types","title":"Explanation: Renv configuration","text":"renv offers different snapshot types. default performs implicit snapshot: tries detect dependencies project scanning R sources. convenient small projects, approach lacks fine control can inefficient larger code bases. preferable use explicit snapshots: dependencies project must listed DESCRIPTION file. Unfortunately faced issues snapshot type deployments. Instead, Rhino uses following setup: Implicit snapshot (configured renv/settings.dcf). dependencies.R file dependencies listed explicitly library() calls. .renvignore file tells renv read dependencies.R. solution offers us benefits explicit snapshots (fine control, efficiency) works well deployment.","code":""},{"path":"https://appsilon.github.io/rhino/articles/explanation/renv-configuration.html","id":"manual-dependency-management","dir":"Articles > Explanation","previous_headings":"","what":"Manual dependency management","title":"Explanation: Renv configuration","text":"cases functions need rhino::pkg_install() rhino::pkg_remove(). However still possible manage dependencies using underlying renv functions directly. can helpful unusual situations (e.g. broken lockfile, installing specific package version). renv save lockfile packages installed local library, remove packages installed. Thus always run renv::restore(clean = TRUE) performing steps .","code":""},{"path":"https://appsilon.github.io/rhino/articles/explanation/renv-configuration.html","id":"add-a-dependency","dir":"Articles > Explanation","previous_headings":"Manual dependency management","what":"Add a dependency","title":"Explanation: Renv configuration","text":"Add library(package) line dependencies.R. Call renv::install(\"package\"). Call renv::snapshot().","code":""},{"path":"https://appsilon.github.io/rhino/articles/explanation/renv-configuration.html","id":"update-a-dependency","dir":"Articles > Explanation","previous_headings":"Manual dependency management","what":"Update a dependency","title":"Explanation: Renv configuration","text":"Call renv::update(\"package\"). Call renv::snapshot(). Calling renv::install(\"package\") instead renv::update(\"package\") effect.","code":""},{"path":"https://appsilon.github.io/rhino/articles/explanation/renv-configuration.html","id":"remove-a-dependency","dir":"Articles > Explanation","previous_headings":"Manual dependency management","what":"Remove a dependency","title":"Explanation: Renv configuration","text":"Remove library(package) line dependencies.R. Call renv::snapshot(). Call renv::restore(clean = TRUE). recommended use renv::remove() function, remove package local library even still required packages. example, renv::remove(\"glue\") followed renv::snapshot() leave without glue package lockfile, even though required shiny.","code":""},{"path":"https://appsilon.github.io/rhino/articles/explanation/rhino-yml.html","id":"configure-rhino-with-rhino-yml","dir":"Articles > Explanation","previous_headings":"","what":"Configure Rhino with rhino.yml","title":"Explanation: Configuring Rhino - rhino.yml","text":"Rhino uses rhino.yml config file can set options works app. Currently available options described .","code":""},{"path":"https://appsilon.github.io/rhino/articles/explanation/rhino-yml.html","id":"rhino-yml-options","dir":"Articles > Explanation","previous_headings":"Configure Rhino with rhino.yml","what":"rhino.yml options","title":"Explanation: Configuring Rhino - rhino.yml","text":"","code":"sass: string # required | one of: \"node\", \"r\" legacy_entrypoint: string # optional | one of: \"app_dir\", \"source\", \"box_top_level\""},{"path":"https://appsilon.github.io/rhino/articles/explanation/rhino-yml.html","id":"sass","dir":"Articles > Explanation","previous_headings":"Configure Rhino with rhino.yml > rhino.yml options","what":"sass","title":"Explanation: Configuring Rhino - rhino.yml","text":"Configures whether Sass built using R package Node.js package. Read Explanation: Node.js - JavaScript Sass tools.","code":""},{"path":"https://appsilon.github.io/rhino/articles/explanation/rhino-yml.html","id":"legacy_entrypoint","dir":"Articles > Explanation","previous_headings":"Configure Rhino with rhino.yml > rhino.yml options","what":"legacy_entrypoint","title":"Explanation: Configuring Rhino - rhino.yml","text":"setting useful migrating existing Shiny application Rhino. details see rhino::app() details section.","code":""},{"path":"https://appsilon.github.io/rhino/articles/explanation/what-is-rhino.html","id":"what-is-rhino","dir":"Articles > Explanation","previous_headings":"","what":"What is Rhino?","title":"Explanation: What is Rhino?","text":"Rhino R package designed help build high quality, enterprise-grade Shiny applications speed. allows create Shiny apps “Appsilon Way” - like fullstack software engineer: apply best software engineering practices, modularize code, test well, make UI beautiful think adoption beginning. Rhino opinionated framework focus best practices development tools. started series internal projects Appsilon aiming : Save time avoid repetitive tasks: include best practices care beginning project. Unify applications’ architecture: provide sensible defaults don’t reinvent wheel. Automate codify existing practices: pass knowledge form code instead documents manuals. past years, building internal tools address issues help us easily structure projects fast way. since evolved R package now excited share Shiny community. Please keep mind project early stages. wanted get something R community look forward continuing development feedback users. just beginning.","code":""},{"path":"https://appsilon.github.io/rhino/articles/explanation/what-is-rhino.html","id":"why-rhino","dir":"Articles > Explanation","previous_headings":"","what":"Why Rhino?","title":"Explanation: What is Rhino?","text":"Rhino helps build Shiny apps faster, making reliable easier maintain. bundles coherent way set tools practices beneficial Shiny applications, especially enterprise. may want use Rhino : need nested files structure handle bigger application. want follow complete set solutions built industry experience, avoid spending time “reinventing wheel”. ’d like scalable, modularized application clear code organization neat separation responsibilities. Rhino can serve guide understanding concepts (box, Shiny modules, view / logic separation). want save time avoid repetitive tasks. Rhino allows quickly start Shiny project set preconfigured development tools (linters, CI, Cypress, logging, Sass JS building) building application production use enterprise - need make sure ’s highly maintainable reliable long term. Shiny applications can converted Rhino project less 2 hours.","code":""},{"path":"https://appsilon.github.io/rhino/articles/explanation/what-is-rhino.html","id":"similar-projects","dir":"Articles > Explanation","previous_headings":"","what":"Similar projects","title":"Explanation: What is Rhino?","text":"Rhino first project kind aimed helping Shiny community enhance structure applications. believe value, developer decide best project. Rhino different …? golem: Rhino apps R packages. Rhino puts emphasis development tools, clean configuration minimal boilerplate tries provide default solutions typical problems questions areas. leprechaun: Leprechaun works scaffolding Shiny apps, without adding dependencies. Rhino minimizes generated code aims provide complete foundation building Shiny apps ready deployment enterprise, can focus application’s logic user experience. devtools: devtools streamlines packages development. Rhino complete framework building Shiny apps. Rhino features interdependent (e.g. coverage unit tests) used without making app basic Rhino structure. usethis: usethis adds independent code snippets ask . Rhino complete framework building Shiny apps. app designed call Rhino functions instead insert code project.","code":""},{"path":"https://appsilon.github.io/rhino/articles/faq.html","id":"running-and-deployment","dir":"Articles","previous_headings":"","what":"Running and deployment","title":"FAQ","text":"run Rhino application? can run Rhino application exactly regular Shiny app: using shiny::runApp() using “Run app” button RStudio use specific port running Rhino application? can: set port shiny::runApp, e.g. shiny:runApp(port = 5000) add options(shiny.port = 5000) .Rprofile file details can found -: Set application run parameters. deploy Rhino application? case regular Shiny app, e.g. can use “Deploy” button RStudio IDE.","code":""},{"path":"https://appsilon.github.io/rhino/articles/faq.html","id":"differences-between-rhino-and-vanilla-shiny","dir":"Articles","previous_headings":"","what":"Differences between Rhino and vanilla Shiny","title":"FAQ","text":"server.R ui.R files? Instead server.R ui.R, Rhino uses single file app/main.R. includes server UI part application. main difference already Shiny modules need use namespace (ns) UI part. global.R file? Rhino encourages work encapsulated modules instead using global objects, thus include global.R file. Instead, objects default available level particular script. Depending context, objects can shared explicitly, passed argument exported @export. put library calls? Rhino application doesn’t use library load packages. Instead, script imports dependencies box::use: place use library calls dependencies.R file. can read managing R dependencies article. www directory? Instead www, Rhino uses app/static. utilize , need provide path assets include static, example:","code":"box::use( dplyr, # functions from `dplyr` are available using `$`, e.g. `dplyr$mutate()` shiny[div, moduleServer, NS], # `div`, `moduleServer`, and `NS` are available (but other functions from `shiny` are not) ) img(src = \"static/images/appsilon-logo.png\")"},{"path":"https://appsilon.github.io/rhino/articles/faq.html","id":"common-problems","dir":"Articles","previous_headings":"","what":"Common problems","title":"FAQ","text":"doesn’t input trigger reactive chain? Rhino uses Shiny modules encapsulate whole application, id every input create needs wrapped ns, example: output visible? Rhino uses Shiny modules encapsulate whole application, id every output create needs wrapped ns, example: shinyBS working Rhino application. shinyBS uses .onAttach() hook call shiny::addResourcePath() necessary resources (JS CSS) loaded correctly. hook never run box::use() (normally library() call run ). worth noting problem also present vanilla Shiny use :: access shinyBS functions (shinyBS use .onLoad() instead). Workaround: Add following snippet app/main.R (just box::use() statements good place): ’ll still need explicitly box::use() whatever functions need shinyBS (library() doesn’t work box module). details can found . R package installed, renv::snapshot() didn’t add renv.lock file. Rhino, renv uses packages added dependencies.R file. way full control libraries used application. Adding library(package name) dependencies.R file fix problem. Check also: renv configuration dependencies management.","code":"box::use( shiny[NS, textInput], ) #' @export ui <- function(id) { ns <- NS(id) textInput( inputId = ns(\"my_input\"), label = \"My Input\" ) } box::use( shiny[moduleServer, NS, renderText, textOutput], ) #' @export ui <- function(id) { ns <- NS(id) textOutput(ns(\"text\")) } #' @export server <- function(id) { moduleServer(id, function(input, output, session) { output$text <- renderText(\"This is a message!\") }) } # Run the `.onAttach` hook (shinyBS uses it to add a Shiny resource path). suppressWarnings(library(shinyBS))"},{"path":"https://appsilon.github.io/rhino/articles/faq.html","id":"styling-rhino-application","dir":"Articles","previous_headings":"","what":"Styling Rhino application","title":"FAQ","text":"Can use multiple Sass files? Yes, can file/directory structure app/styles desire. app/styles/main.scss entry point: ’ll need @use files main.scss. running rhino::build_sass() sufficient include styles application.","code":""},{"path":"https://appsilon.github.io/rhino/articles/how-to/communicate-between-modules.html","id":"introduction","dir":"Articles > How-to","previous_headings":"","what":"Introduction","title":"How-to: Communicate between modules","text":"State management topic comes along often comes reactive programming. application grows size becomes intricate, ’s common find increasing number Shiny modules distributed across various levels depth. results necessity share information, particularly application’s state, among diverse Shiny modules. many ways approach problem going present two examples. first example going pass information (reactive variables) parent module child module second example going pass information two sibling modules.","code":""},{"path":[]},{"path":"https://appsilon.github.io/rhino/articles/how-to/communicate-between-modules.html","id":"example-1---communicating-between-a-parent-module-and-its-children-modules","dir":"Articles > How-to","previous_headings":"Examples","what":"Example 1 - Communicating between a parent module and its children modules","title":"How-to: Communicate between modules","text":"example going two modules. parent module load process data using filters pass child module display table processed data. Figure 1. Diagram illustrating reactive value passed parent child module. Now, let’s explore code look like: Let’s start table module. Remember Figure 1 module receives reactive object data display parent module. continue usage table module within parent module. read_data_from_database process_data imported utils.R module mocked functions using purpose aiding example. funcions defined example code.","code":"box::use( shiny[div, moduleServer, NS, renderTable, req, tableOutput], ) #' @export ui <- function(id) { ns <- NS(id) div( tableOutput( outputId = ns(\"table\") ) ) } #' @params id The Id of this shiny module #' @params table_data A reactive that contains that the data that will be #' displayed in the table. #' @export server <- function(id, table_data) { moduleServer(id, function(input, output, session) { output$table <- renderTable({ req(table_data()) table_data() }) }) } # Parent Module box::use( shiny[ div, moduleServer, NS, observeEvent, reactiveVal, req, selectInput ], ) box::use( table_module = app/view/table_module.R, utils = utils/utils.R # This module is not defined in this example ) #' @export ui <- function(id) { ns <- NS(id) div( selectInput( inputId = ns(\"filters\"), label = \"Select filters\", choices = c(\"Parameter A\", \"Parameter B\", \"Parameter C\") ), table_module$ui(ns(\"table_module\")) ) } #' @export server <- function(id) { moduleServer(id, function(input, output, session) { # Define a reactive variable to pass down the table module processed_data <- reactiveVal() input_data <- utils$read_data_from_database() observeEvent(input$filters, { utils$processed_data( process_data(input_data, input$filters) ) }) # Initialize the table module server function table_module$server(id = \"table_module\", table_data = processed_data) }) }"},{"path":"https://appsilon.github.io/rhino/articles/how-to/communicate-between-modules.html","id":"example-2---communicating-between-two-sibling-modules","dir":"Articles > How-to","previous_headings":"Examples","what":"Example 2 - Communicating between two sibling modules","title":"How-to: Communicate between modules","text":"Suppose data processing module plotting module, functioning siblings, respective roles process exhibit data given plot. sibling modules nested within another module, ’ve denoted main.R main module within Rhino app. Figure 2. Diagram illustrating reactive value passed sibling modules. Let’s explore code modules look like: read_data_from_database process_data imported utils.R module mocked functions using purpose aiding example. funcions defined example code. plotting module: sibling modules ready use main.R function. Pay special attention server function save output data processing module variable pass plot module. sum , aforementioned example, ’ve established reactive variable within data processing module, responsible holding processed data generated module. Subsequently, module returns said reactive variable, passed server function plotting module. plotting module utilizes specific reactive variable, containing processed data, create visualizations.","code":"# processing_data_module.R box::use( shiny[ div, moduleServer, NS, observeEvent, reactiveVal, req, selectInput ], ) box::use( utils = utils/utils.R # This module is not defined in this example ) #' @export ui <- function(id) { ns <- NS(id) div( selectInput( inputId = ns(\"parameter\"), label = Select a parameter, choices = c(\"alfa\", \"beta\", \"gamma\") ) ) } #' @export server <- function(id) { moduleServer(id, function(input, output, session) { data_to_display <- reactiveVal() example_data <- utils$read_data_from_database() observeEvent(input$parameter, { # Updates the data_to_display reactive variable data_to_display( utils$process_data(example_data, input$parameter) ) } # Returns the reactive data_to_display }) } # plotting_module.R box::use( shiny[div, moduleServer, NS, plotOutput, renderPlot, req], graphics[plot], ) #' @params id Id of the module #' @export ui <- function(id) { ns <- NS(id) div( plotOutput( inputId = ns(\"plot\") ) ) ) #' @params id Id of the module #' @params data_to_display A reactive that contains that the data that will be #' plotted #' @export server <- function(id, data_to_display) { moduleServer(id, function(input, output, session) { output$plot <- renderPlot({ req(data_to_display) plot(data_to_display()) }) }) } box::use( shiny[bootstrapPage, div, moduleServer, NS], ) box::use( data_module = app/view/processing_data_module, plot_module = app/view/plotting_module ) #' @export ui <- function(id) { ns <- NS(id) bootstrapPage( div( data_module(ns(\"data_module\")) ), div( plot_module$ui(ns(\"plot_module\")) ) ) } #' @export server <- function(id) { moduleServer(id, function(input, output, session) { # Saving the output of the data_module data_to_display <- data_module$server(\"data_module\") # Passing `data_to_display` to the sibling module plot_module$server(\"plot_module\", data_to_display) }) }"},{"path":"https://appsilon.github.io/rhino/articles/how-to/manage-secrets-and-environments.html","id":"secrets","dir":"Articles > How-to","previous_headings":"","what":"Secrets","title":"How to: Manage secrets and environments","text":"Secrets confidential information tracked version control system. Therefore, natural place system environment variables. Variables set system environment can retrieved within code Sys.getenv(). R provides way easily set environment variables. Upon session start (restart) R reads .Renviron file contents sets environment variables. .Renviron Secrets defined via environment variables can read used following way:","code":"# A comment in .Renviron file DATABASE_PASSWORD=\"foobar123!\" API_KEY=\"75170fc230cd88f32e475ff4087f81d9\" db_password <- Sys.getenv(\"DATABASE_PASSWORD\") if (db_password == \"\") { # Handle unset or empty DATABASE_PASSWORD variable } pool <- pool::dbPool( drv = RMySQL::MySQL(), dbname = \"...\", host = \"...\", username = \"admin\", password = db_password )"},{"path":"https://appsilon.github.io/rhino/articles/how-to/manage-secrets-and-environments.html","id":"recommendations-for-storing-secrets","dir":"Articles > How-to","previous_headings":"Secrets","what":"Recommendations for storing secrets","title":"How to: Manage secrets and environments","text":"Store secrets environment variables .Renviron. Use separate .Renviron file every environment. Swap whole file changing environments. Use CONSTANT_CASE variable names. track .Renviron file version control system. Store secure location, e.g. password manager. publish .Renviron RStudio Connect shinyapps.io. , RStudio Connect Shiny Apps, provide means manage environment variables.","code":""},{"path":"https://appsilon.github.io/rhino/articles/how-to/manage-secrets-and-environments.html","id":"environments","dir":"Articles > How-to","previous_headings":"","what":"Environments","title":"How to: Manage secrets and environments","text":"every configurable setting stored environment variable result overgrown .Renviron files. ’s configurable environments come . Everything confidential can tracked version control system. Rhino endorses use config package managing environments. config.yml .Renviron can access configuration variables following way:","code":"default: rhino_log_level: !expr Sys.getenv(\"RHINO_LOG_LEVEL\", \"INFO\") rhino_log_file: !expr Sys.getenv(\"RHINO_LOG_FILE\", NA) database_user: \"service_account\" database_schema: \"dev\" dev: rhino_log_level: !expr Sys.getenv(\"RHINO_LOG_LEVEL\", \"DEBUG\") staging: database_schema: \"stg\" production: database_user: \"service_account_prod\" database_schema: \"prod\" R_CONFIG_ACTIVE=\"dev\" box::use(config) config$get(\"rhino_log_level\") # == \"DEBUG\" config$get(\"database_user\") # == \"service_account\" config$get(\"rhino_log_level\", config = \"production\") # == \"INFO\" config$get(\"database_user\", config = \"production\") # == \"service_account_prod\" withr::with_envvar(list(RHINO_LOG_LEVEL = \"ERROR\"), { config$get(\"rhino_log_level\") # == \"ERROR\" config$get(\"rhino_log_level\", config = \"production\") # == \"ERROR\" })"},{"path":"https://appsilon.github.io/rhino/articles/how-to/manage-secrets-and-environments.html","id":"recommendations-for-managing-environments","dir":"Articles > How-to","previous_headings":"Environments","what":"Recommendations for managing environments","title":"How to: Manage secrets and environments","text":"Define environments settings config.yml. Select config setting R_CONFIG_ACTIVE variable .Renviron. Make use default values. Use !expr Sys.getenv() make settings overridable environment variables. Import config box call usual, .e. box::use(config) config$get(). Use snake_case field names.","code":""},{"path":"https://appsilon.github.io/rhino/articles/how-to/migrate-1-6.html","id":"prerequisites","dir":"Articles > How-to","previous_headings":"","what":"Prerequisites","title":"How-to: Rhino 1.6 Migration Guide","text":"Back project data. Ensure Node.js --date machine.","code":""},{"path":"https://appsilon.github.io/rhino/articles/how-to/migrate-1-6.html","id":"installation-of-rhino-1-6","dir":"Articles > How-to","previous_headings":"","what":"Installation of Rhino 1.6","title":"How-to: Rhino 1.6 Migration Guide","text":"Choose one following methods install Rhino 1.6:","code":""},{"path":"https://appsilon.github.io/rhino/articles/how-to/migrate-1-6.html","id":"option-1-using-renv","dir":"Articles > How-to","previous_headings":"Installation of Rhino 1.6","what":"Option 1: Using renv","title":"How-to: Rhino 1.6 Migration Guide","text":"Install Rhino using renv take snapshot project dependencies:","code":"renv::install(\"rhino\") renv::snapshot()"},{"path":"https://appsilon.github.io/rhino/articles/how-to/migrate-1-6.html","id":"option-2-using-rhinopkg_install-for-rhino-v1-4","dir":"Articles > How-to","previous_headings":"Installation of Rhino 1.6","what":"Option 2: Using rhino::pkg_install (for Rhino v1.4+)","title":"How-to: Rhino 1.6 Migration Guide","text":"newer versions Rhino, can use built-package installation function: installation, restart R session ensure changes take effect.","code":"rhino::pkg_install(\"rhino\")"},{"path":[]},{"path":"https://appsilon.github.io/rhino/articles/how-to/migrate-1-6.html","id":"step-1-remove-the--rhino-directory","dir":"Articles > How-to","previous_headings":"Migration Steps","what":"Step 1: Remove the .rhino Directory","title":"How-to: Rhino 1.6 Migration Guide","text":"Locate remove .rhino directory root project. directory contains configuration settings previous version Rhino.","code":"rm -rf .rhino"},{"path":"https://appsilon.github.io/rhino/articles/how-to/migrate-1-6.html","id":"step-2-run-node-tool-functions","dir":"Articles > How-to","previous_headings":"Migration Steps","what":"Step 2: Run Node Tool Functions","title":"How-to: Rhino 1.6 Migration Guide","text":"Invoke one following commands run Node tools. action regenerate .rhino directory new configuration, including updated Node modules.","code":"rhino::build_sass() rhino::lint_sass() rhino::build_js() rhino::lint_js()"},{"path":"https://appsilon.github.io/rhino/articles/how-to/migrate-1-6.html","id":"step-3-migrate-cypress-end-to-end-tests","dir":"Articles > How-to","previous_headings":"Migration Steps","what":"Step 3: Migrate Cypress End-to-End Tests","title":"How-to: Rhino 1.6 Migration Guide","text":"project includes Cypress end--end tests, initiate migration wizard : Follow prompts migration wizard update end--end tests.","code":"rhino::test_e2e(interactive = TRUE)"},{"path":"https://appsilon.github.io/rhino/articles/how-to/migrate-1-6.html","id":"step-4-test-your-project","dir":"Articles > How-to","previous_headings":"Migration Steps","what":"Step 4: Test Your Project","title":"How-to: Rhino 1.6 Migration Guide","text":"Conduct extensive testing confirm components project function properly migration.","code":""},{"path":"https://appsilon.github.io/rhino/articles/how-to/migrate-1-6.html","id":"final-steps","dir":"Articles > How-to","previous_headings":"","what":"Final Steps","title":"How-to: Rhino 1.6 Migration Guide","text":"encounter issues questions migrating Rhino 1.6, please consult GitHub discussions Rhino community developer support.","code":""},{"path":"https://appsilon.github.io/rhino/articles/how-to/migrate-app-to-rhino.html","id":"prepare-your-application-for-rhinoinit","dir":"Articles > How-to","previous_headings":"","what":"Prepare Your Application for rhino::init()","title":"How-to: Migrate app to Rhino","text":", able run application using shiny::shinyAppDir(\"app\").","code":". └── app ├── utils │ ├── bar.R │ └── foo.R ├── www │ ├── main.css │ └── main.js ├── server.R └── ui.R . ├── app │ ├── utils │ │ ├── bar.R │ │ └── foo.R │ ├── www │ │ ├── main.css │ │ └── main.js │ ├── server.R │ └── ui.R └── dependencies.R"},{"path":"https://appsilon.github.io/rhino/articles/how-to/migrate-app-to-rhino.html","id":"what-if-my-app-uses-renv","dir":"Articles > How-to","previous_headings":"Prepare Your Application for rhino::init()","what":"What if: My App Uses renv","title":"How-to: Migrate app to Rhino","text":"used renv application, chances active renv session Rhino installed. address either deactivate renv run renv::install(\"rhino\"). Apart additional files related renv, target file structure different one presented .","code":""},{"path":"https://appsilon.github.io/rhino/articles/how-to/migrate-app-to-rhino.html","id":"initialize-your-rhino-application","dir":"Articles > How-to","previous_headings":"","what":"Initialize Your Rhino Application","title":"How-to: Migrate app to Rhino","text":"use renv , Rhino initialized . However, use renv, Rhino added necessary dependencies renv.lock file.","code":". ├── .github │ └── workflows │ └── rhino-test.yml ├── app │ ├── js │ │ └── index.js │ ├── logic │ │ └── __init__.R │ ├── static │ │ └── favicon.ico │ ├── styles │ │ └── main.scss │ ├── utils │ │ ├── bar.R │ │ └── foo.R │ ├── view │ │ └── __init__.R │ ├── www │ │ ├── main.css │ │ └── main.js │ ├── main.R │ ├── server.R │ └── ui.R ├── renv │ └── ... ├── tests │ ├── cypress │ │ ├── e2e │ │ └── .gitignore │ ├── testthat │ │ └── test-main.R │ └── cypress.json ├── .Rprofile ├── .lintr ├── .renvignore ├── app.R ├── dependencies.R ├── old.Rprofile ├── renv.lock ├── rhino.yml └── app.Rproj"},{"path":"https://appsilon.github.io/rhino/articles/how-to/migrate-app-to-rhino.html","id":"what-if-my-app-had--rprofile","dir":"Articles > How-to","previous_headings":"Initialize Your Rhino Application","what":"What if: My App Had .Rprofile","title":"How-to: Migrate app to Rhino","text":".Rprofile moved old.Rprofile. contained relevant bits (e.g. setting options), carry .Rprofile created Rhino.","code":""},{"path":"https://appsilon.github.io/rhino/articles/how-to/migrate-app-to-rhino.html","id":"configure-your-rhino-application","dir":"Articles > How-to","previous_headings":"","what":"Configure Your Rhino Application","title":"How-to: Migrate app to Rhino","text":"last step get started Rhino configuring . minimal setup allows running application setting legacy_entrypoint rhino.yml. able run application immediately set legacy_entrypoint: app_dir, approach requires adjustments application’s structure. adjust adjust application fit best practices suggested Rhino, can modify legacy_entrypoint. Ultimately, application fully migrated Rhino, legacy_entrypoint setting can removed rhino.yml. Refer Next Steps section see continue improving application!","code":""},{"path":[]},{"path":"https://appsilon.github.io/rhino/articles/how-to/migrate-app-to-rhino.html","id":"migrating-javascript-code","dir":"Articles > How-to","previous_headings":"Next Steps","what":"Migrating JavaScript Code","title":"How-to: Migrate app to Rhino","text":"TODO: something along lines build_js() details","code":""},{"path":"https://appsilon.github.io/rhino/articles/how-to/migrate-app-to-rhino.html","id":"migrating-css-styles-to-sass","dir":"Articles > How-to","previous_headings":"Next Steps","what":"Migrating CSS styles to SASS","title":"How-to: Migrate app to Rhino","text":"TODO","code":""},{"path":"https://appsilon.github.io/rhino/articles/how-to/migrate-app-to-rhino.html","id":"boxifying-application","dir":"Articles > How-to","previous_headings":"Next Steps","what":"Boxifying Application","title":"How-to: Migrate app to Rhino","text":"TODO: adjusting application fit structure proposed Rhino","code":""},{"path":"https://appsilon.github.io/rhino/articles/how-to/migrate-app-to-rhino.html","id":"additional-notes","dir":"Articles > How-to","previous_headings":"","what":"Additional notes","title":"How-to: Migrate app to Rhino","text":"process described rhino::init() documentation, albeit great detail. first step put app files app directory, can run shinyAppDir(\"app\"). Practical experience migrating apps shows ’s useful step quickly lets verify whether app still works. process can bit unintuitive however. example, already app.R file ui/server/global R subdirectory, still move whole structure app. case ’ll end app.R, app/app.R ui/server/global app/R/. two app.R files might feel awkward. general use rhino::init() migration. done via RStudio GUI. already .Rprofile renv migrating, ’ll load won’t Rhino inside. need run rhino::init() different directory (perhaps run renv::deactivate()). Rhino renv::load() renv.lock. particular set options(\"repos\") based renv.lock. get “unsatisfied dependencies” migration?","code":""},{"path":"https://appsilon.github.io/rhino/articles/how-to/use-addins.html","id":"addins","dir":"Articles > How-to","previous_headings":"","what":"Addins","title":"How-to: Rhino Addins","text":"RStudio Addins provide mechanism executing R functions interactively within RStudio IDE either keyboard shortcuts, Addins menu.","code":""},{"path":[]},{"path":"https://appsilon.github.io/rhino/articles/how-to/use-addins.html","id":"create-a-new-rhino-module","dir":"Articles > How-to","previous_headings":"Available Addins","what":"Create a new Rhino Module","title":"How-to: Rhino Addins","text":"Jump start module development creating new R script document Rhino module template. Addin sets foundation module structure, letting dive straight coding.","code":""},{"path":"https://appsilon.github.io/rhino/articles/how-to/use-addins.html","id":"format-r-code","dir":"Articles > How-to","previous_headings":"Available Addins","what":"Format R Code","title":"How-to: Rhino Addins","text":"Uses styler package automatically format R script. Addin ensures consistency readability.","code":""},{"path":"https://appsilon.github.io/rhino/articles/how-to/use-addins.html","id":"lint-r-code","dir":"Articles > How-to","previous_headings":"Available Addins","what":"Lint R Code","title":"How-to: Rhino Addins","text":"Uses lintr package check R sources style errors. Identify address potential issues R scripts ease.","code":""},{"path":"https://appsilon.github.io/rhino/articles/how-to/use-addins.html","id":"run-r-tests","dir":"Articles > How-to","previous_headings":"Available Addins","what":"Run R Tests","title":"How-to: Rhino Addins","text":"Uses {testhat} package run unit tests tests/testthat directory. Maintain functions components reliability.","code":""},{"path":"https://appsilon.github.io/rhino/articles/how-to/use-addins.html","id":"build-javascript","dir":"Articles > How-to","previous_headings":"Available Addins","what":"Build JavaScript","title":"How-to: Rhino Addins","text":"Simplify process building JavaScript files using Babel Webpack. Builds app/js/index.js file app/static/js/app.min.js. Choose watch changes, automating build process whenever save JavaScript file.","code":""},{"path":"https://appsilon.github.io/rhino/articles/how-to/use-addins.html","id":"build-sass-styles","dir":"Articles > How-to","previous_headings":"Available Addins","what":"Build Sass Styles","title":"How-to: Rhino Addins","text":"Effortlessly build Sass styles using Dart Sass sass R package. builds app/styles/main.scss file app/static/css/app.min.css. Opt watch changes, allowing automatic rebuilding style sheets.","code":""},{"path":"https://appsilon.github.io/rhino/articles/how-to/use-addins.html","id":"lint-javascript","dir":"Articles > How-to","previous_headings":"Available Addins","what":"Lint JavaScript","title":"How-to: Rhino Addins","text":"Runs ESLint JavaScript sources app/js directory. performs linting JavaScript files ease. Opt fix issues automatically fixing directly.","code":""},{"path":"https://appsilon.github.io/rhino/articles/how-to/use-addins.html","id":"lint-sass-styles","dir":"Articles > How-to","previous_headings":"Available Addins","what":"Lint Sass Styles","title":"How-to: Rhino Addins","text":"Runs Stylelint Sass sources app/styles directory. Choose automatically fix issues streamline process linting Sass styles.","code":""},{"path":"https://appsilon.github.io/rhino/articles/how-to/use-addins.html","id":"run-end-to-end-tests","dir":"Articles > How-to","previous_headings":"Available Addins","what":"Run End-to-End Tests","title":"How-to: Rhino Addins","text":"Execute Cypress end--end tests application. Choose interactive non-interactive modes validate application behavior.","code":""},{"path":[]},{"path":"https://appsilon.github.io/rhino/articles/how-to/use-global-variables.html","id":"vanilla-r","dir":"Articles > How-to","previous_headings":"Global Variables","what":"Vanilla R","title":"How-to: Use global variables","text":"R, global variables live inside .GlobalEnv. Global variables can updated within function using <<-. code loaded box::use(), global variables live inside module’s immutable environment. Updating global variables <<- work.","code":"# constants.R answer <- 42 set_answer <- function(new_answer) { answer <<- new_answer } # main.R source(\"constants.R\") print(answer) # 42 set_answer(0) print(answer) # 0 # app/logic/constants.R #' @export answer <- 42 #' @export set_answer <- function(new_answer) { answer <<- new_answer } # app/main.R box::use(app/logic/constants) print(constants$answer) # 42 constants$set_answer(0) # Error: cannot change value of locked binding."},{"path":"https://appsilon.github.io/rhino/articles/how-to/use-global-variables.html","id":"variables-in-a-new-environment","dir":"Articles > How-to","previous_headings":"Global Variables","what":"Variables in a new environment","title":"How-to: Use global variables","text":"overcome box’s feature limiting scope, Rhino suggests creating new environment use environment contain global variables.","code":"# app/logic/__init__.R #' @export global <- new.env() global$answer <- 42 #' @export set_answer <- function(new_answer) { global$answer <- new_answer } # app/logic/get_answer.R box::use( app/logic[global, set_answer], ) print(global$answer) # 42 set_answer(0) print(global$answer) # 0"},{"path":"https://appsilon.github.io/rhino/articles/how-to/use-global-variables.html","id":"variables-in--globalenv","dir":"Articles > How-to","previous_headings":"Global Variables","what":"Variables in .GlobalEnv","title":"How-to: Use global variables","text":"Alternatively, variables can still stored imported .GlobalEnv. variable must also defined updated using <-.","code":"# app/logic/__init__.R .GlobalEnv$answer <- 42 #' @export set_answer <- function(new_answer) { .GlobalEnv$answer <- new_answer } # app/logic/get_answer.R box::use(app/logic[set_answer]) print(.GlobalEnv$answer) # 42 set_answer(0) print(.GlobalEnv$answer) # 0"},{"path":"https://appsilon.github.io/rhino/articles/how-to/use-global-variables.html","id":"session-variables","dir":"Articles > How-to","previous_headings":"","what":"Session Variables","title":"How-to: Use global variables","text":"Rhino suggests using arguments module servers explicit handling session variables user inputs. However, shiny support session$userData, environment can store session-specific data. modules access variables inside session$userData.","code":"module_ui <- function(id) { ns <- NS(id) textOutput(ns(\"answer\")) } module_server <- function(id, answer) { moduleServer(id, function(input, output, session) { output$answer <- renderText(answer()) }) } shinyApp( ui = bootstrapPage( textInput(\"answer\", \"Answer\"), module_ui(\"module\") ), server = function(input, output, session) { answer <- reactiveVal() observeEvent(input$answer, answer(input$answer)) module_server(\"module\", answer) } ) module_ui <- function(id) { ns <- NS(id) textOutput(ns(\"answer\")) } module_server <- function(id) { moduleServer(id, function(input, output, session) { output$answer <- renderText(session$userData$answer()) }) } shinyApp( ui = bootstrapPage( textInput(\"answer\", \"Answer\"), module_ui(\"module\") ), server = function(input, output, session) { session$userData$answer <- reactiveVal() observeEvent(input$answer, session$userData$answer(input$answer)) module_server(\"module\") } )"},{"path":"https://appsilon.github.io/rhino/articles/how-to/use-shinymanager.html","id":"bookmarking","dir":"Articles > How-to","previous_headings":"","what":"Bookmarking","title":"How-to: Use shinymanager","text":"want use bookmarking together shinymanager, need wrap UI passed secure_app() function:","code":"shiny$enableBookmarking() #' @export ui <- shinymanager$secure_app( # Wrap the UI passed to `secure_app()` in a function with a `request` parameter. function(request) { shiny$bootstrapPage( shiny$bookmarkButton(), shiny$textInput(\"name\", \"Name\"), shiny$textOutput(\"message\") ) } )"},{"path":[]},{"path":"https://appsilon.github.io/rhino/articles/tutorial/create-your-first-rhino-app.html","id":"how-to-install-rhino","dir":"Articles > Tutorial","previous_headings":"Setup","what":"How to install Rhino?","title":"Tutorial: Create your first Rhino app","text":"get started, first thing need install Rhino :","code":"install.packages(\"rhino\")"},{"path":"https://appsilon.github.io/rhino/articles/tutorial/create-your-first-rhino-app.html","id":"dependencies","dir":"Articles > Tutorial","previous_headings":"Setup","what":"Dependencies","title":"Tutorial: Create your first Rhino app","text":"tutorial uses native pipe operator (|>) introduced R 4.1 release. use earlier R version, can use %>% pipe operator found magrittr dplyr packages instead. use state art JavaScript Sass development tools provided Rhino, ’ll need install Node.js (v16 later) system. Rhino still work without Node.js limitations (described JavaScript Sass sections).","code":""},{"path":"https://appsilon.github.io/rhino/articles/tutorial/create-your-first-rhino-app.html","id":"create-an-initial-application","dir":"Articles > Tutorial","previous_headings":"","what":"Create an initial application","title":"Tutorial: Create your first Rhino app","text":"Creating new Rhino application can done two ways - running rhino::init() function using RStudio Create Project functionality.","code":""},{"path":"https://appsilon.github.io/rhino/articles/tutorial/create-your-first-rhino-app.html","id":"create-an-application-using-the-rstudio-wizard","dir":"Articles > Tutorial","previous_headings":"Create an initial application","what":"Create an application using the RStudio wizard","title":"Tutorial: Create your first Rhino app","text":"use RStudio, probably easiest way create new Rhino application simply use Create New Project feature. Rhino installed, automatically added one options RStudio: Choose , input new project name ready go.","code":""},{"path":"https://appsilon.github.io/rhino/articles/tutorial/create-your-first-rhino-app.html","id":"create-an-application-using-rhinoinit","dir":"Articles > Tutorial","previous_headings":"Create an initial application","what":"Create an application using rhino::init()","title":"Tutorial: Create your first Rhino app","text":"Creating Rhino application possible R console running init function: two things need know choosing way initializing application: Rhino change working directory. need either open new R session new application directory manually change working directory. Rhino relies options added projects .Rprofile file. robust way make sure correctly sourced simply restart R session. result paths initial Rhino application following structure: want know , check document.","code":"rhino::init(\"RhinoApplication\") setwd(\"./RhinoApplication\") . ├── app │ ├── js │ │ └── index.js │ ├── logic │ │ └── __init__.R │ ├── static │ │ └── favicon.ico │ ├── styles │ │ └── main.scss │ ├── view │ │ └── __init__.R │ └── main.R ├── tests │ ├── cypress │ │ └── e2e │ │ └── app.cy.js │ ├── testthat │ │ └── test-main.R │ └── cypress.json ├── app.R ├── RhinoApplication.Rproj ├── dependencies.R ├── renv.lock └── rhino.yml"},{"path":"https://appsilon.github.io/rhino/articles/tutorial/create-your-first-rhino-app.html","id":"running-the-application","dir":"Articles > Tutorial","previous_headings":"Create an initial application","what":"Running the application","title":"Tutorial: Create your first Rhino app","text":"Now, set , let’s run : seeing right now:","code":"shiny::runApp()"},{"path":"https://appsilon.github.io/rhino/articles/tutorial/create-your-first-rhino-app.html","id":"add-your-first-module","dir":"Articles > Tutorial","previous_headings":"","what":"Add your first module","title":"Tutorial: Create your first Rhino app","text":"application runs, doesn’t meaningful functionality. Let’s add something !","code":""},{"path":"https://appsilon.github.io/rhino/articles/tutorial/create-your-first-rhino-app.html","id":"module-structure","dir":"Articles > Tutorial","previous_headings":"Add your first module","what":"Module structure","title":"Tutorial: Create your first Rhino app","text":"Rhino, application view intended live Shiny module use encapsulation provided box package. Rhino already created good place new modules, app/view directory. Create file , named chart.R:","code":"# app/view/chart.R box::use( shiny[h3, moduleServer, NS], ) #' @export ui <- function(id) { ns <- NS(id) h3(\"Chart\") } #' @export server <- function(id) { moduleServer(id, function(input, output, session) { print(\"Chart module server part works!\") }) }"},{"path":"https://appsilon.github.io/rhino/articles/tutorial/create-your-first-rhino-app.html","id":"calling-a-module","dir":"Articles > Tutorial","previous_headings":"Add your first module","what":"Calling a module","title":"Tutorial: Create your first Rhino app","text":"next step call new module application. First, need import main application file. , add another box::use section app/main.R file: Now, main module able use exported functions chart.R. Let’s try ! Modify app/main.R file look like : Now, run application, see message newly created module:","code":"# app/main.R box::use( app/view/chart, ) ... # app/main.R box::use( shiny[bootstrapPage, moduleServer, NS], ) box::use( app/view/chart, ) #' @export ui <- function(id) { ns <- NS(id) bootstrapPage( chart$ui(ns(\"chart\")) ) } #' @export server <- function(id) { moduleServer(id, function(input, output, session) { chart$server(\"chart\") }) }"},{"path":"https://appsilon.github.io/rhino/articles/tutorial/create-your-first-rhino-app.html","id":"adding-components-to-a-module","dir":"Articles > Tutorial","previous_headings":"Add your first module","what":"Adding components to a module","title":"Tutorial: Create your first Rhino app","text":"Now time start adding something new module. can add “chart” module? ’re right, chart. Let’s add chart rhinoceros dataset available Rhino.","code":""},{"path":"https://appsilon.github.io/rhino/articles/tutorial/create-your-first-rhino-app.html","id":"adding-r-packages","dir":"Articles > Tutorial","previous_headings":"Add your first module > Adding components to a module","what":"Adding R packages","title":"Tutorial: Create your first Rhino app","text":"First, need install library visualizations - , go echarts4r. using total 5 packages application. save us time tutorial install . function install packages, update dependencies.R renv.lock files accordingly. Note: Package htmlwidgets already installed since dependency shiny, still add dependencies.R file.","code":"# In R console rhino::pkg_install(c(\"dplyr\", \"echarts4r\", \"htmlwidgets\", \"reactable\", \"tidyr\"))"},{"path":"https://appsilon.github.io/rhino/articles/tutorial/create-your-first-rhino-app.html","id":"add-dependencies-to-the-module","dir":"Articles > Tutorial","previous_headings":"Add your first module > Adding components to a module","what":"Add dependencies to the module","title":"Tutorial: Create your first Rhino app","text":"Now, packages available project environment, ’s time use . First, need import module. Extend box::use call app/view/chart.R file: can use packages module calling {package}${function}. options importing box check link. Add echarts4r render server part module output part UI: One thing worth noting UI part use another function Shiny - tagList. able , adjust import box::use - simply add tagList list imported functions. Finally, run application, see something similar :","code":"# app/view/chart.R box::use( echarts4r, shiny[h3, moduleServer, NS, tagList], ) ... # app/view/chart.R box::use( echarts4r, shiny[h3, moduleServer, NS, tagList], rhino[rhinos], ) #' @export ui <- function(id) { ns <- NS(id) tagList( h3(\"Chart\"), echarts4r$echarts4rOutput(ns(\"chart\")) ) } #' @export server <- function(id) { moduleServer(id, function(input, output, session) { output$chart <- echarts4r$renderEcharts4r( rhinos |> echarts4r$group_by(Species) |> echarts4r$e_chart(x = Year) |> echarts4r$e_line(Population) |> echarts4r$e_x_axis(Year) |> echarts4r$e_tooltip() ) }) }"},{"path":"https://appsilon.github.io/rhino/articles/tutorial/create-your-first-rhino-app.html","id":"add-a-second-module","dir":"Articles > Tutorial","previous_headings":"","what":"Add a second module","title":"Tutorial: Create your first Rhino app","text":"content presented application, great add table show dataset. , let’s create another module - app/view/table.R:","code":"# app/view/table.R box::use( shiny[h3, moduleServer, NS, tagList], ) #' @export ui <- function(id) { ns <- NS(id) tagList( h3(\"Table\") ) } #' @export server <- function(id) { moduleServer(id, function(input, output, session) { }) }"},{"path":"https://appsilon.github.io/rhino/articles/tutorial/create-your-first-rhino-app.html","id":"calling-the-second-module","dir":"Articles > Tutorial","previous_headings":"Add a second module","what":"Calling the second module","title":"Tutorial: Create your first Rhino app","text":", need call new module main.R file:","code":"# app/main.R box::use( shiny[bootstrapPage, moduleServer, NS], ) box::use( app/view/chart, app/view/table, ) #' @export ui <- function(id) { ns <- NS(id) bootstrapPage( table$ui(ns(\"table\")), chart$ui(ns(\"chart\")) ) } #' @export server <- function(id) { moduleServer(id, function(input, output, session) { table$server(\"table\") chart$server(\"chart\") }) }"},{"path":"https://appsilon.github.io/rhino/articles/tutorial/create-your-first-rhino-app.html","id":"use-the-same-dataset-for-both-modules","dir":"Articles > Tutorial","previous_headings":"Add a second module","what":"Use the same dataset for both modules","title":"Tutorial: Create your first Rhino app","text":"want use dataset modules, instead calling twice, let’s pass data argument:","code":"# app/main.R box::use( shiny[bootstrapPage, moduleServer, NS], rhino[rhinos], ) box::use( app/view/chart, app/view/table, ) #' @export ui <- function(id) { ns <- NS(id) bootstrapPage( table$ui(ns(\"table\")), chart$ui(ns(\"chart\")) ) } #' @export server <- function(id) { moduleServer(id, function(input, output, session) { data <- rhinos table$server(\"table\", data = data) chart$server(\"chart\", data = data) }) } # app/view/table.R box::use( shiny[h3, moduleServer, NS, tagList], ) #' @export ui <- function(id) { ns <- NS(id) tagList( h3(\"Table\") ) } #' @export server <- function(id, data) { moduleServer(id, function(input, output, session) { }) } # app/view/chart.R box::use( echarts4r, shiny[h3, moduleServer, NS, tagList], ) #' @export ui <- function(id) { ns <- NS(id) tagList( h3(\"Chart\"), echarts4r$echarts4rOutput(ns(\"chart\")) ) } #' @export server <- function(id, data) { moduleServer(id, function(input, output, session) { output$chart <- echarts4r$renderEcharts4r( data |> echarts4r$group_by(Species) |> echarts4r$e_chart(x = Year) |> echarts4r$e_line(Population) |> echarts4r$e_x_axis(Year) |> echarts4r$e_tooltip() ) }) }"},{"path":"https://appsilon.github.io/rhino/articles/tutorial/create-your-first-rhino-app.html","id":"create-a-table","dir":"Articles > Tutorial","previous_headings":"Add a second module","what":"Create a table","title":"Tutorial: Create your first Rhino app","text":"table, go reactable package. Now can add table application. Let’s check raw data Rhinos: application look similar :","code":"# app/view/table.R box::use( reactable, shiny[h3, moduleServer, NS, tagList], ) #' @export ui <- function(id) { ns <- NS(id) tagList( h3(\"Table\"), reactable$reactableOutput(ns(\"table\")) ) } #' @export server <- function(id, data) { moduleServer(id, function(input, output, session) { output$table <- reactable$renderReactable( reactable$reactable(data) ) }) }"},{"path":"https://appsilon.github.io/rhino/articles/tutorial/create-your-first-rhino-app.html","id":"add-logic","dir":"Articles > Tutorial","previous_headings":"","what":"Add logic","title":"Tutorial: Create your first Rhino app","text":"seems great slightly adjust table. Let’s transform dataset little bit. recommend placing code can expressed without Shiny app/logic directory. Let’s create file , called app/logic/data_transformation.R. table better Rhino species separate column, easy compare populations across time. , need transform dataset using pivot_wider function tidyr package. Now able access function data_transformation.R file using box::use(). Let’s also create function wraps pivot_wider transforms data. Note , always, need add @export able access file sourced. next step call function table module. Add box import transform dataset: run application, see something similar : can notice, table arranged Black Rhino population. make sense change Year using dplyr::arrange. Next, add arrange transform_data function: result looks much understandable: still one element can improved. check X-axis chart, values contain comma. ’s default behavior integers, year! fix , need add custom formatter. Let’s create another file, app/logic/chart_utils.R: Finally, add formatter chart module: now look better:","code":"# app/logic/data_transformation.R box::use( tidyr[pivot_wider], ) #' @export transform_data <- function(data) { pivot_wider( data = data, names_from = Species, values_from = Population ) } # app/view/table.R box::use( reactable, shiny[h3, moduleServer, NS, tagList], ) box::use( app/logic/data_transformation[transform_data], ) #' @export ui <- function(id) { ns <- NS(id) tagList( h3(\"Table\"), reactable$reactableOutput(ns(\"table\")) ) } #' @export server <- function(id, data) { moduleServer(id, function(input, output, session) { output$table <- reactable$renderReactable( data |> transform_data() |> reactable$reactable() ) }) } # app/logic/data_transformation.R box::use( dplyr[arrange], tidyr[pivot_wider], ) #' @export transform_data <- function(data) { pivot_wider( data = data, names_from = Species, values_from = Population ) |> arrange(Year) } # app/logic/chart_utils.R box::use( htmlwidgets[JS], ) #' @export label_formatter <- JS(\"(value, index) => value\") # app/view/chart.R box::use( echarts4r, shiny[h3, moduleServer, NS, tagList], ) box::use( app/logic/chart_utils[label_formatter], ) #' @export ui <- function(id) { ns <- NS(id) tagList( h3(\"Chart\"), echarts4r$echarts4rOutput(ns(\"chart\")) ) } #' @export server <- function(id, data) { moduleServer(id, function(input, output, session) { output$chart <- echarts4r$renderEcharts4r( data |> echarts4r$group_by(Species) |> echarts4r$e_chart(x = Year) |> echarts4r$e_line(Population) |> echarts4r$e_x_axis( Year, axisLabel = list( formatter = label_formatter ) ) |> echarts4r$e_tooltip() ) }) }"},{"path":"https://appsilon.github.io/rhino/articles/tutorial/create-your-first-rhino-app.html","id":"add-custom-styles","dir":"Articles > Tutorial","previous_headings":"","what":"Add custom styles","title":"Tutorial: Create your first Rhino app","text":"Note: Sass builder uses Node.js. able install Node environment, can change sass entry rhino.yml file r. now use R package Sass bundling. hood, uses deprecated C++ library, Node solution strongly recommended . stage, application working components, doesn’t clean organized look . need little CSS styling. Adjusting application style can done providing custom styles app/styles directory, first, need adjust application little bit adding HTML tags CSS classes: Now ready modify styles. Simply add CSS rules app/styles/mains.scss file: try running application right now, see changes. Rhino uses minified app/static/app.min.css styling. use , need build using Rhino function: Now, running application see something similar : worth noting, don’t need add app/static/app.min.css application header - Rhino . Let’s adjust application little bit adding title: styling: Finally, build Sass : result look similar :","code":"# app/main.R box::use( shiny[bootstrapPage, div, moduleServer, NS], rhino[rhinos], ) box::use( app/view/chart, app/view/table, ) #' @export ui <- function(id) { ns <- NS(id) bootstrapPage( div( class = \"components-container\", table$ui(ns(\"table\")), chart$ui(ns(\"chart\")) ) ) } #' @export server <- function(id) { moduleServer(id, function(input, output, session) { data <- rhinos table$server(\"table\", data = data) chart$server(\"chart\", data = data) }) } # app/view/chart.R box::use( echarts4r, shiny[div, moduleServer, NS], ) box::use( app/logic/chart_utils[label_formatter], ) #' @export ui <- function(id) { ns <- NS(id) div( class = \"component-box\", echarts4r$echarts4rOutput(ns(\"chart\")) ) } #' @export server <- function(id, data) { moduleServer(id, function(input, output, session) { output$chart <- echarts4r$renderEcharts4r( data |> echarts4r$group_by(Species) |> echarts4r$e_chart(x = Year) |> echarts4r$e_line(Population) |> echarts4r$e_x_axis( Year, axisLabel = list( formatter = label_formatter ) ) |> echarts4r$e_tooltip() ) }) } # app/view/table.R box::use( reactable, shiny[div, moduleServer, NS], ) box::use( app/logic/data_transformation[transform_data], ) #' @export ui <- function(id) { ns <- NS(id) div( class = \"component-box\", reactable$reactableOutput(ns(\"table\")) ) } #' @export server <- function(id, data) { moduleServer(id, function(input, output, session) { output$table <- reactable$renderReactable( data |> transform_data() |> reactable$reactable() ) }) } // app/styles/main.scss .components-container { display: inline-grid; grid-template-columns: 1fr 1fr; width: 100%; .component-box { padding: 10px; margin: 10px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); } } # in R console rhino::build_sass() # app/main.R box::use( shiny[bootstrapPage, div, h1, moduleServer, NS], ) box::use( app/view/chart, app/view/table, ) #' @export ui <- function(id) { ns <- NS(id) bootstrapPage( h1(\"RhinoApplication\"), div( class = \"components-container\", table$ui(ns(\"table\")), chart$ui(ns(\"chart\")) ) ) } ... // app/styles/main.scss .components-container { display: inline-grid; grid-template-columns: 1fr 1fr; width: 100%; .component-box { padding: 10px; margin: 10px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); } } h1 { text-align: center; font-weight: 900; } # in R console rhino::build_sass()"},{"path":"https://appsilon.github.io/rhino/articles/tutorial/create-your-first-rhino-app.html","id":"add-javascript-code","dir":"Articles > Tutorial","previous_headings":"","what":"Add JavaScript code","title":"Tutorial: Create your first Rhino app","text":"Note: Rhino tools JS require Node.js. can still use JavaScript code like regular Shiny application, instead using www directory, add files static/js call using full path, e.g. tags$script(src = \"static/js/app.min.js\"). last element, let’s add button trigger JavaScript popup. First, need create simple button style : Remember rebuild Sass rhino::build_sass()! now see button question mark top right corner application: Now, ’s time writing JavaScript code show popup message. JS code stored app/js directory. already first (empty) file - index.js. Let’s use : function simply show browser alert message. familiar JavaScript code used Shiny applications, notice one difference - keyword export added function name. Rhino, functions marked like available Shiny use. styles, Rhino application use JS files directly, instead utilizes minified version build rhino::build_js function. Try : Now app/static/js/app.min.js file created , minified CSS file, automatically included application head tag. last thing use showHelp() function application. , let’s simply add onclick button: probably noticed second difference classic Shiny approach one used Rhino. exported JS functions now available App (JavaScript function library, e.g. Math.round). Now, run application click button, see something like : Congratulations! now fully armed operational battle station Rhino application!","code":"# app/main.R box::use( shiny[bootstrapPage, div, h1, icon, moduleServer, NS, tags], ) box::use( app/view/chart, app/view/table, ) #' @export ui <- function(id) { ns <- NS(id) bootstrapPage( h1(\"RhinoApplication\"), div( class = \"components-container\", table$ui(ns(\"table\")), chart$ui(ns(\"chart\")) ), tags$button( id = \"help-button\", icon(\"question\") ) ) } ... // app/styles/main.scss .components-container { display: inline-grid; grid-template-columns: 1fr 1fr; width: 100%; .component-box { padding: 10px; margin: 10px; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); } } h1 { text-align: center; font-weight: 900; } #help-button { position: fixed; top: 0; right: 0; margin: 10px; } // app/js/index.js export function showHelp() { alert('Learn more about Rhino: https://appsilon.github.io/rhino/'); } # in R console rhino::build_js() # app/main.R box::use( shiny[bootstrapPage, div, h1, icon, moduleServer, NS, tags], ) box::use( app/view/chart, app/view/table, ) #' @export ui <- function(id) { ns <- NS(id) bootstrapPage( h1(\"RhinoApplication\"), div( class = \"components-container\", table$ui(ns(\"table\")), chart$ui(ns(\"chart\")) ), tags$button( id = \"help-button\", icon(\"question\"), onclick = \"App.showHelp()\" ) ) } ..."},{"path":"https://appsilon.github.io/rhino/articles/tutorial/use-react-in-rhino.html","id":"starting-off","dir":"Articles > Tutorial","previous_headings":"","what":"Starting off","title":"Tutorial: Use React in Rhino","text":"start , let’s initialize fresh Rhino application. Launch R console empty directory run: use React Rhino need add shiny.react package project dependencies: Now, three steps add React component Rhino application: Define component using JSX. Declare component R. Use component application. Let’s go steps add simple Reveal component app.","code":"rhino::init() rhino::pkg_install(\"shiny.react\")"},{"path":"https://appsilon.github.io/rhino/articles/tutorial/use-react-in-rhino.html","id":"defining-the-component","dir":"Articles > Tutorial","previous_headings":"","what":"Defining the component","title":"Tutorial: Use React in Rhino","text":"use JSX, syntax extension JavaScript, define component. Create Reveal.jsx file app/js directory following content: Reveal component just
provided ID, button can used show hide children. make component available Rhino, need register . Edit app/js/index.js file like : Rhino global variable can used without declaration, similar Shiny. registerReactComponents() function takes object mapping component names definitions ({ Reveal } shorthand { Reveal: Reveal }). Lastly, need build JavaScript: create app/static/js/app.min.js file automatically included Rhino.","code":"const { useState } = React; export default function Reveal({ id, children }) { const [visible, setVisible] = useState(false); return (