├── .Rbuildignore ├── .babelrc ├── .eslintrc.js ├── .flowconfig ├── .github ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md ├── shiny-workflows │ └── website.R └── workflows │ └── R-CMD-check.yaml ├── .gitignore ├── .lintr ├── DESCRIPTION ├── Gruntfile.js ├── LICENSE ├── NAMESPACE ├── NEWS.md ├── R ├── renderReactLog.R ├── setReactLog.R ├── shinyModule.R ├── showReactLog.R └── version.R ├── README.md ├── bin ├── clean_rlog_file.sh ├── lint_file.sh ├── postinstall.sh └── update-license.js ├── cran-comments.md ├── index.html ├── inst ├── examples │ └── 03_reactivity │ │ ├── app.R │ │ ├── debug_reactlog.json │ │ └── tests │ │ ├── shinytest.R │ │ └── shinytest │ │ ├── mytest-expected │ │ ├── 001.json │ │ ├── 001.png │ │ ├── 002.json │ │ ├── 002.png │ │ ├── 003.json │ │ ├── 003.png │ │ ├── 004.json │ │ └── 004.png │ │ └── mytest.R ├── gantt │ ├── ganttAsset │ │ ├── gantt-chart.js │ │ ├── gantt.css │ │ └── gantt.js │ └── reactive-gantt.html ├── log-files │ ├── log-crandash.js │ ├── log-cranwhales.js │ ├── log-linear-multi.js │ ├── log-radiant.js │ ├── log-superzip.js │ └── old_log.js └── reactlog │ ├── defaultLog.js │ ├── reactlog.html │ └── reactlogAsset │ ├── fira-mono_source-sans-pro_latin-ext.css │ ├── images │ ├── iconSearch.svg │ ├── next-end.svg │ ├── next-idle.svg │ ├── next-mark.svg │ ├── next-output-calc.svg │ ├── next-step.svg │ ├── prev-idle.svg │ ├── prev-mark.svg │ ├── prev-output-calc.svg │ ├── prev-start.svg │ └── prev-step.svg │ ├── reactlog.css │ ├── reactlog.js │ └── reactlog.js.map ├── logo ├── reactlog-hex.png ├── reactlog.png └── reactlog.svg ├── man ├── figures │ └── logo.svg ├── reactlog_module.Rd ├── reactlog_show.Rd ├── reactlog_write.Rd └── setReactLog.Rd ├── package.json ├── pkgdown ├── .gitignore ├── _pkgdown.yml └── favicon │ ├── apple-touch-icon-120x120.png │ ├── apple-touch-icon-152x152.png │ ├── apple-touch-icon-180x180.png │ ├── apple-touch-icon-60x60.png │ ├── apple-touch-icon-76x76.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ └── favicon.ico ├── prettier.config.js ├── reactlog.Rproj ├── readme-images ├── cranwhales.gif └── pythagoras.gif ├── revdep ├── .gitignore ├── README.md ├── cran.md ├── failures.md ├── problems.md └── revdep_cran.md ├── scripts ├── license_checker.js └── rhub.R ├── srcjs ├── cyto │ ├── cytoClasses.js │ ├── cytoFlowType.js │ ├── cytoOn.js │ ├── cytoStyle.js │ ├── cytoscapeInit.js │ └── layoutOptions.js ├── graph │ ├── ActiveStateStatus.js │ ├── Edge.js │ ├── GhostEdge.js │ ├── Graph.js │ ├── GraphAtStep.js │ ├── HoverStatus.js │ ├── Node.js │ └── StatusArr.js ├── index.js ├── layout │ ├── keydown.js │ ├── logEntry.js │ └── progressBar.js ├── log │ ├── initStep.js │ └── logStates.js ├── rlog.js ├── style │ └── colors.js ├── updateGraph │ ├── atTick.js │ ├── buttons.js │ ├── hoverStickyFilterSearch.js │ ├── idle.js │ ├── index.js │ ├── outputCalc.js │ ├── resize.js │ ├── searchString.js │ ├── step.js │ ├── tick.js │ └── userMarks.js └── utils │ ├── ArrayHelper.js │ ├── MapHelper.js │ ├── console.js │ ├── numbers.js │ ├── queryString.js │ └── shinytest.js ├── tests ├── testthat.R └── testthat │ └── test-shiny_module.R ├── vignettes ├── .gitignore ├── images │ ├── 04-reactivity │ │ ├── reactivity-graph-00.png │ │ ├── reactivity-graph-01.png │ │ ├── reactivity-graph-02.png │ │ ├── reactivity-graph-03.png │ │ ├── reactivity-graph-04.png │ │ ├── reactivity-graph-05.png │ │ ├── reactivity-graph-06.png │ │ ├── reactivity-graph-07.png │ │ ├── reactivity-graph-08.png │ │ ├── reactivity-graph-09.png │ │ ├── reactivity-graph-10.png │ │ ├── reactivity-graph-11.png │ │ └── reactivity-graph-12.png │ ├── buttons │ │ ├── next-end.svg │ │ ├── next-idle.svg │ │ ├── next-mark.svg │ │ ├── next-output-calc.svg │ │ ├── next-step.svg │ │ ├── prev-idle.svg │ │ ├── prev-mark.svg │ │ ├── prev-output-calc.svg │ │ ├── prev-start.svg │ │ └── prev-step.svg │ ├── elements.png │ ├── example_cranwhales.png │ ├── legend.png │ ├── navigation.png │ ├── progress_bar.png │ ├── search_bar.png │ ├── status_bar.png │ ├── step_information.png │ └── types.png └── reactlog.Rmd └── yarn.lock /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^CRAN-RELEASE$ 2 | ^Meta$ 3 | ^doc$ 4 | ^cran-comments\.md$ 5 | ^docs$ 6 | ^_pkgdown\.yml$ 7 | ^appveyor\.yml$ 8 | ^.*\.Rproj$ 9 | ^\.Rproj\.user$ 10 | ^LICENSE\.md$ 11 | ^srcjs 12 | ^src_old 13 | ^\.babelrc$ 14 | ^\.eslintrc\.js$ 15 | ^\.flowconfig$ 16 | ^\.travis\.yml$ 17 | ^Gruntfile\.js$ 18 | ^package\.json$ 19 | ^prettier\.config\.js$ 20 | ^yarn 21 | ^CODE_OF_CONDUCT\.md$ 22 | ^node_modules 23 | ^bin 24 | ^inst/reactlogAsset/report.html$ 25 | ^flow-typed 26 | ^_ignore 27 | ^\.github 28 | ^index\.html$ 29 | ^\.lintr$ 30 | ^scripts 31 | .*\.js\.map$ 32 | ^inst/log-files 33 | ^readme-images 34 | ^inst/gantt 35 | ^License.md 36 | ^\.github$ 37 | ^logo 38 | ^pkgdown$ 39 | ^revdep$ 40 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "sourceMap": true, 3 | "compact": false, 4 | "presets": [ 5 | "@babel/preset-flow", 6 | ["@babel/preset-env", { 7 | "modules": "umd", 8 | "useBuiltIns": "entry", 9 | "corejs": 2 10 | }] 11 | ], 12 | "plugins": [ 13 | "@babel/plugin-proposal-class-properties" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "parser": "babel-eslint", 3 | "plugins": [ 4 | "flowtype" 5 | ], 6 | "extends": [ 7 | "plugin:flowtype/recommended", 8 | "eslint:recommended" 9 | ], 10 | "rules": { 11 | "flowtype/space-after-type-colon": 0, // fixed / clashes with prettier 12 | "comma-dangle": [2, "only-multiline"], 13 | "consistent-return": 1, 14 | "dot-location": [1, "property"], 15 | "eqeqeq": 2, 16 | // "no-shadow": 1, 17 | "no-undef": 2, 18 | "no-unused-vars": [1, {"args": "none"}], 19 | "guard-for-in": 2, 20 | // "no-use-before-define": [1, {"functions": false}], 21 | "semi": [2, "always"], 22 | "no-fallthrough": 0, 23 | "no-console": 2, // ["error", { allow: ["warn", "error"] }] 24 | "no-var": 2 25 | }, 26 | "parserOptions": { "ecmaVersion": 6 }, // enable es6 language 27 | "env": { 28 | "browser": true, 29 | "es6": true // enable es6 objects, ex: Set 30 | }, 31 | } 32 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | src/log-files 3 | src/old 4 | .*/node_modules/.*broken.json 5 | 6 | [include] 7 | srcjs 8 | 9 | [libs] 10 | # https://github.com/nrnb/GoogleSummerOfCode/issues/94 11 | # cytoscape is getting flow this summer 12 | 13 | [lints] 14 | # all=off by default 15 | all=error 16 | sketchy-null=warn 17 | untyped-type-import=off 18 | unclear-type=off 19 | unsafe-getters-setters=off 20 | 21 | [options] 22 | suppress_comment=\\(.\\|\n\\)*\\$Flow 23 | 24 | [strict] 25 | nonstrict-import 26 | unclear-type 27 | unsafe-getters-setters 28 | untyped-import 29 | untyped-type-import 30 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, we pledge to respect all people who 4 | contribute through reporting issues, posting feature requests, updating documentation, 5 | submitting pull requests or patches, and other activities. 6 | 7 | We are committed to making participation in this project a harassment-free experience for 8 | everyone, regardless of level of experience, gender, gender identity and expression, 9 | sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion. 10 | 11 | Examples of unacceptable behavior by participants include the use of sexual language or 12 | imagery, derogatory comments or personal attacks, trolling, public or private harassment, 13 | insults, or other unprofessional conduct. 14 | 15 | Project maintainers have the right and responsibility to remove, edit, or reject comments, 16 | commits, code, wiki edits, issues, and other contributions that are not aligned to this 17 | Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed 18 | from the project team. 19 | 20 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by 21 | opening an issue or contacting one or more of the project maintainers. 22 | 23 | This Code of Conduct is adapted from the Contributor Covenant 24 | (http://contributor-covenant.org), version 1.0.0, available at 25 | http://contributor-covenant.org/version/1/0/0/ 26 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We welcome contributions to the **reactlog** package! 4 | 5 | To submit a contribution: 6 | 7 | 1. [Fork](https://github.com/rstudio/reactlog/fork) the repository and make your changes. 8 | 9 | 2. Ensure that you have signed the [individual](https://www.rstudio.com/wp-content/uploads/2014/06/rstudioindividualcontributoragreement.pdf) or [corporate](https://www.rstudio.com/wp-content/uploads/2014/06/rstudiocorporatecontributoragreement.pdf) contributor agreement as appropriate. You can send the signed copy to contribute@rstudio.com. 10 | 11 | 3. Submit a [pull request](https://help.github.com/articles/using-pull-requests). 12 | 13 | We generally do not merge pull requests that update included web libraries (such as Bootstrap or jQuery) because it is difficult for us to verify that the update is done correctly; we prefer to update these libraries ourselves. 14 | 15 | 16 | ## How to make changes 17 | 18 | Before you submit a pull request, please do the following: 19 | 20 | * Add an entry to NEWS concisely describing what you changed. 21 | 22 | * If appropriate, add unit tests in the tests/ directory. 23 | 24 | * Run Build->Check Package in the RStudio IDE, or `devtools::check()`, to make sure your change did not add any messages, warnings, or errors. 25 | 26 | Doing these things will make it easier for the `reactlog` development team to evaluate your pull request. Even so, we may still decide to modify your code or even not merge it at all. Factors that may prevent us from merging the pull request include: 27 | 28 | * breaking backward compatibility 29 | * adding a feature that we do not consider relevant for `reactlog` 30 | * is hard to understand 31 | * is hard to maintain in the future 32 | * is computationally expensive 33 | * is not intuitive for people to use 34 | 35 | We will try to be responsive and provide feedback in case we decide not to merge your pull request. 36 | 37 | 38 | ## Filing issues 39 | 40 | If you find a bug in `reactlog`, you can also [file an issue](https://github.com/rstudio/reactlog/issues/new). Please provide as much relevant information as you can, and include a minimal reproducible example if possible. 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Please briefly describe your problem and what output you expect. If you have a question, please try using the [RStudio Community website](https://community.rstudio.com/c/shiny/8) first. 2 | 3 | Please include a minimal reprex. The goal of a reprex is to make it as easy as possible for me to recreate your problem so that I can fix it. If you've never heard of a reprex before, start by reading , and follow the advice further down the page. Do NOT include session info unless it's explicitly asked for, or you've used `reprex::reprex(..., si = TRUE)` to hide it away. 4 | 5 | While you may not be able to submit true `reprex::reprex({#code})` due to the interactivity of shiny, a working [app.R script](http://shiny.rstudio.com/articles/app-formats.html#appr) containing the minimal elements to produce the error is highly appreciated. 6 | 7 | Delete these instructions once you have read them. 8 | 9 | --- 10 | 11 | ## Recording issue 12 | 13 | Brief description of the problem. This should show how shiny is not recording something properly. 14 | 15 | ```r 16 | library(shiny) 17 | library(reactlog) 18 | 19 | reactlog_enable() 20 | 21 | ui <- # FILL IN UI 22 | server <- function(input, output, session) { 23 | # FILL IN SERVER 24 | } 25 | 26 | shiny::shinyApp(ui = ui, server = server) 27 | ``` 28 | 29 | #### Interactive steps to produce bad reactlog recording 30 | 31 | * Select A 32 | * Click plot 33 | * Show reactlog 34 | * ... 35 | 36 | 37 | ----------------- 38 | 39 | ## Playback issue 40 | 41 | Brief description of the problem. Given that Shiny recorded it correctly, the reactlog provided by `shiny::reactlog()` is not being displaying properly. 42 | 43 | Please attach a screenshot if appropriate. 44 | 45 | ```r 46 | jsonlite::toJSON(shiny::reactlog(), pretty = TRUE, auto_unbox = TRUE) 47 | ``` 48 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Pull Request 2 | 3 | Before you submit a pull request, please do the following: 4 | 5 | * Add an entry to NEWS concisely describing what you changed. 6 | 7 | * If appropriate, add unit tests in the tests/testthat directory. 8 | 9 | * Run Build->Check Package in the RStudio IDE, or `devtools::check()`, to make sure your change did not add any messages, warnings, or errors. (Known NOTE of large package size and sub-directories 'reactlogAsset' size.) 10 | 11 | Doing these things will make it easier for the `reactlog` development team to evaluate your pull request. Even so, we may still decide to modify your code or even not merge it at all. Factors that may prevent us from merging the pull request include: 12 | 13 | * breaking backward compatibility 14 | * adding a feature that we do not consider relevant for `reactlog` 15 | * is hard to understand 16 | * is hard to maintain in the future 17 | * is computationally expensive 18 | * is not intuitive for people to use 19 | 20 | We will try to be responsive and provide feedback in case we decide not to merge your pull request. 21 | 22 | ## Minimal reproducible example 23 | 24 | Finally, Please include a minimal reprex. The goal of a reprex is to make it as easy as possible for me to recreate your problem so that I can fix it. If you've never heard of a reprex before, start by reading , and follow the advice further down the page. Do NOT include session info unless it's explicitly asked for, or you've used `reprex::reprex(..., si = TRUE)` to hide it away. 25 | 26 | While you may not be able to submit true `reprex::reprex({#code})` due to the interactivity of shiny, a working [app.R script](http://shiny.rstudio.com/articles/app-formats.html#appr) containing the minimal elements to produce the error is highly appreciated. 27 | 28 | Delete these instructions once you have read them. 29 | 30 | --------------------------------------------- 31 | 32 | 33 | ## Playback issue fixed 34 | 35 | Brief description of the problem. Given that Shiny recorded it correctly, the reactlog provided by `shiny::reactlog()` is not being displaying properly. 36 | 37 | Please attach a screenshot of before and after if appropriate. 38 | 39 | ```r 40 | jsonlite::toJSON(shiny::reactlog(), pretty = TRUE, auto_unbox = TRUE) 41 | ``` 42 | 43 | 44 | --------------------------------------------- 45 | 46 | ## PR task list: 47 | 48 | - [ ] Passes `devtools::check()` 49 | - [ ] Add NEWS entry explaining change (reference username and PR#) 50 | - [ ] Add tests (if appropriate) 51 | - [ ] Update documentation with `devtools::document()` 52 | -------------------------------------------------------------------------------- /.github/shiny-workflows/website.R: -------------------------------------------------------------------------------- 1 | # copy readme files 2 | stopifnot( 3 | file.copy("readme-images/", "pkgdown/", recursive = TRUE) 4 | ) 5 | # copy demo files 6 | stopifnot( 7 | file.copy("inst/reactlog/", "pkgdown/", recursive = TRUE) 8 | ) 9 | # rename to 'demo' 10 | stopifnot( 11 | file.rename("pkgdown/reactlog", "pkgdown/demo") 12 | ) 13 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/rstudio/shiny-workflows 2 | # 3 | # NOTE: This Shiny team GHA workflow is overkill for most R packages. 4 | # For most R packages it is better to use https://github.com/r-lib/actions 5 | on: 6 | push: 7 | branches: [main, rc-**] 8 | pull_request: 9 | branches: [main] 10 | schedule: 11 | - cron: '0 8 * * 1' # every monday 12 | 13 | name: Package checks 14 | 15 | jobs: 16 | website: 17 | uses: rstudio/shiny-workflows/.github/workflows/website.yaml@v1 18 | routine: 19 | uses: rstudio/shiny-workflows/.github/workflows/routine.yaml@v1 20 | R-CMD-check: 21 | uses: rstudio/shiny-workflows/.github/workflows/R-CMD-check.yaml@v1 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Meta 2 | doc 3 | inst/doc 4 | 5 | # History files 6 | .Rhistory 7 | .Rapp.history 8 | 9 | # pkgdown output. Covered by GHA pkgdown 10 | docs/ 11 | 12 | # Session Data files 13 | .RData 14 | 15 | # Example code in package build process 16 | *-Ex.R 17 | 18 | # Output files from R CMD build 19 | /*.tar.gz 20 | 21 | # Output files from R CMD check 22 | /*.Rcheck/ 23 | 24 | # RStudio files 25 | .Rproj.user/ 26 | 27 | # produced vignettes 28 | vignettes/*.html 29 | vignettes/*.pdf 30 | 31 | # OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3 32 | .httr-oauth 33 | 34 | # knitr and R markdown default cache directories 35 | /*_cache/ 36 | /cache/ 37 | 38 | # Temporary files created by R markdown 39 | *.utf8.md 40 | *.knit.md 41 | 42 | # Shiny token, see https://shiny.rstudio.com/articles/shinyapps.html 43 | rsconnect/ 44 | 45 | .Rproj.user 46 | inst/reactlog/reactlogAsset/report.html 47 | node_modules 48 | flow-typed 49 | yarn-error.log 50 | src_old 51 | _ignore 52 | *.rej 53 | -------------------------------------------------------------------------------- /.lintr: -------------------------------------------------------------------------------- 1 | linters: linters_with_defaults( 2 | line_length_linter(100) 3 | ) 4 | exclusions: list( 5 | "inst/examples/03_reactivity/app.R" 6 | ) 7 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: reactlog 2 | Title: Reactivity Visualizer for 'shiny' 3 | Version: 1.1.1 4 | Authors@R: c( 5 | person( 6 | "Barret", "Schloerke", email = "barret@rstudio.com", role = c("aut", "cre"), 7 | comment = c(ORCID = "0000-0001-9986-114X") 8 | ), 9 | person("Joe", "Cheng", email = "joe@rstudio.com", role = c("ctb")), 10 | person("RStudio", role = c("cph", "fnd")) 11 | ) 12 | Description: Building interactive web applications with R is incredibly easy 13 | with 'shiny'. Behind the scenes, 'shiny' builds a reactive graph that can 14 | quickly become intertwined and difficult to debug. 'reactlog' 15 | (Schloerke 2019) provides a visual insight into 16 | that black box of 'shiny' reactivity by constructing a directed dependency 17 | graph of the application's reactive state at any time point in a reactive 18 | recording. 19 | Depends: 20 | R (>= 3.0.2) 21 | Imports: 22 | jsonlite (>= 0.9.16), 23 | Suggests: 24 | shiny (>= 1.5.0), 25 | fontawesome (>= 0.3.0), 26 | knitr, 27 | rmarkdown, 28 | htmltools, 29 | testthat 30 | License: GPL-3 | file LICENSE 31 | Encoding: UTF-8 32 | RoxygenNote: 7.2.1 33 | URL: https://rstudio.github.io/reactlog/, https://github.com/rstudio/reactlog, https://community.rstudio.com/tag/reactlog 34 | BugReports: https://github.com/rstudio/reactlog/issues 35 | VignetteBuilder: knitr 36 | Language: en-US 37 | Roxygen: list(markdown = TRUE) 38 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 2 | // make sure packages like lodash are not being double stored 3 | var DuplicatePackageCheckerPlugin = require("duplicate-package-checker-webpack-plugin"); 4 | // visualize the bundle size 5 | var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; 6 | 7 | module.exports = function(grunt) { 8 | 9 | var rootDir = __dirname; 10 | 11 | var instdir = rootDir + '/inst/reactlog/'; 12 | var jsSrcdir = rootDir + '/srcjs/'; 13 | 14 | gruntConfig = { 15 | 16 | webpack: { 17 | options: { 18 | mode: "production", // do not take time to shrink files; 19 | devtool: "source-map", // produce a sibling source map file 20 | stats: { 21 | colors: true, 22 | modules: true, 23 | reasons: true 24 | }, 25 | progress: true, 26 | failOnError: true, 27 | }, 28 | reactlog: { 29 | entry: jsSrcdir + "index.js", 30 | output: { 31 | path: instdir + "reactlogAsset", 32 | filename: 'reactlog.js' 33 | }, 34 | plugins: [ 35 | // new BundleAnalyzerPlugin({ 36 | // analyzerMode: 'static' 37 | // }), 38 | // new DuplicatePackageCheckerPlugin() 39 | ], 40 | watch: false, 41 | module: { 42 | rules: [{ 43 | test: /\.js$/, 44 | exclude: /node_modules/, 45 | use: [{ 46 | loader: "babel-loader" 47 | }] 48 | }] 49 | } 50 | } 51 | } 52 | 53 | }; 54 | 55 | grunt.loadNpmTasks('grunt-webpack'); 56 | 57 | 58 | grunt.task.registerTask("webpackSetWatch", "sets 'watch' to true for reactlog webpack task", function() { 59 | gruntConfig.webpack.reactlog.watch = true 60 | }); 61 | 62 | 63 | grunt.initConfig(gruntConfig); 64 | 65 | grunt.registerTask("default", "webpack:reactlog") 66 | 67 | }; 68 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(reactlog_disable) 4 | export(reactlog_enable) 5 | export(reactlog_module_server) 6 | export(reactlog_module_ui) 7 | export(reactlog_render) 8 | export(reactlog_show) 9 | export(reactlog_write) 10 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # reactlog 1.1.1 2 | 3 | - Fixed Font Awesome icon warning about `refresh` icon (#87) 4 | 5 | # reactlog 1.1.0 6 | 7 | - Added a shiny module to inline the current `reactlog`. See `?reactlog_module_ui` for an example (#66) 8 | - Added `reactlog_enable()` and `reactlog_disable()` which replace the need to explicitly set R options (#61) 9 | - Use log entry for status bar instead of a final graph (#67) 10 | - Allow reactlog to handle isolate calls in a non-reactive context (#68) 11 | 12 | 13 | # reactlog 1.0.0 14 | 15 | Initialize package 16 | -------------------------------------------------------------------------------- /R/renderReactLog.R: -------------------------------------------------------------------------------- 1 | inst_reactlog_file <- function(file) { 2 | system.file(file.path("reactlog", file), package = "reactlog") 3 | } 4 | inst_reactlog_assets <- function() { 5 | inst_reactlog_file("reactlogAsset") 6 | } 7 | 8 | 9 | #' @export 10 | #' @rdname reactlog_show 11 | #' @param session_token token to be used to subset which session is displayed. 12 | #' Defaults to all sessions. 13 | reactlog_render <- function(log, session_token = NULL, time = TRUE) { 14 | log <- reactlog_upgrade(log) 15 | 16 | template_file <- inst_reactlog_file("reactlog.html") 17 | # does not need utf8 support 18 | html <- paste(readLines(template_file, warn = FALSE), collapse = "\n") 19 | 20 | # get the json form of the lgo without writing to disk 21 | json_blob <- as.character( 22 | reactlog_write(log, file = NULL, session_token = session_token) 23 | ) 24 | 25 | fixed_sub <- function(...) { 26 | sub(..., fixed = TRUE) 27 | } 28 | 29 | html <- fixed_sub( 30 | "__DATA__", paste(json_blob, collapse = "\n"), 31 | fixed_sub( 32 | "__TIME__", paste0("\"", time, "\""), 33 | fixed_sub( 34 | "", "", 35 | html 36 | ) 37 | ) 38 | ) 39 | 40 | # check if shiny is even available 41 | if (requireNamespace("shiny")) { 42 | # add resource path to pkg files for shiny 43 | # (avoids warning of tmp folder moving around) 44 | shiny::addResourcePath( 45 | "reactlogAsset", # prefix 46 | inst_reactlog_assets() 47 | ) 48 | } 49 | 50 | file <- tempfile(fileext = ".html") 51 | 52 | write_utf8(html, file = file) 53 | 54 | # copy js and style folder 55 | file.copy( 56 | inst_reactlog_assets(), 57 | dirname(file), 58 | recursive = TRUE 59 | ) 60 | 61 | return(file) 62 | } 63 | -------------------------------------------------------------------------------- /R/setReactLog.R: -------------------------------------------------------------------------------- 1 | #' Enable or disable the reactlog 2 | #' 3 | #' Before the reactlog can be visualized, it needs to be enabled. For security 4 | #' and performance reasons, you should not enable the reactlog in a shiny app 5 | #' in production. 6 | #' @param warn Should a warning message be shown? 7 | #' @seealso [reactlog::reactlog_show()] 8 | #' @name setReactLog 9 | #' @export 10 | #' @rdname setReactLog 11 | reactlog_enable <- function() { 12 | options(shiny.reactlog = TRUE) 13 | } 14 | 15 | #' @export 16 | #' @rdname setReactLog 17 | reactlog_disable <- function(warn = TRUE) { 18 | if (!isTRUE(warn) && !identical(warn, FALSE)) { 19 | stop("'warn' must be either 'TRUE' or 'FALSE'") 20 | } 21 | 22 | options(shiny.reactlog = FALSE) 23 | if (isTRUE(warn)) { 24 | warning("Please restart R to free up 'reactlog' memory", call. = FALSE) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /R/shinyModule.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | #' Reactlog Shiny Module 4 | #' 5 | #' Displays an iframe of the reactlog in the given application. 6 | #' 7 | #' State will not be preserved between refreshes. 8 | #' To open the reactlog at a particular step, be sure to mark your time points 9 | #' with `Cmd+Shift+F3` (Windows: `Ctrl+Shift+F3`) 10 | #' 11 | #' @param id \pkg{shiny} module id to use 12 | #' @param ... parameters passed to [shiny::actionButton()] 13 | #' @param width,height HTML attributes to be applied to the reactlog iframe 14 | #' @param include_refresh should the iframe refresh button be included? 15 | #' @seealso [shiny::moduleServer()] 16 | #' @rdname reactlog_module 17 | #' @export 18 | #' @examples 19 | #' if (!require("shiny")) { 20 | #' message("`shiny` required to run example") 21 | #' return() 22 | #' } 23 | #' 24 | #' library(shiny) 25 | #' # Enable reactlog 26 | #' reactlog_enable() 27 | #' 28 | #' # Define UI for app that draws a histogram ---- 29 | #' ui <- fluidPage( 30 | #' tags$h1("Pythagorean theorem"), 31 | #' numericInput("a", "A", 3), 32 | #' numericInput("b", "B", 4), 33 | #' "C:", verbatimTextOutput("c"), 34 | #' ### start ui module 35 | #' reactlog_module_ui() 36 | #' ### end ui module 37 | #' ) 38 | #' 39 | #' server <- function(input, output, session) { 40 | #' a2 <- reactive({a <- input$a; req(a); a * a}, label = "a^2") 41 | #' b2 <- reactive({b <- input$b; req(b); b * b}, label = "b^2") 42 | #' c2 <- reactive({a2() + b2()}, label = "c^2") 43 | #' c_val <- reactive({sqrt(c2())}, label = "c") 44 | #' 45 | #' output$c <- renderText({ 46 | #' c_val() 47 | #' }) 48 | #' 49 | #' ### start server module 50 | #' reactlog_module_server() 51 | #' ### end server module 52 | #' 53 | #' } 54 | #' 55 | #' if (interactive()) { 56 | #' shinyApp(ui = ui, server = server) 57 | #' } 58 | reactlog_module_ui <- function(include_refresh = TRUE, id = "reactlog_module") { 59 | ns <- shiny::NS(id) 60 | shiny::tagList( 61 | if (isTRUE(include_refresh)) 62 | shiny::actionButton( 63 | ns("refresh"), 64 | "", 65 | icon = shiny::icon("arrows-rotate", lib = "font-awesome"), 66 | class = "btn-sm btn-warning" 67 | ), 68 | shiny::uiOutput(ns("iframe")) 69 | ) 70 | } 71 | 72 | #' @rdname reactlog_module 73 | #' @export 74 | reactlog_module_server <- function( 75 | id = "reactlog_module", 76 | width = "100%", 77 | height = 600, 78 | ... 79 | ) { 80 | 81 | assert_shiny_version() 82 | 83 | shiny::moduleServer( 84 | id, 85 | function(input, output, session) { 86 | ns <- shiny::NS(id) 87 | 88 | output$iframe <- shiny::renderUI({ 89 | # trigger render refresh 90 | input$refresh 91 | 92 | test_mode_txt <- 93 | if (isTRUE(getOption("shiny.testmode"))) { 94 | "&test=1" 95 | } else { 96 | "" 97 | } 98 | 99 | random_id <- ns(paste0( 100 | "reactlog_iframe_", 101 | as.hexmode(floor(stats::runif(1, 1, 16^7))) 102 | )) 103 | htmltools::tagList( 104 | htmltools::tags$iframe( 105 | id = random_id, 106 | width = width, 107 | height = height, 108 | ... 109 | ), 110 | htmltools::tags$script(htmltools::HTML(paste0(" 111 | (function() { 112 | var src = 113 | 'reactlog?w=' + window.escape(window.Shiny.shinyapp.config.workerId) + 114 | '&s=' + window.escape(window.Shiny.shinyapp.config.sessionId) + '", 115 | test_mode_txt, "'; 116 | $('#", random_id, "').attr('src', src); 117 | })() 118 | "))) 119 | ) 120 | 121 | }) 122 | 123 | } 124 | ) 125 | } 126 | 127 | 128 | shiny_version_required <- function() { 129 | desc_file <- system.file("DESCRIPTION", package = "reactlog") 130 | suggests <- read.dcf(desc_file)[1, "Suggests"] 131 | pkgs <- strsplit(suggests, ",")[[1]] 132 | shiny_version <- gsub("[^.0-9]", "", pkgs[grepl("^shiny ", pkgs)]) 133 | package_version(shiny_version) 134 | } 135 | test_shiny_version <- function() { 136 | tryCatch({ 137 | utils::packageVersion("shiny") >= shiny_version_required() 138 | }, error = function() { 139 | # package not found 140 | FALSE 141 | }) 142 | } 143 | assert_shiny_version <- function() { 144 | if (!test_shiny_version()) { 145 | stop("`shiny` v", shiny_version_required, " or greater must be installed") 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /R/showReactLog.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #' Reactive Log Visualizer 5 | #' 6 | #' Provides an interactive browser-based tool for visualizing reactive 7 | #' dependencies and execution in your application. 8 | #' 9 | #' To use the reactive log visualizer, start with a fresh R session and 10 | #' run the command \code{reactlog_enable()}; then launch your 11 | #' application in the usual way (e.g. using [shiny::runApp()]). At 12 | #' any time you can hit \preformatted{Ctrl+F3} 13 | #' (or for Mac users, \preformatted{Cmd+F3}) in your 14 | #' web browser to launch the reactive log visualization. 15 | #' 16 | #' The reactive log visualization only includes reactive activity up 17 | #' until the time the report was loaded. If you want to see more recent 18 | #' activity, refresh the browser. 19 | #' 20 | #' Note that Shiny does not distinguish between reactive dependencies 21 | #' that "belong" to one Shiny user session versus another, so the 22 | #' visualization will include all reactive activity that has taken place 23 | #' in the process, not just for a particular application or session. 24 | #' 25 | #' As an alternative to pressing \preformatted{Ctrl/Cmd+F3}--for example, if you 26 | #' are using reactives outside of the context of a Shiny 27 | #' application--you can run the [shiny::reactlogShow()] function, which will 28 | #' generate the reactive log visualization as a static HTML file and 29 | #' launch it in your default browser. In this case, refreshing your 30 | #' browser will not load new activity into the report; you will need to 31 | #' call [shiny::reactlogShow()] explicitly. 32 | #' 33 | #' For security and performance reasons, do not enable the reactlog 34 | #' in production environments. When the option is 35 | #' enabled, it's possible for any user of your app to see at least some 36 | #' of the source code of your reactive expressions and observers. 37 | #' 38 | #' @param log Log produced by shiny to be processed 39 | #' @param time A boolean that specifies whether or not to display the 40 | #' time that each reactive takes to calculate a result. 41 | #' @param ... Future parameter expansion. Currently ignored 42 | #' @seealso [shiny::reactlogShow()] and 43 | #' [reactlog::reactlog_enable()] 44 | #' @export 45 | #' @examples 46 | #' 47 | #' \dontrun{ 48 | #' library(shiny) 49 | #' library(reactlog) 50 | #' 51 | #' # tell shiny to log reactivity 52 | #' reactlog_enable() 53 | #' 54 | #' # run a shiny app 55 | #' app <- system.file("examples/01_hello", package = "shiny") 56 | #' runApp(app) 57 | #' 58 | #' # once app has closed, display reactlog 59 | #' shiny::reactlogShow() 60 | #' } 61 | 62 | reactlog_show <- function(log, time = TRUE, ...) { 63 | file <- reactlog_render(log, time = as.logical(time), ...) 64 | utils::browseURL(file) 65 | } 66 | 67 | #' Write reactlog 68 | #' 69 | #' Write the reactlog to a file. If a session token is provided, all reactive 70 | #' interactions will be subsetted to either the global session or the 71 | #' session provided. 72 | #' 73 | #' @param log produced by shiny to be written 74 | #' @param file location of output file. If a \code{NULL} file is given, the 75 | #' json representation is return. 76 | #' @param session_token Session token identifier to be used when subsetting the 77 | #' complete reactlog 78 | #' @export 79 | reactlog_write <- function(log, file = stdout(), session_token = NULL) { 80 | if (!is.null(session_token)) { 81 | log <- Filter( 82 | function(x) { 83 | is.null(x$session) || identical(x$session, session_token) 84 | }, 85 | log 86 | ) 87 | } 88 | json <- jsonlite::toJSON( 89 | log, pretty = TRUE, 90 | # from shiny pkg 91 | null = "null", na = "null", 92 | auto_unbox = TRUE, digits = getOption("shiny.json.digits", 16), 93 | use_signif = TRUE, force = TRUE, POSIXt = "ISO8601", UTC = TRUE, 94 | rownames = FALSE, keep_vec_names = TRUE, strict_atomic = TRUE 95 | ) 96 | if (is.null(file)) { 97 | # return the json as a character string 98 | json 99 | } else { 100 | # write to the file connection 101 | write_utf8(json, file = file) 102 | } 103 | } 104 | 105 | 106 | write_utf8 <- function(x, file, ...) { 107 | writeLines(enc2utf8(x), file, ..., useBytes = TRUE) 108 | } 109 | -------------------------------------------------------------------------------- /R/version.R: -------------------------------------------------------------------------------- 1 | 2 | reactlog_upgrade <- function(log) { 3 | version <- attr(log, "version") 4 | if (is.null(version)) { 5 | stop("'log' is missing a 'version' attribute. This is required.") 6 | } 7 | version <- as.character(version) 8 | if (identical(version, "1")) { 9 | return(log) 10 | } 11 | 12 | stop( 13 | "Versions available: 1\n", 14 | "Latest reactlog version: 1\n", 15 | "Version provided: ", version 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # reactlog 2 | 3 | 4 | [![R build status](https://github.com/rstudio/reactlog/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/rstudio/reactlog/actions) 5 | [![CRAN version](http://www.r-pkg.org/badges/version/reactlog)](https://cran.r-project.org/package=reactlog) 6 | [![reactlog downloads per month](http://cranlogs.r-pkg.org/badges/reactlog)](http://www.rpackages.io/package/reactlog) 7 | [![DOI](https://zenodo.org/badge/137799634.svg)](https://zenodo.org/badge/latestdoi/137799634) 8 | [![RStudio community](https://img.shields.io/badge/community-reactlog-blue?style=social&logo=rstudio&logoColor=75AADB)](https://community.rstudio.com/tags/c/shiny/8/reactlog) 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | [Shiny](https://shiny.rstudio.com/) is an R package from RStudio that makes it incredibly easy to build interactive web applications with R. Behind the scenes, Shiny builds a reactive graph that can quickly become intertwined and difficult to debug. **reactlog** provides a visual insight into that _black box_ of Shiny reactivity. 18 | 19 | After logging the reactive interactions of a Shiny application, **reactlog** constructs a directed dependency graph of the Shiny's reactive state at any time point in the record. The **reactlog** dependency graph provides users with the ability to visually see if reactive elements are: 20 | * Not utilized (never retrieved) 21 | * Over utilized (called independently many times) 22 | * Interacting with unexpected elements 23 | * Invalidating all expected dependencies 24 | * Freezing (and thawing), preventing triggering of future reactivity 25 | 26 | 27 | 28 | 29 | ## Major Features 30 | 31 | There are many subtle features hidden throughout **reactlog**. Here is a short list quickly describing what is possible within **reactlog**: 32 | 33 | * Display the reactivity dependency graph of your Shiny applications 34 | * Navigate throughout your reactive history to replay element interactions 35 | * Highlight reactive family trees 36 | * Filter on reactive family trees 37 | * Search for reactive elements 38 | 39 | For a more in-depth explanation of **reactlog**, please visit the [**reactlog** vignette](https://rstudio.github.io/reactlog/articles/reactlog.html). 40 | 41 | ## Installation 42 | 43 | To install the stable version from CRAN, run the following from an R console: 44 | 45 | ```r 46 | install.packages("reactlog") 47 | ``` 48 | 49 | For the latest development version: 50 | 51 | ```r 52 | remotes::install_github("rstudio/reactlog") 53 | ``` 54 | 55 | ## Usage 56 | 57 | 58 | ```r 59 | library(shiny) 60 | library(reactlog) 61 | 62 | # tell shiny to log all reactivity 63 | reactlog_enable() 64 | 65 | # run a shiny app 66 | app <- system.file("examples/01_hello", package = "shiny") 67 | runApp(app) 68 | 69 | # once app has closed, display reactlog from shiny 70 | shiny::reactlogShow() 71 | ``` 72 | 73 | Or while your Shiny app is running, press the key combination `Ctrl+F3` (Mac: `Cmd+F3`) to launch the **reactlog** application. 74 | 75 | To mark a specific execution time point within your Shiny app, press the key combination `Ctrl+Shift+F3` (Mac: `Cmd+Shift+F3`). This will highlight a specific point in time in your reactlog. 76 | 77 | 78 | #### Example 79 | 80 | Here is a [demo](https://rstudio.github.io/reactlog/demo/reactlog.html) of the **reactlog** visualization applied to the [`cranwhales`](https://github.com/rstudio/cranwhales) shiny app. 81 | 82 | [ 83 | 84 | ](https://rstudio.github.io/reactlog/demo/reactlog.html) 85 | 86 | For more examples and explanation, see the [**reactlog** vignette](https://rstudio.github.io/reactlog/articles/reactlog.html#reactlog). 87 | 88 | 89 | ## Community Support 90 | 91 | The best place to get help with Shiny and **reactlog** is [RStudio Community](https://community.rstudio.com/c/shiny/8). 92 | If you're having difficulties with **reactlog**, feel free to [ask questions here](https://community.rstudio.com/new-topic?title=&category_id=8&tags=reactlog&body=%0A%0A%0A%20%20--------%0A%20%20%0A%20%20%3Csup%3EReferred%20here%20by%20%60reactlog%60%27s%20README%3C/sup%3E%0A&u=barret). 93 | For bug reports, please use the **reactlog** [issue tracker](https://github.com/rstudio/reactlog/issues). 94 | 95 | 96 | ## Development 97 | 98 | [![node version: 12.x](https://img.shields.io/badge/node-12.x-brightgreen.svg)](https://nodejs.org/en/) 99 | [![yarn version: 1.x](https://img.shields.io/badge/yarn-1.x-257bac.svg)](https://classic.yarnpkg.com/lang/en/) 100 | [![JavaScript type: flow](https://img.shields.io/npm/types/flow-typed.svg)](https://github.com/flow-typed/flow-typed) 101 | [![cytoscape](https://img.shields.io/github/package-json/dependency-version/rstudio/reactlog/cytoscape.svg)](https://js.cytoscape.org/) 102 | [![@babel/preset-env](https://img.shields.io/github/package-json/dependency-version/rstudio/reactlog/dev/@babel/preset-env.svg)](https://babeljs.io/) 103 | [![webpack](https://img.shields.io/github/package-json/dependency-version/rstudio/reactlog/dev/webpack.svg)](https://webpack.js.org/) 104 | [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) 105 | [![linter: eslint](https://img.shields.io/badge/linter-eslint-3524ca.svg)](https://eslint.org/) 106 | 107 | 108 | Please make sure you have [GitHub Large File Storage](https://git-lfs.github.com/), [Node.js](https://nodejs.org/en/) and [yarn](https://classic.yarnpkg.com/en/docs/install) installed. 109 | 110 | Installation script: 111 | 112 | ```bash 113 | # install git lfs hooks 114 | git lfs install 115 | 116 | # install dependencies and build JavaScript 117 | yarn install 118 | 119 | # build on file change 120 | yarn watch 121 | ``` 122 | 123 | By changing the file `'./inst/reactlog/defaultLog.js'` with the contents of any log file in `'./inst/log-files/'`, different default log files can be loaded. Once the local JavaScript (`'./inst/reactlog/reactlogAsset/reactlog.js'`) has been built with `yarn build` or `yarn watch`, refresh `'./inst/reactlog/reactlog.html'` to avoid constantly spawning Shiny applications for testing. 124 | -------------------------------------------------------------------------------- /bin/clean_rlog_file.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # should be used with `npm run fix FILE` 4 | 5 | yarn lint "$@" 6 | 7 | yarn build-only 8 | -------------------------------------------------------------------------------- /bin/lint_file.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ex 2 | 3 | # should be used with `yarn lint FILE` 4 | 5 | if [[ "$#" == 0 ]] 6 | then 7 | echo "please include a file to lint and make prettier: 'yarn lint FILE'" 8 | exit 1; 9 | fi 10 | 11 | echo "eslint..." 12 | eslint --fix "$@" 13 | 14 | echo "prettier..." 15 | prettier --write "$@" 16 | 17 | # echo "flow..." 18 | # flow status 19 | -------------------------------------------------------------------------------- /bin/postinstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # do not create stubs from missing libraries 4 | # ignore dev dependencies 5 | yarn flow-typed install --skip true --ignoreDeps dev 6 | 7 | yarn build-only 8 | -------------------------------------------------------------------------------- /bin/update-license.js: -------------------------------------------------------------------------------- 1 | // node ./scripts/license_checker.js > LICENSE.note 2 | 3 | var checker = require('license-checker'); 4 | var fs = require('fs'); 5 | 6 | var pkg = require('./../package.json'); 7 | 8 | var _ = require('lodash'); 9 | 10 | 11 | checker.init( 12 | { 13 | start: '.' 14 | }, 15 | function(err, license_json) { 16 | if (err) { 17 | console.log(err); 18 | return err; 19 | } 20 | for_every_prod_package = function(fn) { 21 | var pkg_name, pkg_title, pkg_info; 22 | for (pkg_name in license_json) { 23 | pkg_title = pkg_name.replace(/\@\d+\.\d+\.\d+$/, ""); 24 | if (_.has(pkg.dependencies, pkg_title)) { 25 | pkg_info = license_json[pkg_name]; 26 | fn(pkg_name, pkg_info, pkg_title); 27 | } 28 | } 29 | } 30 | 31 | console.log("The reactlog package as a whole is distributed under GPL-3 (GNU GENERAL PUBLIC LICENSE version 3).\n\nThe reactlog package includes other open source software components. The following\nis a list of these components (full copies of the license agreements used by\nthese components are included below):"); 32 | console.log(""); 33 | 34 | //The sorted json data 35 | // console.log(json); 36 | for_every_prod_package(function(pkg_name, pkg_info, pkg_title) { 37 | console.log(" -", pkg_name, "-", pkg_info.licenses, "-", pkg_info.repository); 38 | }); 39 | console.log("\n\n\n"); 40 | for_every_prod_package(function(pkg_name, pkg_info, pkg_title) { 41 | console.log(pkg_name, "-", pkg_info.licenses, "-", pkg_info.repository); 42 | console.log("----------------------------------------------------"); 43 | file_info = fs.readFileSync(pkg_info.licenseFile, 'utf8'); 44 | console.log(file_info); 45 | console.log("\n\n\n\n"); 46 | }); 47 | } 48 | ); 49 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## Comments 2 | 3 | #### 2022-09-19 4 | 5 | * Fixed a `{fontawesome}` bug. 6 | * Removed `LazyData: true` from DESCRIPTION. 7 | 8 | Please let me know if there is anything else I can provide. 9 | 10 | Best, 11 | Barret 12 | 13 | ## Test environments 14 | 15 | * local macOS, R 4.1.3 16 | * r-hub 17 | * GitHub Actions 18 | * macOS 19 | * 4.2 20 | * windows 21 | * 4.2 22 | * ubuntu18 23 | * devel, 4.2, 4.1, 4.0, 3.6, 3.5 24 | * devtools:: 25 | * check_win_devel() 26 | 27 | ## R CMD check results 28 | 29 | 0 errors ✔ | 0 warnings ✔ | 0 notes ✔ 30 | 31 | ## revdepcheck results 32 | 33 | We checked 1 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package. 34 | 35 | * We saw 0 new problems 36 | * We failed to check 0 packages 37 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /inst/examples/03_reactivity/app.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | # Enable reactlog 3 | reactlog::reactlog_enable() 4 | 5 | # The app below is a VERY condensed form of shiny::runExample("03_reactivity") 6 | # with the reactlog module added in the `ui` and `server` 7 | ui <- fluidPage( 8 | titlePanel("Reactivity"), 9 | sidebarLayout( 10 | sidebarPanel( 11 | textInput(inputId = "caption", label = "Caption:", value = "Data Summary"), 12 | selectInput(inputId = "dataset", label = "Choose a dataset:", choices = c("rock", "pressure", "cars")), 13 | numericInput(inputId = "obs", label = "Number of observations to view:", value = 10) 14 | ), 15 | mainPanel( 16 | h3(textOutput("caption_out", container = span)), 17 | verbatimTextOutput("summary"), 18 | tableOutput("view") 19 | ) 20 | ), 21 | ### start module ui 22 | reactlog::reactlog_module_ui(include_refresh = TRUE) 23 | ### end module ui 24 | ) 25 | 26 | server <- function(input, output) { 27 | datasetInput <- reactive({ 28 | switch(input$dataset, "rock" = rock, "pressure" = pressure, "cars" = cars) 29 | }) 30 | output$caption_out <- renderText({ input$caption }) 31 | output$summary <- renderPrint({ summary(datasetInput()) }) 32 | output$view <- renderTable({ head(datasetInput(), n = input$obs) }) 33 | 34 | ### start module server 35 | reactlog::reactlog_module_server() 36 | ### end module server 37 | } 38 | 39 | shinyApp(ui = ui, server = server) 40 | -------------------------------------------------------------------------------- /inst/examples/03_reactivity/tests/shinytest.R: -------------------------------------------------------------------------------- 1 | library(shinytest) 2 | shinytest::testApp("../") 3 | -------------------------------------------------------------------------------- /inst/examples/03_reactivity/tests/shinytest/mytest-expected/001.json: -------------------------------------------------------------------------------- 1 | { 2 | "input": { 3 | "caption": "Data Summary", 4 | "dataset": "rock", 5 | "obs": 10, 6 | "reactlog_module-refresh": 1 7 | }, 8 | "output": { 9 | "caption_out": "Data Summary", 10 | "reactlog_module-iframe": { 11 | "html": "