├── .Rbuildignore ├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── bug.yml │ ├── config.yml │ ├── cran-release.yml │ ├── feature.yml │ ├── question.yml │ └── release.yml ├── pull_request_template.md └── workflows │ ├── check.yaml │ ├── cla.yaml │ ├── docs.yaml │ ├── post-release.yaml │ ├── release.yaml │ └── scheduled.yaml ├── .gitignore ├── .gitlab-ci.yml ├── .lintr ├── .pre-commit-config.yaml ├── DESCRIPTION ├── LICENSE ├── NAMESPACE ├── NEWS.md ├── R ├── TealAppDriver.R ├── checkmate.R ├── dummy_functions.R ├── include_css_js.R ├── init.R ├── landing_popup_module.R ├── module_bookmark_manager.R ├── module_data_summary.R ├── module_filter_data.R ├── module_filter_manager.R ├── module_init_data.R ├── module_nested_tabs.R ├── module_session_info.R ├── module_snapshot_manager.R ├── module_teal.R ├── module_teal_data.R ├── module_teal_lockfile.R ├── module_teal_with_splash.R ├── module_transform_data.R ├── modules.R ├── reporter_previewer_module.R ├── show_rcode_modal.R ├── tdata.R ├── teal.R ├── teal_data_module-eval_code.R ├── teal_data_module-within.R ├── teal_data_module.R ├── teal_data_utils.R ├── teal_modifiers.R ├── teal_reporter.R ├── teal_slices-store.R ├── teal_slices.R ├── teal_transform_module.R ├── utils.R ├── validate_inputs.R ├── validations.R └── zzz.R ├── README.md ├── SECURITY.md ├── _pkgdown.yml ├── inst ├── WORDLIST ├── css │ ├── custom.css │ ├── sidebar.css │ └── validation.css ├── design │ ├── filters-mapping.drawio │ ├── teal-app-components-hover.drawio │ ├── teal-app-components.drawio │ ├── teal-transform-module-decorators.drawio │ └── teal-transform-module-transformators.drawio └── js │ ├── clipboard.js │ ├── init.js │ └── togglePanelItems.js ├── man ├── TealAppDriver.Rd ├── TealReportCard.Rd ├── TealSlicesBlock.Rd ├── add_landing_modal.Rd ├── append_module.Rd ├── bookmarks_identical.Rd ├── build_app_title.Rd ├── check_filter_datanames.Rd ├── check_modules_datanames.Rd ├── check_reactive.Rd ├── create_app_id.Rd ├── decorate_err_msg.Rd ├── deep_copy_filter.Rd ├── dot-add_signature_to_data.Rd ├── dot-call_once_when.Rd ├── dot-get_hashes_code.Rd ├── dot-smart_rbind.Rd ├── dot-teal_favicon.Rd ├── example_module.Rd ├── extract_transformators.Rd ├── figures │ ├── filterpanel.png │ ├── lifecycle-archived.svg │ ├── lifecycle-defunct.svg │ ├── lifecycle-deprecated.svg │ ├── lifecycle-experimental.svg │ ├── lifecycle-maturing.svg │ ├── lifecycle-questioning.svg │ ├── lifecycle-soft-deprecated.svg │ ├── lifecycle-stable.svg │ ├── lifecycle-superseded.svg │ ├── logo.svg │ ├── readme_app.webp │ ├── reporter.jpg │ └── showrcode.jpg ├── get_client_timezone.Rd ├── get_unique_labels.Rd ├── include_css_files.Rd ├── include_js_files.Rd ├── include_teal_css_js.Rd ├── init.Rd ├── is_arg_used.Rd ├── landing_popup_module.Rd ├── make_teal_transform_server.Rd ├── module_bookmark_manager.Rd ├── module_data_summary.Rd ├── module_filter_data.Rd ├── module_filter_manager.Rd ├── module_init_data.Rd ├── module_labels.Rd ├── module_management.Rd ├── module_session_info.Rd ├── module_snapshot_manager.Rd ├── module_teal.Rd ├── module_teal_data.Rd ├── module_teal_lockfile.Rd ├── module_teal_module.Rd ├── module_teal_with_splash.Rd ├── module_transform_data.Rd ├── modules_bookmarkable.Rd ├── modules_depth.Rd ├── pluralize.Rd ├── report_card_template.Rd ├── reporter_previewer_module.Rd ├── restoreValue.Rd ├── run_js_files.Rd ├── show_rcode_modal.Rd ├── slices_store.Rd ├── tdata.Rd ├── teal-package.Rd ├── teal_data_module.Rd ├── teal_data_to_filtered_data.Rd ├── teal_data_utilities.Rd ├── teal_extend_server.Rd ├── teal_modifiers.Rd ├── teal_modules.Rd ├── teal_slices.Rd ├── teal_transform_module.Rd ├── validate_app_title_tag.Rd ├── validate_has_data.Rd ├── validate_has_elements.Rd ├── validate_has_variable.Rd ├── validate_in.Rd ├── validate_inputs.Rd ├── validate_n_levels.Rd ├── validate_no_intersection.Rd └── validate_one_row_per_id.Rd ├── revdep └── .gitignore ├── staged_dependencies.yaml ├── teal.Rproj ├── tests ├── testthat.R └── testthat │ ├── helper-shinytest2.R │ ├── setup-logger.R │ ├── setup-options.R │ ├── setup-testing_depth.R │ ├── test-init.R │ ├── test-module_session_info.R │ ├── test-module_teal.R │ ├── test-modules.R │ ├── test-report_previewer_module.R │ ├── test-shinytest2-data_summary.R │ ├── test-shinytest2-decorators.R │ ├── test-shinytest2-filter_panel.R │ ├── test-shinytest2-init.R │ ├── test-shinytest2-landing_popup.R │ ├── test-shinytest2-module_bookmark_manager.R │ ├── test-shinytest2-modules.R │ ├── test-shinytest2-reporter.R │ ├── test-shinytest2-show-rcode.R │ ├── test-shinytest2-teal_data_module.R │ ├── test-shinytest2-teal_slices.R │ ├── test-shinytest2-wunder_bar.R │ ├── test-teal_data_module-eval_code.R │ ├── test-teal_data_module.R │ ├── test-teal_reporter.R │ ├── test-teal_slices-store.R │ ├── test-teal_slices.R │ ├── test-teal_transform_module.R │ ├── test-utils.R │ ├── test-validate_has_data.R │ └── test-validate_inputs.R └── vignettes ├── .gitignore ├── adding-support-for-reporting.Rmd ├── blueprint ├── _setup.Rmd ├── actors.Rmd ├── dataflow.Rmd ├── filter_panel.Rmd ├── in_app_data.Rmd ├── index.Rmd ├── input_data.Rmd ├── intro.Rmd ├── module_encapsulation.Rmd └── product_map.Rmd ├── bootstrap-themes-in-teal.Rmd ├── creating-custom-modules.Rmd ├── data-as-shiny-module.Rmd ├── filter-panel.Rmd ├── getting-started-with-teal.Rmd ├── images ├── bs-corners.png ├── bs-final.png ├── bs-font-size.png ├── bs-launch.png ├── bs-theme-set.png ├── custom_app.png ├── filters-mapping.svg ├── reporter.jpg ├── show_code_prepro_missing.png ├── show_code_prepro_present.png ├── teal-app-components-hover.svg ├── teal-app-components.svg ├── teal-transform-module-decorators.svg └── teal-transform-module-transformators.svg ├── including-data-in-teal-applications.Rmd ├── teal-as-a-shiny-module.Rmd ├── teal-options.Rmd ├── transform-input-data.Rmd └── transform-module-output.Rmd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | LICENSE 2 | ^renv$ 3 | ^renv\.lock$ 4 | CODE_OF_CONDUCT.md 5 | SECURITY.md 6 | ^.*\.Rproj$ 7 | ^Jenkinsfile$ 8 | ^Makefile$ 9 | ^Meta$ 10 | ^TODO\.md$ 11 | ^[^/]+\.R$ 12 | ^[^/]+\.Rmd$ 13 | ^[^/]+\.html$ 14 | ^[^/]+\.png$ 15 | ^\.CI-FORCE-RELEASE-VERSION$ 16 | ^\.Rprofile$ 17 | ^\.Rproj\.user$ 18 | ^\.drone\.yml$ 19 | ^\.github$ 20 | ^\.gitlab-ci\.yml$ 21 | ^\.lintr$ 22 | ^\.travis\.yml$ 23 | ^\_pkgdown\.yaml$ 24 | ^\_pkgdown\.yml 25 | ^_dev$ 26 | ^build_docker_image$ 27 | ^cache$ 28 | ^data-raw$ 29 | ^data/script\.R$ 30 | ^design$ 31 | ^dev$ 32 | ^doc$ 33 | ^docs$ 34 | ^logs$ 35 | ^man-roxygen$ 36 | ^outputdir$ 37 | ^\.pre-commit-config\.yaml$ 38 | ^scratch$ 39 | ^staged_dependencies\.yaml$ 40 | ^stubs$ 41 | ^temp$ 42 | ^templates$ 43 | ^test_full_example$ 44 | coverage.* 45 | ^pkgdown$ 46 | ^.revdeprefs\.yaml$ 47 | ^revdep$ 48 | ^\.covrignore$ 49 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐞 Bug Report 3 | description: File a bug report 4 | title: "[Bug]: " 5 | labels: ["bug"] 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Thanks for taking the time to fill out this bug report! 11 | - type: textarea 12 | id: what-happened 13 | attributes: 14 | label: What happened? 15 | description: Also tell us, what did you expect to happen? 16 | placeholder: Tell us what you see! 17 | value: "A bug happened!" 18 | validations: 19 | required: true 20 | - type: textarea 21 | id: session-info 22 | attributes: 23 | label: sessionInfo() 24 | description: Please copy and paste your output from `sessionInfo()`. This will be automatically formatted into code, so no need for backticks. 25 | render: R 26 | - type: textarea 27 | id: logs 28 | attributes: 29 | label: Relevant log output 30 | description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. 31 | render: R 32 | - type: checkboxes 33 | id: code-of-conduct 34 | attributes: 35 | label: Code of Conduct 36 | description: By submitting this issue, you agree to follow our [Code of Conduct.](https://insightsengineering.github.io/teal/latest-tag/CODE_OF_CONDUCT.html) 37 | options: 38 | - label: I agree to follow this project's Code of Conduct. 39 | required: true 40 | - type: checkboxes 41 | id: contributor-guidelines 42 | attributes: 43 | label: Contribution Guidelines 44 | description: By submitting this issue, you agree to follow our [Contribution Guidelines.](https://insightsengineering.github.io/teal/latest-tag/CONTRIBUTING.html) 45 | options: 46 | - label: I agree to follow this project's Contribution Guidelines. 47 | required: true 48 | - type: checkboxes 49 | id: security-policy 50 | attributes: 51 | label: Security Policy 52 | description: By submitting this issue, you agree to follow our [Security Policy.](https://github.com/insightsengineering/teal/security/policy) 53 | options: 54 | - label: I agree to follow this project's Security Policy. 55 | required: true 56 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | blank_issues_enabled: false 3 | 4 | contact_links: 5 | - name: We are hiring! 6 | url: https://careers.gene.com/ 7 | about: Genentech and Roche are hiring! 8 | - name: Pharmaverse 9 | url: https://pharmaverse.org/ 10 | about: Related projects @ Pharmaverse.org 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: ✨ Feature Request 3 | description: Request or propose a new feature 4 | title: "[Feature Request]: <title>" 5 | labels: ["enhancement"] 6 | body: 7 | - type: textarea 8 | attributes: 9 | label: Feature description 10 | validations: 11 | required: true 12 | - type: checkboxes 13 | id: code-of-conduct 14 | attributes: 15 | label: Code of Conduct 16 | description: By submitting this issue, you agree to follow our [Code of Conduct.](https://insightsengineering.github.io/teal/latest-tag/CODE_OF_CONDUCT.html) 17 | options: 18 | - label: I agree to follow this project's Code of Conduct. 19 | required: true 20 | - type: checkboxes 21 | id: contributor-guidelines 22 | attributes: 23 | label: Contribution Guidelines 24 | description: By submitting this issue, you agree to follow our [Contribution Guidelines.](https://insightsengineering.github.io/teal/latest-tag/CONTRIBUTING.html) 25 | options: 26 | - label: I agree to follow this project's Contribution Guidelines. 27 | required: true 28 | - type: checkboxes 29 | id: security-policy 30 | attributes: 31 | label: Security Policy 32 | description: By submitting this issue, you agree to follow our [Security Policy.](https://github.com/insightsengineering/teal/security/policy) 33 | options: 34 | - label: I agree to follow this project's Security Policy. 35 | required: true 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: ❓ Question 3 | description: Question about usage or documentation 4 | title: "[Question]: <title>" 5 | labels: ["question"] 6 | body: 7 | - type: textarea 8 | attributes: 9 | label: What is your question? 10 | validations: 11 | required: true 12 | - type: checkboxes 13 | id: code-of-conduct 14 | attributes: 15 | label: Code of Conduct 16 | description: By submitting this issue, you agree to follow our [Code of Conduct.](https://insightsengineering.github.io/teal/latest-tag/CODE_OF_CONDUCT.html) 17 | options: 18 | - label: I agree to follow this project's Code of Conduct. 19 | required: true 20 | - type: checkboxes 21 | id: contributor-guidelines 22 | attributes: 23 | label: Contribution Guidelines 24 | description: By submitting this issue, you agree to follow our [Contribution Guidelines.](https://insightsengineering.github.io/teal/latest-tag/CONTRIBUTING.html) 25 | options: 26 | - label: I agree to follow this project's Contribution Guidelines. 27 | required: true 28 | - type: checkboxes 29 | id: security-policy 30 | attributes: 31 | label: Security Policy 32 | description: By submitting this issue, you agree to follow our [Security Policy.](https://github.com/insightsengineering/teal/security/policy) 33 | options: 34 | - label: I agree to follow this project's Security Policy. 35 | required: true 36 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Pull Request 2 | 3 | <!--- Replace `#nnn` with your issue link for reference. --> 4 | 5 | Fixes #nnn 6 | -------------------------------------------------------------------------------- /.github/workflows/cla.yaml: -------------------------------------------------------------------------------- 1 | name: CLA 🔏 2 | 3 | on: 4 | issue_comment: 5 | types: 6 | - created 7 | # For PRs that originate from forks 8 | pull_request_target: 9 | types: 10 | - opened 11 | - closed 12 | - synchronize 13 | 14 | jobs: 15 | CLA: 16 | name: CLA 📝 17 | uses: insightsengineering/.github/.github/workflows/cla.yaml@main 18 | secrets: inherit 19 | -------------------------------------------------------------------------------- /.github/workflows/docs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Docs 📚 3 | 4 | on: 5 | push: 6 | branches: 7 | - main 8 | paths: 9 | - "inst/templates/**" 10 | - "_pkgdown.*" 11 | - DESCRIPTION 12 | - "**.md" 13 | - "**.Rmd" 14 | - "man/**" 15 | - "LICENSE.*" 16 | - NAMESPACE 17 | pull_request: 18 | types: 19 | - opened 20 | - synchronize 21 | - reopened 22 | - ready_for_review 23 | branches: 24 | - main 25 | paths: 26 | - "inst/templates/**" 27 | - "_pkgdown.*" 28 | - DESCRIPTION 29 | - "**.md" 30 | - "**.Rmd" 31 | - "man/**" 32 | - "LICENSE.*" 33 | - NAMESPACE 34 | workflow_dispatch: 35 | 36 | jobs: 37 | docs: 38 | name: Pkgdown Docs 📚 39 | uses: insightsengineering/r.pkg.template/.github/workflows/pkgdown.yaml@main 40 | secrets: 41 | REPO_GITHUB_TOKEN: ${{ secrets.REPO_GITHUB_TOKEN }} 42 | with: 43 | default-landing-page: latest-tag 44 | additional-unit-test-report-directories: unit-test-report-non-cran 45 | deps-installation-method: setup-r-dependencies 46 | -------------------------------------------------------------------------------- /.github/workflows/post-release.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Post release ✨ 3 | 4 | on: 5 | release: 6 | types: ["released"] 7 | 8 | jobs: 9 | vbump: 10 | name: Version Bump 🤜🤛 11 | uses: insightsengineering/r.pkg.template/.github/workflows/version-bump.yaml@main 12 | secrets: 13 | REPO_GITHUB_TOKEN: ${{ secrets.REPO_GITHUB_TOKEN }} 14 | with: 15 | vbump-after-release: true 16 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Release 🎈 3 | 4 | on: 5 | push: 6 | tags: 7 | - "v*" 8 | workflow_dispatch: 9 | 10 | jobs: 11 | docs: 12 | name: Pkgdown Docs 📚 13 | needs: release 14 | uses: insightsengineering/r.pkg.template/.github/workflows/pkgdown.yaml@main 15 | secrets: 16 | REPO_GITHUB_TOKEN: ${{ secrets.REPO_GITHUB_TOKEN }} 17 | with: 18 | default-landing-page: latest-tag 19 | deps-installation-method: setup-r-dependencies 20 | validation: 21 | name: R Package Validation report 📃 22 | needs: release 23 | uses: insightsengineering/r.pkg.template/.github/workflows/validation.yaml@main 24 | secrets: 25 | REPO_GITHUB_TOKEN: ${{ secrets.REPO_GITHUB_TOKEN }} 26 | with: 27 | deps-installation-method: setup-r-dependencies 28 | release: 29 | name: Create release 🎉 30 | uses: insightsengineering/r.pkg.template/.github/workflows/release.yaml@main 31 | secrets: 32 | REPO_GITHUB_TOKEN: ${{ secrets.REPO_GITHUB_TOKEN }} 33 | build: 34 | name: Build package and reports 🎁 35 | needs: [release, docs] 36 | uses: insightsengineering/r.pkg.template/.github/workflows/build-check-install.yaml@main 37 | secrets: 38 | REPO_GITHUB_TOKEN: ${{ secrets.REPO_GITHUB_TOKEN }} 39 | with: 40 | additional-env-vars: | 41 | _R_CHECK_CRAN_INCOMING_REMOTE_=false 42 | additional-r-cmd-check-params: --as-cran 43 | enforce-note-blocklist: true 44 | note-blocklist: | 45 | checking dependencies in R code .* NOTE 46 | checking R code for possible problems .* NOTE 47 | checking examples .* NOTE 48 | checking Rd line widths .* NOTE 49 | checking top-level files .* NOTE 50 | unit-test-report-brand: >- 51 | https://raw.githubusercontent.com/insightsengineering/hex-stickers/main/thumbs/teal.png 52 | deps-installation-method: setup-r-dependencies 53 | coverage: 54 | name: Coverage 📔 55 | needs: [release, docs] 56 | uses: insightsengineering/r.pkg.template/.github/workflows/test-coverage.yaml@main 57 | secrets: 58 | REPO_GITHUB_TOKEN: ${{ secrets.REPO_GITHUB_TOKEN }} 59 | with: 60 | additional-env-vars: | 61 | NOT_CRAN=true 62 | deps-installation-method: setup-r-dependencies 63 | wasm: 64 | name: Build WASM packages 🧑‍🏭 65 | needs: release 66 | uses: insightsengineering/r.pkg.template/.github/workflows/wasm.yaml@main 67 | -------------------------------------------------------------------------------- /.github/workflows/scheduled.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Scheduled 🕰️ 3 | 4 | on: 5 | schedule: 6 | - cron: '45 3 * * 0' 7 | workflow_dispatch: 8 | inputs: 9 | chosen-workflow: 10 | description: | 11 | Select which workflow you'd like to run 12 | required: true 13 | type: choice 14 | default: rhub 15 | options: 16 | - rhub 17 | - dependency-test 18 | - branch-cleanup 19 | - revdepcheck 20 | 21 | jobs: 22 | dependency-test: 23 | if: > 24 | github.event_name == 'schedule' || ( 25 | github.event_name == 'workflow_dispatch' && 26 | inputs.chosen-workflow == 'dependency-test' 27 | ) 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | test-strategy: ["min_cohort", "min_isolated", "release", "max"] 32 | uses: insightsengineering/r.pkg.template/.github/workflows/verdepcheck.yaml@main 33 | name: Dependency Test - ${{ matrix.test-strategy }} 🔢 34 | secrets: 35 | REPO_GITHUB_TOKEN: ${{ secrets.REPO_GITHUB_TOKEN }} 36 | GCHAT_WEBHOOK: ${{ secrets.GCHAT_WEBHOOK }} 37 | with: 38 | strategy: ${{ matrix.test-strategy }} 39 | additional-env-vars: | 40 | PKG_SYSREQS_DRY_RUN=true 41 | extra-deps: | 42 | matrixStats (>= 1.5.0) 43 | branch-cleanup: 44 | if: > 45 | github.event_name == 'schedule' || ( 46 | github.event_name == 'workflow_dispatch' && 47 | inputs.chosen-workflow == 'branch-cleanup' 48 | ) 49 | name: Branch Cleanup 🧹 50 | uses: insightsengineering/r.pkg.template/.github/workflows/branch-cleanup.yaml@main 51 | secrets: 52 | REPO_GITHUB_TOKEN: ${{ secrets.REPO_GITHUB_TOKEN }} 53 | revdepcheck: 54 | if: > 55 | github.event_name == 'schedule' || ( 56 | github.event_name == 'workflow_dispatch' && 57 | inputs.chosen-workflow == 'revdepcheck' 58 | ) 59 | name: revdepcheck ↩️ 60 | uses: insightsengineering/r.pkg.template/.github/workflows/revdepcheck.yaml@main 61 | 62 | rhub: 63 | if: > 64 | github.event_name == 'schedule' || ( 65 | github.event_name == 'workflow_dispatch' && 66 | inputs.chosen-workflow == 'rhub' 67 | ) 68 | name: R-hub 🌐 69 | uses: insightsengineering/r.pkg.template/.github/workflows/rhub.yaml@main 70 | 71 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.Rcheck 2 | *.html 3 | *.rprof 4 | *.sas.txt 5 | *~ 6 | .DS_Store 7 | .RData 8 | .Rhistory 9 | .Rproj.user 10 | .Ruserdata 11 | .httr-oauth 12 | .project 13 | .settings/** 14 | /.project 15 | Meta 16 | coverage.* 17 | devel/* 18 | doc 19 | docs 20 | inst/outputs/* 21 | logs 22 | packrat/lib*/ 23 | temp 24 | temp_w 25 | templates/ 26 | tmp.* 27 | vignettes/*.R 28 | vignettes/*.html 29 | vignettes/*.md 30 | inst/doc 31 | tests/testthat/_snaps/**/*.new.md 32 | tests/testthat/_snaps/**/*.new.svg 33 | teal_app.lock 34 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | include: 4 | - project: 'nest/automation/gitlab-shared-library' 5 | ref: main 6 | file: R/R_NEST_min.gitlab-ci.yml 7 | -------------------------------------------------------------------------------- /.lintr: -------------------------------------------------------------------------------- 1 | linters: linters_with_defaults( 2 | line_length_linter = line_length_linter(120), 3 | cyclocomp_linter = NULL, 4 | object_usage_linter = NULL 5 | ) 6 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # All available hooks: https://pre-commit.com/hooks.html 3 | # R specific hooks: https://github.com/lorenzwalthert/precommit 4 | default_stages: [pre-commit] 5 | default_language_version: 6 | python: python3 7 | repos: 8 | - repo: https://github.com/lorenzwalthert/precommit 9 | rev: v0.4.3.9009 10 | hooks: 11 | - id: style-files 12 | name: Style code with `styler` 13 | args: 14 | [--style_pkg=styler, --style_fun=tidyverse_style, --cache-root=styler] 15 | - id: roxygenize 16 | name: Regenerate package documentation 17 | additional_dependencies: 18 | - davidgohel/flextable # Error: package 'flextable' is not available 19 | - davidgohel/gdtools # for flextable 20 | - mirai 21 | - checkmate 22 | - cli 23 | - htmltools 24 | - jsonlite 25 | - lifecycle 26 | - logger 27 | - magrittr 28 | - methods 29 | - renv 30 | - rlang 31 | - shiny 32 | - shinyjs 33 | - stats 34 | - insightsengineering/roxy.shinylive 35 | - insightsengineering/teal.code 36 | - insightsengineering/teal.data 37 | - insightsengineering/teal.logger 38 | - insightsengineering/teal.reporter 39 | - insightsengineering/teal.slice 40 | - insightsengineering/teal.widgets 41 | - utils 42 | - shinytest2 # Necessary for documentation 43 | - shinyvalidate # Necessary for documentation 44 | - rvest # Necessary for documentation 45 | - id: spell-check 46 | name: Check spelling with `spelling` 47 | exclude: > 48 | (?x)^( 49 | .*\.[rR]| 50 | .*\.css| 51 | .*\.jpg| 52 | .*\.js| 53 | .*\.png| 54 | .*\.py| 55 | .*\.RData| 56 | .*\.Rds| 57 | .*\.rds| 58 | .*\.Rproj| 59 | .*\.sh| 60 | .*\.svg| 61 | .*\.xml| 62 | (.*/|)\_pkgdown.y[a]?ml| 63 | (.*/|)\.covrignore| 64 | (.*/|)\.gitignore| 65 | (.*/|)\.gitlab-ci\.y[a]?ml| 66 | (.*/|)\.lintr| 67 | (.*/|)\.pre-commit-.*| 68 | (.*/|)\.Rbuildignore| 69 | (.*/|)\.Renviron| 70 | (.*/|)\.Rprofile| 71 | (.*/|)CODEOWNERS| 72 | (.*/|)DESCRIPTION| 73 | (.*/|)LICENSE| 74 | (.*/|)NAMESPACE| 75 | (.*/|)staged_dependencies\.y[a]?ml| 76 | (.*/|)WORDLIST| 77 | \.github/.*\.y[a]?ml| 78 | data/.* 79 | )$ 80 | - id: no-browser-statement 81 | name: Check for browser() statement 82 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022 F. Hoffmann-La Roche AG 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method(c,teal_slices) 4 | S3method(format,teal_module) 5 | S3method(format,teal_modules) 6 | S3method(join_keys,tdata) 7 | S3method(print,teal_module) 8 | S3method(print,teal_modules) 9 | S3method(srv_teal_module,default) 10 | S3method(srv_teal_module,teal_module) 11 | S3method(srv_teal_module,teal_modules) 12 | S3method(ui_teal_module,default) 13 | S3method(ui_teal_module,teal_module) 14 | S3method(ui_teal_module,teal_modules) 15 | S3method(within,teal_data_module) 16 | export(TealReportCard) 17 | export(add_landing_modal) 18 | export(as.teal_slices) 19 | export(as_tdata) 20 | export(build_app_title) 21 | export(example_module) 22 | export(get_code_tdata) 23 | export(get_metadata) 24 | export(init) 25 | export(landing_popup_module) 26 | export(make_teal_transform_server) 27 | export(modify_footer) 28 | export(modify_header) 29 | export(modify_title) 30 | export(module) 31 | export(modules) 32 | export(new_tdata) 33 | export(report_card_template) 34 | export(reporter_previewer_module) 35 | export(show_rcode_modal) 36 | export(srv_session_info) 37 | export(srv_teal) 38 | export(srv_teal_with_splash) 39 | export(srv_transform_teal_data) 40 | export(tdata2env) 41 | export(teal_data_module) 42 | export(teal_slices) 43 | export(teal_transform_module) 44 | export(ui_session_info) 45 | export(ui_teal) 46 | export(ui_teal_with_splash) 47 | export(ui_transform_teal_data) 48 | export(validate_has_data) 49 | export(validate_has_elements) 50 | export(validate_has_variable) 51 | export(validate_in) 52 | export(validate_inputs) 53 | export(validate_n_levels) 54 | export(validate_no_intersection) 55 | export(validate_one_row_per_id) 56 | import(shiny) 57 | import(teal.data) 58 | import(teal.slice) 59 | importFrom(methods,new) 60 | importFrom(methods,setMethod) 61 | importFrom(shiny,reactiveVal) 62 | importFrom(shiny,reactiveValues) 63 | importFrom(stats,setNames) 64 | importMethodsFrom(teal.code,eval_code) 65 | -------------------------------------------------------------------------------- /R/checkmate.R: -------------------------------------------------------------------------------- 1 | #' Check that argument is reactive. 2 | #' 3 | #' @inherit checkmate::check_class params return 4 | #' 5 | #' @keywords internal 6 | check_reactive <- function(x, null.ok = FALSE) { # nolint: object_name_linter. 7 | if (!isTRUE(checkmate::test_class(x, classes = "reactive", null.ok = null.ok))) { 8 | cl <- class(x) 9 | return(sprintf( 10 | "Must be a reactive (i.e. inherit from 'reactive' class) but has class%s '%s'", 11 | if (length(cl) > 1L) "es" else "", 12 | paste0(cl, collapse = "','") 13 | )) 14 | } 15 | return(TRUE) 16 | } 17 | #' @rdname check_reactive 18 | test_reactive <- function(x, null.ok = FALSE) { # nolint: object_name_linter. 19 | isTRUE(check_reactive(x, null.ok = null.ok)) 20 | } 21 | #' @rdname check_reactive 22 | assert_reactive <- checkmate::makeAssertionFunction(check_reactive) 23 | 24 | #' Capture error and decorate error message. 25 | #' 26 | #' @param x object to evaluate 27 | #' @param pre (`character(1)`) A string to prepend to error message 28 | #' @param post (`character(1)`) A string to append to error message 29 | #' 30 | #' @return `x` if no error, otherwise throws error with decorated message 31 | #' 32 | #' @keywords internal 33 | decorate_err_msg <- function(x, pre = character(0), post = character(0)) { 34 | tryCatch( 35 | x, 36 | error = function(e) { 37 | stop( 38 | "\n", 39 | pre, 40 | "\n", 41 | e$message, 42 | "\n", 43 | post, 44 | call. = FALSE 45 | ) 46 | } 47 | ) 48 | x 49 | } 50 | -------------------------------------------------------------------------------- /R/include_css_js.R: -------------------------------------------------------------------------------- 1 | #' Include `CSS` files from `/inst/css/` package directory to application header 2 | #' 3 | #' `system.file` should not be used to access files in other packages, it does 4 | #' not work with `devtools`. Therefore, we redefine this method in each package 5 | #' as needed. Thus, we do not export this method. 6 | #' 7 | #' @param pattern (`character`) pattern of files to be included 8 | #' 9 | #' @return HTML code that includes `CSS` files. 10 | #' @keywords internal 11 | include_css_files <- function(pattern = "*") { 12 | css_files <- list.files( 13 | system.file("css", package = "teal", mustWork = TRUE), 14 | pattern = pattern, full.names = TRUE 15 | ) 16 | 17 | singleton( 18 | tags$head(lapply(css_files, includeCSS)) 19 | ) 20 | } 21 | 22 | #' Include `JS` files from `/inst/js/` package directory to application header 23 | #' 24 | #' `system.file` should not be used to access files in other packages, it does 25 | #' not work with `devtools`. Therefore, we redefine this method in each package 26 | #' as needed. Thus, we do not export this method 27 | #' 28 | #' @param pattern (`character`) pattern of files to be included, passed to `system.file` 29 | #' @param except (`character`) vector of basename filenames to be excluded 30 | #' 31 | #' @return HTML code that includes `JS` files. 32 | #' @keywords internal 33 | include_js_files <- function(pattern = NULL, except = NULL) { 34 | checkmate::assert_character(except, min.len = 1, any.missing = FALSE, null.ok = TRUE) 35 | js_files <- list.files(system.file("js", package = "teal", mustWork = TRUE), pattern = pattern, full.names = TRUE) 36 | js_files <- js_files[!(basename(js_files) %in% except)] # no-op if except is NULL 37 | 38 | singleton(lapply(js_files, includeScript)) 39 | } 40 | 41 | #' Run `JS` file from `/inst/js/` package directory 42 | #' 43 | #' This is triggered from the server to execute on the client 44 | #' rather than triggered directly on the client. 45 | #' Unlike `include_js_files` which includes `JavaScript` functions, 46 | #' the `run_js` actually executes `JavaScript` functions. 47 | #' 48 | #' `system.file` should not be used to access files in other packages, it does 49 | #' not work with `devtools`. Therefore, we redefine this method in each package 50 | #' as needed. Thus, we do not export this method. 51 | #' 52 | #' @param files (`character`) vector of filenames. 53 | #' 54 | #' @return `NULL`, invisibly. 55 | #' @keywords internal 56 | run_js_files <- function(files) { 57 | checkmate::assert_character(files, min.len = 1, any.missing = FALSE) 58 | lapply(files, function(file) { 59 | shinyjs::runjs(paste0(readLines(system.file("js", file, package = "teal", mustWork = TRUE)), collapse = "\n")) 60 | }) 61 | invisible(NULL) 62 | } 63 | 64 | #' Code to include `teal` `CSS` and `JavaScript` files 65 | #' 66 | #' This is useful when you want to use the same `JavaScript` and `CSS` files that are 67 | #' used with the `teal` application. 68 | #' This is also useful for running standalone modules in `teal` with the correct 69 | #' styles. 70 | #' Also initializes `shinyjs` so you can use it. 71 | #' 72 | #' Simply add `include_teal_css_js()` as one of the UI elements. 73 | #' @return A `shiny.tag.list`. 74 | #' @keywords internal 75 | include_teal_css_js <- function() { 76 | tagList( 77 | shinyjs::useShinyjs(), 78 | include_css_files(), 79 | # init.js is executed from the server 80 | include_js_files(except = "init.js"), 81 | shinyjs::hidden(icon("fas fa-gear")), # add hidden icon to load font-awesome css for icons 82 | ) 83 | } 84 | -------------------------------------------------------------------------------- /R/landing_popup_module.R: -------------------------------------------------------------------------------- 1 | #' Landing popup module 2 | #' 3 | #' @description `r lifecycle::badge("deprecated")` Creates a landing welcome popup for `teal` applications. 4 | #' 5 | #' This module is used to display a popup dialog when the application starts. 6 | #' The dialog blocks access to the application and must be closed with a button before the application can be viewed. 7 | #' This function is deprecated, please use `add_landing_modal()` on the teal app object instead. 8 | #' 9 | #' @param label (`character(1)`) Label of the module. 10 | #' @param title (`character(1)`) Text to be displayed as popup title. 11 | #' @param content (`character(1)`, `shiny.tag` or `shiny.tag.list`) with the content of the popup. 12 | #' Passed to `...` of `shiny::modalDialog`. See examples. 13 | #' @param buttons (`shiny.tag` or `shiny.tag.list`) Typically a `modalButton` or `actionButton`. See examples. 14 | #' 15 | #' @return A `teal_module` (extended with `teal_landing_module` class) to be used in `teal` applications. 16 | #' 17 | #' @export 18 | landing_popup_module <- function(label = "Landing Popup", 19 | title = NULL, 20 | content = NULL, 21 | buttons = modalButton("Accept")) { 22 | lifecycle::deprecate_soft( 23 | when = "0.16.0", 24 | what = "landing_popup_module()", 25 | details = paste( 26 | "landing_popup_module() is deprecated.", 27 | "Use add_landing_modal() on the teal app object instead." 28 | ) 29 | ) 30 | checkmate::assert_string(label) 31 | checkmate::assert_string(title, null.ok = TRUE) 32 | checkmate::assert_multi_class( 33 | content, 34 | classes = c("character", "shiny.tag", "shiny.tag.list", "html"), null.ok = TRUE 35 | ) 36 | checkmate::assert_multi_class(buttons, classes = c("shiny.tag", "shiny.tag.list")) 37 | 38 | message("Initializing landing_popup_module") 39 | 40 | module <- module( 41 | label = label, 42 | datanames = NULL, 43 | server = function(id) { 44 | moduleServer(id, function(input, output, session) { 45 | showModal( 46 | modalDialog( 47 | id = "landingpopup", 48 | title = title, 49 | content, 50 | footer = buttons 51 | ) 52 | ) 53 | }) 54 | } 55 | ) 56 | class(module) <- c("teal_module_landing", class(module)) 57 | module 58 | } 59 | -------------------------------------------------------------------------------- /R/module_session_info.R: -------------------------------------------------------------------------------- 1 | #' `teal` user session info module 2 | #' 3 | #' Module to display the user session info popup and to download a lockfile. Module is included 4 | #' when running [init()] but skipped when using [`module_teal`]. Please be aware that session info 5 | #' contains R session information, so multiple module's calls will share the same information. 6 | #' 7 | #' @rdname module_session_info 8 | #' @name module_session_info 9 | #' 10 | #' @inheritParams module_teal 11 | #' 12 | #' @examplesShinylive 13 | #' library(teal) 14 | #' interactive <- function() TRUE 15 | #' {{ next_example }} 16 | #' @examples 17 | #' ui <- fluidPage( 18 | #' ui_session_info("session_info") 19 | #' ) 20 | #' 21 | #' server <- function(input, output, session) { 22 | #' srv_session_info("session_info") 23 | #' } 24 | #' 25 | #' if (interactive()) { 26 | #' shinyApp(ui, server) 27 | #' } 28 | #' 29 | #' @return `NULL` invisibly 30 | NULL 31 | 32 | #' @rdname module_session_info 33 | #' @export 34 | ui_session_info <- function(id) { 35 | ns <- NS(id) 36 | tags$div( 37 | teal.widgets::verbatim_popup_ui(ns("sessionInfo"), "Session Info", type = "link"), 38 | br(), 39 | ui_teal_lockfile(ns("lockfile")), 40 | textOutput(ns("identifier")) 41 | ) 42 | } 43 | 44 | #' @rdname module_session_info 45 | #' @export 46 | srv_session_info <- function(id) { 47 | moduleServer(id, function(input, output, session) { 48 | srv_teal_lockfile("lockfile") 49 | 50 | output$identifier <- renderText( 51 | paste0("Pid:", Sys.getpid(), " Token:", substr(session$token, 25, 32)) 52 | ) 53 | 54 | teal.widgets::verbatim_popup_srv( 55 | "sessionInfo", 56 | verbatim_content = utils::capture.output(utils::sessionInfo()), 57 | title = "SessionInfo" 58 | ) 59 | }) 60 | } 61 | -------------------------------------------------------------------------------- /R/module_teal_with_splash.R: -------------------------------------------------------------------------------- 1 | #' UI and server modules of `teal` 2 | #' 3 | #' @description `r lifecycle::badge("deprecated")` 4 | #' Please use [`module_teal`] instead. 5 | #' 6 | #' @inheritParams ui_teal 7 | #' @inheritParams srv_teal 8 | #' @inheritParams init 9 | #' 10 | #' @return 11 | #' Returns a `reactive` expression containing a `teal_data` object when data is loaded or `NULL` when it is not. 12 | #' @name module_teal_with_splash 13 | #' 14 | NULL 15 | 16 | #' @export 17 | #' @rdname module_teal_with_splash 18 | ui_teal_with_splash <- function(id, 19 | data, 20 | modules, 21 | title = build_app_title(), 22 | header = tags$p(), 23 | footer = tags$p()) { 24 | lifecycle::deprecate_soft( 25 | when = "0.16.0", 26 | what = "ui_teal_with_splash()", 27 | details = "Please use `?ui_teal` instead" 28 | ) 29 | ns <- shiny::NS(id) 30 | fluidPage( 31 | title = tags$div( 32 | id = ns("teal-app-title"), 33 | tags$head( 34 | tags$title("teal app"), 35 | tags$link( 36 | rel = "icon", 37 | href = .teal_favicon, 38 | sizes = "any" 39 | ) 40 | ) 41 | ), 42 | tags$header(id = ns("teal-header-content")), 43 | ui_teal(id = id, modules = modules), 44 | tags$footer( 45 | id = "teal-footer", 46 | tags$div(id = "teal-footer-content"), 47 | ui_session_info(ns("teal-footer-session_info")) 48 | ) 49 | ) 50 | } 51 | 52 | #' @export 53 | #' @rdname module_teal_with_splash 54 | srv_teal_with_splash <- function(id, data, modules, filter = teal_slices()) { 55 | lifecycle::deprecate_soft( 56 | when = "0.16.0", 57 | what = "srv_teal_with_splash()", 58 | details = "Deprecated, please use `?srv_teal` instead" 59 | ) 60 | srv_teal(id = id, data = data, modules = modules, filter = filter) 61 | srv_session_info("teal-footer-session_info") 62 | } 63 | -------------------------------------------------------------------------------- /R/reporter_previewer_module.R: -------------------------------------------------------------------------------- 1 | #' Create a `teal` module for previewing a report 2 | #' 3 | #' @description `r lifecycle::badge("experimental")` 4 | #' 5 | #' This function wraps [teal.reporter::reporter_previewer_ui()] and 6 | #' [teal.reporter::reporter_previewer_srv()] into a `teal_module` to be 7 | #' used in `teal` applications. 8 | #' 9 | #' If you are creating a `teal` application using [init()] then this 10 | #' module will be added to your application automatically if any of your `teal_modules` 11 | #' support report generation. 12 | #' 13 | #' @inheritParams teal_modules 14 | #' @param server_args (named `list`) 15 | #' Arguments passed to [teal.reporter::reporter_previewer_srv()]. 16 | #' 17 | #' @return 18 | #' `teal_module` (extended with `teal_module_previewer` class) containing the `teal.reporter` previewer functionality. 19 | #' 20 | #' @export 21 | #' 22 | reporter_previewer_module <- function(label = "Report previewer", server_args = list()) { 23 | checkmate::assert_string(label) 24 | checkmate::assert_list(server_args, names = "named") 25 | checkmate::assert_true(all(names(server_args) %in% names(formals(teal.reporter::reporter_previewer_srv)))) 26 | 27 | message("Initializing reporter_previewer_module") 28 | 29 | srv <- function(id, reporter, ...) { 30 | teal.reporter::reporter_previewer_srv(id, reporter, ...) 31 | } 32 | 33 | ui <- function(id, ...) { 34 | teal.reporter::reporter_previewer_ui(id, ...) 35 | } 36 | 37 | module <- module( 38 | label = "temporary label", 39 | server = srv, ui = ui, 40 | server_args = server_args, ui_args = list(), datanames = NULL 41 | ) 42 | # Module is created with a placeholder label and the label is changed later. 43 | # This is to prevent another module being labeled "Report previewer". 44 | class(module) <- c(class(module), "teal_module_previewer") 45 | module$label <- label 46 | attr(module, "teal_bookmarkable") <- TRUE 47 | module 48 | } 49 | -------------------------------------------------------------------------------- /R/show_rcode_modal.R: -------------------------------------------------------------------------------- 1 | #' Show `R` code modal 2 | #' 3 | #' @description `r lifecycle::badge("deprecated")` 4 | #' 5 | #' Use the [shiny::showModal()] function to show the `R` code inside. 6 | #' 7 | #' @param title (`character(1)`) 8 | #' Title of the modal, displayed in the first comment of the `R` code. 9 | #' @param rcode (`character`) 10 | #' vector with `R` code to show inside the modal. 11 | #' @param session (`ShinySession`) optional 12 | #' `shiny` session object, defaults to [shiny::getDefaultReactiveDomain()]. 13 | #' 14 | #' @references [shiny::showModal()] 15 | #' @export 16 | show_rcode_modal <- function(title = NULL, rcode, session = getDefaultReactiveDomain()) { 17 | lifecycle::deprecate_soft( 18 | when = "0.16.0", 19 | what = "show_rcode_modal()", 20 | details = "This function will be removed in the next release." 21 | ) 22 | 23 | rcode <- paste(rcode, collapse = "\n") 24 | 25 | ns <- session$ns 26 | showModal(modalDialog( 27 | tagList( 28 | tags$div( 29 | actionButton(ns("copyRCode"), "Copy to Clipboard", `data-clipboard-target` = paste0("#", ns("r_code"))), 30 | modalButton("Dismiss") 31 | ), 32 | tags$div(tags$pre(id = ns("r_code"), rcode)), 33 | ), 34 | title = title, 35 | footer = tagList( 36 | actionButton(ns("copyRCode"), "Copy to Clipboard", `data-clipboard-target` = paste0("#", ns("r_code"))), 37 | modalButton("Dismiss") 38 | ), 39 | size = "l", 40 | easyClose = TRUE 41 | )) 42 | } 43 | -------------------------------------------------------------------------------- /R/tdata.R: -------------------------------------------------------------------------------- 1 | #' Create a `tdata` object 2 | #' 3 | #' @description `r lifecycle::badge("superseded")` 4 | #' 5 | #' Recent changes in `teal` cause modules to fail because modules expect a `tdata` object 6 | #' to be passed to the `data` argument but instead they receive a `teal_data` object, 7 | #' which is additionally wrapped in a reactive expression in the server functions. 8 | #' In order to easily adapt such modules without a proper refactor, 9 | #' use this function to downgrade the `data` argument. 10 | #' 11 | #' @name tdata 12 | #' @param ... ignored 13 | #' @return nothing 14 | NULL 15 | 16 | #' @rdname tdata 17 | #' @export 18 | new_tdata <- function(...) { 19 | .deprecate_tdata_msg() 20 | } 21 | 22 | #' @rdname tdata 23 | #' @export 24 | tdata2env <- function(...) { 25 | .deprecate_tdata_msg() 26 | } 27 | 28 | #' @rdname tdata 29 | #' @export 30 | get_code_tdata <- function(...) { 31 | .deprecate_tdata_msg() 32 | } 33 | 34 | #' @rdname tdata 35 | #' @export 36 | join_keys.tdata <- function(...) { 37 | .deprecate_tdata_msg() 38 | } 39 | 40 | #' @rdname tdata 41 | #' @export 42 | get_metadata <- function(...) { 43 | .deprecate_tdata_msg() 44 | } 45 | 46 | #' @rdname tdata 47 | #' @export 48 | as_tdata <- function(...) { 49 | .deprecate_tdata_msg() 50 | } 51 | 52 | 53 | .deprecate_tdata_msg <- function() { 54 | lifecycle::deprecate_stop( 55 | when = "0.16.0", 56 | what = "tdata()", 57 | details = paste( 58 | "tdata has been removed in favour of `teal_data`.\n", 59 | "Please follow migration instructions https://github.com/insightsengineering/teal/discussions/987." 60 | ) 61 | ) 62 | } 63 | -------------------------------------------------------------------------------- /R/teal.R: -------------------------------------------------------------------------------- 1 | #' `teal`: Interactive exploration of clinical trials data 2 | #' 3 | #' The `teal` package provides a `shiny` based framework for creating an 4 | #' interactive data analysis environment. 5 | #' 6 | #' To learn mode about the package, visit the [project website](https://insightsengineering.github.io/teal/latest-tag/) 7 | #' or read the [init()] manual page. 8 | #' 9 | #' @keywords internal 10 | "_PACKAGE" 11 | 12 | #' @import shiny teal.data teal.slice 13 | #' @importFrom stats setNames 14 | #' @export 15 | NULL 16 | -------------------------------------------------------------------------------- /R/teal_data_module-eval_code.R: -------------------------------------------------------------------------------- 1 | setOldClass("teal_data_module") 2 | 3 | #' Evaluate code on `teal_data_module` 4 | #' 5 | #' @details 6 | #' `eval_code` evaluates given code in the environment of the `teal_data` object created by the `teal_data_module`. 7 | #' The code is added to the `@code` slot of the `teal_data`. 8 | #' 9 | #' @param object (`teal_data_module`) 10 | #' @inheritParams teal.code::eval_code 11 | #' 12 | #' @return 13 | #' `eval_code` returns a `teal_data_module` object with a delayed evaluation of `code` when the module is run. 14 | #' 15 | #' @examples 16 | #' eval_code(tdm, "dataset1 <- subset(dataset1, Species == 'virginica')") 17 | #' 18 | #' @include teal_data_module.R 19 | #' @name eval_code 20 | #' @rdname teal_data_module 21 | #' @aliases eval_code,teal_data_module,character-method 22 | #' @aliases eval_code,teal_data_module,language-method 23 | #' @aliases eval_code,teal_data_module,expression-method 24 | #' 25 | #' @importFrom methods setMethod 26 | #' @importMethodsFrom teal.code eval_code 27 | #' 28 | setMethod("eval_code", signature = c("teal_data_module", "character"), function(object, code) { 29 | teal_data_module( 30 | ui = function(id) { 31 | ns <- NS(id) 32 | object$ui(ns("mutate_inner")) 33 | }, 34 | server = function(id) { 35 | moduleServer(id, function(input, output, session) { 36 | data <- object$server("mutate_inner") 37 | td <- eventReactive(data(), 38 | { 39 | if (inherits(data(), c("teal_data", "qenv.error"))) { 40 | eval_code(data(), code) 41 | } else { 42 | data() 43 | } 44 | }, 45 | ignoreNULL = FALSE 46 | ) 47 | td 48 | }) 49 | } 50 | ) 51 | }) 52 | 53 | setMethod("eval_code", signature = c("teal_data_module", "language"), function(object, code) { 54 | eval_code(object, code = paste(lang2calls(code), collapse = "\n")) 55 | }) 56 | 57 | setMethod("eval_code", signature = c("teal_data_module", "expression"), function(object, code) { 58 | eval_code(object, code = paste(lang2calls(code), collapse = "\n")) 59 | }) 60 | -------------------------------------------------------------------------------- /R/teal_data_module-within.R: -------------------------------------------------------------------------------- 1 | #' Evaluate expression on `teal_data_module` 2 | #' 3 | #' @details 4 | #' `within` is a convenience function for evaluating inline code inside the environment of a `teal_data_module`. 5 | #' It accepts only inline expressions (both simple and compound) and allows for injecting values into `expr` through 6 | #' the `...` argument: as `name:value` pairs are passed to `...`, `name` in `expr` will be replaced with `value.` 7 | #' 8 | #' @param data (`teal_data_module`) object 9 | #' @param expr (`expression`) to evaluate. Must be inline code. See [within()] 10 | #' @param ... See `Details`. 11 | #' 12 | #' @return 13 | #' `within` returns a `teal_data_module` object with a delayed evaluation of `expr` when the module is run. 14 | #' 15 | #' @examples 16 | #' within(tdm, dataset1 <- subset(dataset1, Species == "virginica")) 17 | #' 18 | #' # use additional parameter for expression value substitution. 19 | #' valid_species <- "versicolor" 20 | #' within(tdm, dataset1 <- subset(dataset1, Species %in% species), species = valid_species) 21 | #' @include teal_data_module.R 22 | #' @name within 23 | #' @rdname teal_data_module 24 | #' 25 | #' @export 26 | #' 27 | within.teal_data_module <- function(data, expr, ...) { 28 | expr <- substitute(expr) 29 | extras <- list(...) 30 | 31 | # Add braces for consistency. 32 | if (!identical(as.list(expr)[[1L]], as.symbol("{"))) { 33 | expr <- call("{", expr) 34 | } 35 | 36 | calls <- as.list(expr)[-1] 37 | 38 | # Inject extra values into expressions. 39 | calls <- lapply(calls, function(x) do.call(substitute, list(x, env = extras))) 40 | 41 | eval_code(object = data, code = as.expression(calls)) 42 | } 43 | -------------------------------------------------------------------------------- /R/teal_data_module.R: -------------------------------------------------------------------------------- 1 | #' Data module for `teal` applications 2 | #' 3 | #' @description 4 | #' `r lifecycle::badge("experimental")` 5 | #' 6 | #' Create a `teal_data_module` object and evaluate code on it with history tracking. 7 | #' 8 | #' @details 9 | #' `teal_data_module` creates a `shiny` module to interactively supply or modify data in a `teal` application. 10 | #' The module allows for running any code (creation _and_ some modification) after the app starts or reloads. 11 | #' The body of the server function will be run in the app rather than in the global environment. 12 | #' This means it will be run every time the app starts, so use sparingly. 13 | #' 14 | #' Pass this module instead of a `teal_data` object in a call to [init()]. 15 | #' Note that the server function must always return a `teal_data` object wrapped in a reactive expression. 16 | #' 17 | #' See vignette `vignette("data-as-shiny-module", package = "teal")` for more details. 18 | #' 19 | #' @param ui (`function(id)`) 20 | #' `shiny` module UI function; must only take `id` argument 21 | #' @param server (`function(id)`) 22 | #' `shiny` module server function; must only take `id` argument; 23 | #' must return reactive expression containing `teal_data` object 24 | #' @param label (`character(1)`) Label of the module. 25 | #' @param once (`logical(1)`) 26 | #' If `TRUE`, the data module will be shown only once and will disappear after successful data loading. 27 | #' App user will no longer be able to interact with this module anymore. 28 | #' If `FALSE`, the data module can be reused multiple times. 29 | #' App user will be able to interact and change the data output from the module multiple times. 30 | #' 31 | #' @return 32 | #' `teal_data_module` returns a list of class `teal_data_module` containing two elements, `ui` and 33 | #' `server` provided via arguments. 34 | #' 35 | #' @examples 36 | #' tdm <- teal_data_module( 37 | #' ui = function(id) { 38 | #' ns <- NS(id) 39 | #' actionButton(ns("submit"), label = "Load data") 40 | #' }, 41 | #' server = function(id) { 42 | #' moduleServer(id, function(input, output, session) { 43 | #' eventReactive(input$submit, { 44 | #' data <- within( 45 | #' teal_data(), 46 | #' { 47 | #' dataset1 <- iris 48 | #' dataset2 <- mtcars 49 | #' } 50 | #' ) 51 | #' 52 | #' data 53 | #' }) 54 | #' }) 55 | #' } 56 | #' ) 57 | #' 58 | #' @name teal_data_module 59 | #' @seealso [`teal.data::teal_data-class`], [teal.code::qenv()] 60 | #' 61 | #' @export 62 | teal_data_module <- function(ui, server, label = "data module", once = TRUE) { 63 | checkmate::assert_function(ui, args = "id", nargs = 1) 64 | checkmate::assert_function(server, args = "id", nargs = 1) 65 | checkmate::assert_string(label) 66 | checkmate::assert_flag(once) 67 | structure( 68 | list( 69 | ui = ui, 70 | server = function(id) { 71 | data_out <- server(id) 72 | decorate_err_msg( 73 | assert_reactive(data_out), 74 | pre = sprintf("From: 'teal_data_module()':\nA 'teal_data_module' with \"%s\" label:", label), 75 | post = "Please make sure that this module returns a 'reactive` object containing 'teal_data' class of object." # nolint: line_length_linter. 76 | ) 77 | } 78 | ), 79 | label = label, 80 | class = "teal_data_module", 81 | once = once 82 | ) 83 | } 84 | -------------------------------------------------------------------------------- /R/teal_data_utils.R: -------------------------------------------------------------------------------- 1 | #' `teal_data` utils 2 | #' 3 | #' In `teal` we need to recreate the `teal_data` object due to two operations: 4 | #' - we need to append filter-data code and objects which have been evaluated in `FilteredData` and 5 | #' we want to avoid double-evaluation. 6 | #' - we need to subset `teal_data` to `datanames` used by the module, to shorten obtainable R-code 7 | #' 8 | #' Due to above recreation of `teal_data` object can't be done simply by using public 9 | #' `teal.code` and `teal.data` methods. 10 | #' 11 | #' @param data (`teal_data`) 12 | #' @param code (`character`) code to append to the object's code slot. 13 | #' @param objects (`list`) objects to append to object's environment. 14 | #' @return modified `teal_data` 15 | #' @keywords internal 16 | #' @name teal_data_utilities 17 | NULL 18 | 19 | #' @rdname teal_data_utilities 20 | .append_evaluated_code <- function(data, code) { 21 | checkmate::assert_class(data, "teal_data") 22 | data@code <- c(data@code, code2list(code)) 23 | methods::validObject(data) 24 | data 25 | } 26 | 27 | #' @rdname teal_data_utilities 28 | .append_modified_data <- function(data, objects) { 29 | checkmate::assert_class(data, "teal_data") 30 | checkmate::assert_class(objects, "list") 31 | new_env <- list2env(objects, parent = .GlobalEnv) 32 | rlang::env_coalesce(new_env, as.environment(data)) 33 | data@.xData <- new_env 34 | data 35 | } 36 | -------------------------------------------------------------------------------- /R/teal_slices-store.R: -------------------------------------------------------------------------------- 1 | #' Store and restore `teal_slices` object 2 | #' 3 | #' Functions that write a `teal_slices` object to a file in the `JSON` format, 4 | #' and also restore the object from disk. 5 | #' 6 | #' Date and date time objects are stored in the following formats: 7 | #' 8 | #' - `Date` class is converted to the `"ISO8601"` standard (`YYYY-MM-DD`). 9 | #' - `POSIX*t` classes are converted to character by using 10 | #' `format.POSIX*t(usetz = TRUE, tz = "UTC")` (`YYYY-MM-DD HH:MM:SS UTC`, where 11 | #' `UTC` is the `Coordinated Universal Time` timezone short-code). 12 | #' 13 | #' This format is assumed during `slices_restore`. All `POSIX*t` objects in 14 | #' `selected` or `choices` fields of `teal_slice` objects are always printed in 15 | #' `UTC` timezone as well. 16 | #' 17 | #' @param tss (`teal_slices`) object to be stored. 18 | #' @param file (`character(1)`) file path where `teal_slices` object will be 19 | #' saved and restored. The file extension should be `".json"`. 20 | #' 21 | #' @return `slices_store` returns `NULL`, invisibly. 22 | #' 23 | #' @seealso [teal_slices()] 24 | #' 25 | #' @keywords internal 26 | #' 27 | slices_store <- function(tss, file) { 28 | checkmate::assert_class(tss, "teal_slices") 29 | checkmate::assert_path_for_output(file, overwrite = TRUE, extension = "json") 30 | 31 | cat(format(tss, trim_lines = FALSE), "\n", file = file) 32 | } 33 | 34 | #' @rdname slices_store 35 | #' @return `slices_restore` returns a `teal_slices` object restored from the file. 36 | #' @keywords internal 37 | slices_restore <- function(file) { 38 | checkmate::assert_file_exists(file, access = "r", extension = "json") 39 | 40 | tss_json <- jsonlite::fromJSON(file, simplifyDataFrame = FALSE) 41 | tss_json$slices <- 42 | lapply(tss_json$slices, function(slice) { 43 | for (field in c("selected", "choices")) { 44 | if (!is.null(slice[[field]])) { 45 | if (length(slice[[field]]) > 0) { 46 | date_partial_regex <- "^[0-9]{4}-[0-9]{2}-[0-9]{2}" 47 | time_stamp_regex <- paste0(date_partial_regex, "\\s[0-9]{2}:[0-9]{2}:[0-9]{2}\\sUTC$") 48 | 49 | slice[[field]] <- 50 | if (all(grepl(paste0(date_partial_regex, "$"), slice[[field]]))) { 51 | as.Date(slice[[field]]) 52 | } else if (all(grepl(time_stamp_regex, slice[[field]]))) { 53 | as.POSIXct(slice[[field]], tz = "UTC") 54 | } else { 55 | slice[[field]] 56 | } 57 | } else { 58 | slice[[field]] <- character(0) 59 | } 60 | } 61 | } 62 | slice 63 | }) 64 | 65 | tss_elements <- lapply(tss_json$slices, as.teal_slice) 66 | 67 | do.call(teal_slices, c(tss_elements, tss_json$attributes)) 68 | } 69 | -------------------------------------------------------------------------------- /R/zzz.R: -------------------------------------------------------------------------------- 1 | .onLoad <- function(libname, pkgname) { 2 | # adapted from https://github.com/r-lib/devtools/blob/master/R/zzz.R 3 | 4 | teal_default_options <- list( 5 | teal.show_js_log = FALSE, 6 | teal.lockfile.mode = "auto", 7 | shiny.sanitize.errors = FALSE 8 | ) 9 | 10 | op <- options() 11 | toset <- !(names(teal_default_options) %in% names(op)) 12 | if (any(toset)) options(teal_default_options[toset]) 13 | 14 | # Set up the teal logger instance 15 | teal.logger::register_logger("teal") 16 | teal.logger::register_handlers("teal") 17 | 18 | invisible() 19 | } 20 | 21 | .onAttach <- function(libname, pkgname) { 22 | packageStartupMessage( 23 | "\nYou are using teal version ", 24 | # `system.file` uses the `shim` of `system.file` by `teal` 25 | # we avoid `desc` dependency here to get the version 26 | read.dcf(system.file("DESCRIPTION", package = "teal"))[, "Version"] 27 | ) 28 | } 29 | 30 | # This one is here because setdiff_teal_slice should not be exported from teal.slice. 31 | setdiff_teal_slices <- getFromNamespace("setdiff_teal_slices", "teal.slice") 32 | # This one is here because it is needed by c.teal_slices but we don't want it exported from teal.slice. 33 | coalesce_r <- getFromNamespace("coalesce_r", "teal.slice") 34 | # all *Block objects are private in teal.reporter 35 | RcodeBlock <- getFromNamespace("RcodeBlock", "teal.reporter") # nolint: object_name. 36 | 37 | # Use non-exported function(s) from teal.code 38 | # This one is here because lang2calls should not be exported from teal.code 39 | lang2calls <- getFromNamespace("lang2calls", "teal.code") 40 | code2list <- getFromNamespace("code2list", "teal.data") 41 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting Security Issues 4 | 5 | If you believe you have found a security vulnerability in any of the repositories in this organization, please report it to us through coordinated disclosure. 6 | 7 | **Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** 8 | 9 | Instead, please send an email to vulnerability.management[@]roche.com. 10 | 11 | Please include as much of the information listed below as you can to help us better understand and resolve the issue: 12 | 13 | * The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting) 14 | * Full paths of source file(s) related to the manifestation of the issue 15 | * The location of the affected source code (tag/branch/commit or direct URL) 16 | * Any special configuration required to reproduce the issue 17 | * Step-by-step instructions to reproduce the issue 18 | * Proof-of-concept or exploit code (if possible) 19 | * Impact of the issue, including how an attacker might exploit the issue 20 | 21 | This information will help us triage your report more quickly. 22 | 23 | ## Data Security Standards (DSS) 24 | 25 | Please make sure that while reporting issues in the form a bug, feature, or pull request, *all* sensitive information such as [PII](https://www.dhs.gov/privacy-training/what-personally-identifiable-information), [PHI](https://www.hhs.gov/hipaa/for-professionals/security/laws-regulations/index.html), and [PCI](https://www.pcisecuritystandards.org/pci_security/standards_overview) is completely removed from any text and attachments, including pictures and videos. 26 | -------------------------------------------------------------------------------- /inst/WORDLIST: -------------------------------------------------------------------------------- 1 | Biomarker 2 | CDISC 3 | Forkers 4 | Hoffmann 5 | MAEs 6 | ORCID 7 | Shinylive 8 | TLG 9 | Transformators 10 | UI 11 | UX 12 | args 13 | bookmarkable 14 | favicon 15 | favicons 16 | funder 17 | lockfile 18 | modularized 19 | omics 20 | pre 21 | quosure 22 | reactively 23 | summarization 24 | tabset 25 | themer 26 | theming 27 | transformator 28 | transformators 29 | ui 30 | uncheck 31 | -------------------------------------------------------------------------------- /inst/css/custom.css: -------------------------------------------------------------------------------- 1 | /* teal custom css */ 2 | 3 | /* per tag */ 4 | 5 | body:not(.modal-open) { 6 | padding-right: 0 !important; 7 | overflow: auto !important; 8 | } 9 | 10 | /* teal_data_module modal styling */ 11 | body > div:has(~ #shiny-modal-wrapper .fade .blur_background) { 12 | transition: filter 0.3s; 13 | } 14 | 15 | body > div:has(~ #shiny-modal-wrapper .blur_background) { 16 | filter: blur(5px); 17 | } 18 | 19 | #shiny-modal.fade.in:has(.hide_background) { 20 | transition: background-color 0.3s; 21 | } 22 | 23 | #shiny-modal:has(.hide_background) { 24 | background-color: var(--bs-white); 25 | } 26 | 27 | .btn { 28 | --bs-btn-padding-x: 0.7em; 29 | --bs-btn-padding-y: 0.4em; 30 | } 31 | 32 | :root { 33 | --bs-body-font-size: 0.875rem; 34 | } 35 | 36 | .accordion-button { 37 | font-size: 0.875rem; 38 | font-weight: bold; 39 | } 40 | 41 | .teal-body .tabbable > .nav-pills { 42 | width: calc(100% - 5rem); 43 | } 44 | 45 | .teal.bookmark-popup .modal-body { 46 | padding: 0 1.5rem; 47 | } 48 | 49 | .modal-dialog:has(.teal-filter-manager-modal) { 50 | width: fit-content; 51 | } 52 | 53 | .teal-body .bslib-mb-spacing { 54 | --bslib-mb-spacer: 0; 55 | } 56 | -------------------------------------------------------------------------------- /inst/css/validation.css: -------------------------------------------------------------------------------- 1 | /* adding boarder to the validated input */ 2 | .teal_validated:has(.shiny-output-error) { 3 | border: 1px solid red; 4 | border-radius: 4px; 5 | } 6 | 7 | .teal_validated:has(.teal-output-warning) { 8 | border: 1px solid orange; 9 | border-radius: 4px; 10 | } 11 | 12 | .teal_validated .teal-output-warning { 13 | color: #888; 14 | } 15 | 16 | .teal_validated .shiny-output-error, 17 | .teal_validated .teal-output-warning { 18 | margin-top: 0.5em; 19 | } 20 | 21 | .teal_validated .teal-output-warning::before { 22 | content: "\26A0\FE0F"; 23 | } 24 | 25 | .teal_validated .shiny-output-error::before { 26 | content: "\1F6A8"; 27 | } 28 | 29 | .teal_primary_col .shiny-output-error::before { 30 | content: "\1F6A8"; 31 | } 32 | 33 | .teal_primary_col .teal-output-warning::before { 34 | content: "\26A0\FE0F"; 35 | } 36 | 37 | .teal_primary_col .teal_validated:has(.shiny-output-error), 38 | .teal_primary_col .teal_validated:has(.teal-output-warning) { 39 | margin: 1em 0 1em 0; 40 | padding: 0.5em 0 0.5em 0.5em; 41 | } 42 | 43 | .teal_primary_col > .teal_validated:has(.teal-output-warning), 44 | .teal_primary_col > .teal_validated:has(.shiny-output-error) { 45 | width: 100%; 46 | background-color: rgba(223, 70, 97, 0.1); 47 | border: 1px solid red; 48 | padding: 1em; 49 | } 50 | -------------------------------------------------------------------------------- /inst/js/init.js: -------------------------------------------------------------------------------- 1 | // This file contains functions that should be executed at the start of each session, 2 | // not included in the original HTML 3 | 4 | // this code alows the show R code "copy to clipbaord" button to work 5 | var clipboard = new ClipboardJS(".btn[data-clipboard-target]"); 6 | -------------------------------------------------------------------------------- /inst/js/togglePanelItems.js: -------------------------------------------------------------------------------- 1 | // When invoked it adds the setClass and removes the removeClass from the element. 2 | function setAndRemoveClass(element, setClass, removeClass) { 3 | if (typeof element === "string") { 4 | element = document.querySelector(element); 5 | } 6 | element.classList.add(setClass); 7 | element.classList.remove(removeClass); 8 | } 9 | 10 | // When invoked it toggles the class of the element. 11 | function toggleClass(element, class1, class2) { 12 | if (typeof element === "string") { 13 | element = document.querySelector(element); 14 | } 15 | if (element.classList.contains(class1)) { 16 | setAndRemoveClass(element, class2, class1); 17 | } else { 18 | setAndRemoveClass(element, class1, class2); 19 | } 20 | } 21 | 22 | // When invoked it shows the targetSelector element. 23 | function showPanelItem(targeSelector, duration = 400, easing = "slideInTop") { 24 | $(`#${targeSelector}`).show(duration, easing); 25 | $(`#${targeSelector}`).trigger("shown"); 26 | } 27 | 28 | // When invoked it hides the targetSelector element. 29 | function hidePanelItem(targeSelector, duration = 400, easing = "slideOutLeft") { 30 | $(`#${targeSelector}`).hide(duration, easing); 31 | } 32 | 33 | // When invoked it hides/shows targetSelectors elements 34 | // and changes class of element from class1 <-> class2 35 | function togglePanelItems( 36 | element, 37 | targetSelectors, 38 | class1, 39 | class2, 40 | duration = 400, 41 | easing = "swing" 42 | ) { 43 | if (!Array.isArray(targetSelectors)) { 44 | targetSelectors = [targetSelectors]; 45 | } 46 | 47 | targetSelectors.forEach((targetSelector) => { 48 | if ($(`#${targetSelector}`).is(":visible")) { 49 | hidePanelItem(targetSelector, duration, easing); 50 | } else { 51 | showPanelItem(targetSelector, duration, easing); 52 | } 53 | }); 54 | 55 | toggleClass(element, class1, class2); 56 | } 57 | -------------------------------------------------------------------------------- /man/add_landing_modal.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/teal_modifiers.R 3 | \name{add_landing_modal} 4 | \alias{add_landing_modal} 5 | \title{Add a Landing Popup to \code{teal} Application} 6 | \usage{ 7 | add_landing_modal( 8 | x, 9 | title = NULL, 10 | content = NULL, 11 | footer = modalButton("Accept"), 12 | ... 13 | ) 14 | } 15 | \arguments{ 16 | \item{x}{(\code{teal_app}) A \code{teal_app} object created using the \code{init} function.} 17 | 18 | \item{title}{An optional title for the dialog.} 19 | 20 | \item{content}{(\code{character(1)}, \code{shiny.tag} or \code{shiny.tag.list}) with the content of the popup.} 21 | 22 | \item{footer}{UI for footer. Use \code{NULL} for no footer.} 23 | 24 | \item{...}{Additional arguments to \code{\link[shiny:modalDialog]{shiny::modalDialog()}}.} 25 | } 26 | \description{ 27 | Adds a landing popup to the \code{teal} app. This popup will be shown when the app starts. 28 | The dialog must be closed by the app user to proceed to the main application. 29 | } 30 | \examples{ 31 | app <- init( 32 | data = teal_data(IRIS = iris, MTCARS = mtcars), 33 | modules = modules(example_module()) 34 | ) |> 35 | add_landing_modal( 36 | title = "Welcome", 37 | content = "This is a landing popup.", 38 | buttons = modalButton("Accept") 39 | ) 40 | 41 | if (interactive()) { 42 | shinyApp(app$ui, app$server) 43 | } 44 | } 45 | \section{Examples in Shinylive}{ 46 | \describe{ 47 | \item{example-1}{ 48 | \href{https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKcqagSgB0ItMnGYFStAG5wABAB4AtNIBmAVwhjaJdj2kAVLAFUAogIFpUcxUNql2A6dIAmUUlGkBeaV2oB9Z6-YASSxAgGUPaVpGWgBnXGkAWV0AYQBBLHDPGFICFhieXHtpGCJHFWo4GIiSsoqY9jgAD1hUCp8a8rhtfggdAB8APiKoR0cfaigIRyEAc3bS7jsIBwdxUgqIvjAAdThqYngtwuWV4mEyTbBdAAtYyKq3CanZ6VQiVBVMI6KHehVSUgkKpZBbUABC-0BEDsYFSBAIcFQpC2PQcPQEtCU0nYQnIonEUm60hARRitwgrFS6HY5gAJCpaPE6TERFJGD0AL5gDkAXSAA}{Open in Shinylive} 49 | \if{html}{\out{<iframe class="iframe_shinylive" src="https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKcqagSgB0ItMnGYFStAG5wABAB4AtNIBmAVwhjaJdj2kAVLAFUAogIFpUcxUNql2A6dIAmUUlGkBeaV2oB9Z6-YASSxAgGUPaVpGWgBnXGkAWV0AYQBBLHDPGFICFhieXHtpGCJHFWo4GIiSsoqY9jgAD1hUCp8a8rhtfggdAB8APiKoR0cfaigIRyEAc3bS7jsIBwdxUgqIvjAAdThqYngtwuWV4mEyTbBdAAtYyKq3CanZ6VQiVBVMI6KHehVSUgkKpZBbUABC-0BEDsYFSBAIcFQpC2PQcPQEtCU0nYQnIonEUm60hARRitwgrFS6HY5gAJCpaPE6TERFJGD0AL5gDkAXSAA" style="height: 800px; width: 100vw; max-width: 1400px; border: 1px solid rgba(0,0,0,0.175); border-radius: .375rem; position: absolute; left: 50\%; margin-top: 30px; transform: translateX(-50\%); z-index: 1"></iframe>}} 50 | \if{html}{\out{<a style='height: 800px; display: block;'></a>}} 51 | } 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /man/append_module.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/modules.R 3 | \name{append_module} 4 | \alias{append_module} 5 | \title{Append a \code{teal_module} to \code{children} of a \code{teal_modules} object} 6 | \usage{ 7 | append_module(modules, module) 8 | } 9 | \arguments{ 10 | \item{modules}{(\code{teal_modules})} 11 | 12 | \item{module}{(\code{teal_module}) object to be appended onto the children of \code{modules}} 13 | } 14 | \value{ 15 | A \code{teal_modules} object with \code{module} appended. 16 | } 17 | \description{ 18 | Append a \code{teal_module} to \code{children} of a \code{teal_modules} object 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /man/bookmarks_identical.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/module_bookmark_manager.R 3 | \name{bookmarks_identical} 4 | \alias{bookmarks_identical} 5 | \title{Compare bookmarks.} 6 | \usage{ 7 | bookmarks_identical(book1, book2) 8 | } 9 | \arguments{ 10 | \item{book1, book2}{bookmark directories stored in \verb{shiny_bookmarks/}; 11 | default to the two most recently modified directories} 12 | } 13 | \value{ 14 | Invisible \code{NULL} if bookmarks are identical or if there are no bookmarks to test. 15 | \code{FALSE} if inconsistencies are detected. 16 | } 17 | \description{ 18 | Test if two bookmarks store identical state. 19 | } 20 | \details{ 21 | \code{input} environments are compared one variable at a time and if not identical, 22 | values in both bookmarks are reported. States of \code{datatable}s are stripped 23 | of the \code{time} element before comparing because the time stamp is always different. 24 | The contents themselves are not printed as they are large and the contents are not informative. 25 | Elements present in one bookmark and absent in the other are also reported. 26 | Differences are printed as messages. 27 | 28 | \code{values} environments are compared with \code{all.equal}. 29 | } 30 | \section{How to use}{ 31 | 32 | Open an application, change relevant inputs (typically, all of them), and create a bookmark. 33 | Then open that bookmark and immediately create a bookmark of that. 34 | If restoring bookmarks occurred properly, the two bookmarks should store the same state. 35 | } 36 | 37 | \keyword{internal} 38 | -------------------------------------------------------------------------------- /man/build_app_title.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{build_app_title} 4 | \alias{build_app_title} 5 | \title{Build app title with favicon} 6 | \usage{ 7 | build_app_title( 8 | title = "teal app", 9 | favicon = 10 | "https://raw.githubusercontent.com/insightsengineering/hex-stickers/main/PNG/nest.png" 11 | ) 12 | } 13 | \arguments{ 14 | \item{title}{(\code{character}) The browser title for the \code{teal} app.} 15 | 16 | \item{favicon}{(\code{character}) The path for the icon for the title. 17 | The image/icon path can be remote or the static path accessible by \code{shiny}, like the \verb{www/}} 18 | } 19 | \value{ 20 | A \code{shiny.tag} containing the element that adds the title and logo to the \code{shiny} app. 21 | } 22 | \description{ 23 | A helper function to create the browser title along with a logo. 24 | } 25 | -------------------------------------------------------------------------------- /man/check_filter_datanames.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{check_filter_datanames} 4 | \alias{check_filter_datanames} 5 | \title{Check \code{datanames} in filters} 6 | \usage{ 7 | check_filter_datanames(filters, datanames) 8 | } 9 | \arguments{ 10 | \item{filters}{(\code{teal_slices}) object} 11 | 12 | \item{datanames}{(\code{character}) names of datasets available in the \code{data} object} 13 | } 14 | \value{ 15 | A \code{character(1)} containing error message or TRUE if validation passes. 16 | } 17 | \description{ 18 | This function checks whether \code{datanames} in filters correspond to those in \code{data}, 19 | returning character vector with error messages or \code{TRUE} if all checks pass. 20 | } 21 | \keyword{internal} 22 | -------------------------------------------------------------------------------- /man/check_modules_datanames.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{check_modules_datanames} 4 | \alias{check_modules_datanames} 5 | \alias{check_reserved_datanames} 6 | \alias{check_modules_datanames_html} 7 | \title{Check \code{datanames} in modules} 8 | \usage{ 9 | check_modules_datanames(modules, datanames) 10 | 11 | check_reserved_datanames(datanames) 12 | 13 | check_modules_datanames_html(modules, datanames) 14 | } 15 | \arguments{ 16 | \item{modules}{(\code{teal_modules}) object} 17 | 18 | \item{datanames}{(\code{character}) names of datasets available in the \code{data} object} 19 | } 20 | \value{ 21 | \code{TRUE} if validation passes, otherwise \code{character(1)} or \code{shiny.tag.list} 22 | } 23 | \description{ 24 | These functions check if specified \code{datanames} in modules match those in the data object, 25 | returning error messages or \code{TRUE} for successful validation. Two functions return error message 26 | in different forms: 27 | \itemize{ 28 | \item \code{check_modules_datanames} returns \code{character(1)} for basic assertion usage 29 | \item \code{check_modules_datanames_html} returns \code{shiny.tag.list} to display it in the app. 30 | } 31 | } 32 | \keyword{internal} 33 | -------------------------------------------------------------------------------- /man/check_reactive.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/checkmate.R 3 | \name{check_reactive} 4 | \alias{check_reactive} 5 | \alias{test_reactive} 6 | \alias{assert_reactive} 7 | \title{Check that argument is reactive.} 8 | \usage{ 9 | check_reactive(x, null.ok = FALSE) 10 | 11 | test_reactive(x, null.ok = FALSE) 12 | 13 | assert_reactive( 14 | x, 15 | null.ok = FALSE, 16 | .var.name = checkmate::vname(x), 17 | add = NULL 18 | ) 19 | } 20 | \arguments{ 21 | \item{x}{[any]\cr 22 | Object to check.} 23 | 24 | \item{null.ok}{[\code{logical(1)}]\cr 25 | If set to \code{TRUE}, \code{x} may also be \code{NULL}. 26 | In this case only a type check of \code{x} is performed, all additional checks are disabled.} 27 | 28 | \item{.var.name}{[\code{character(1)}]\cr 29 | Name of the checked object to print in assertions. Defaults to 30 | the heuristic implemented in \code{\link[checkmate]{vname}}.} 31 | 32 | \item{add}{[\code{AssertCollection}]\cr 33 | Collection to store assertion messages. See \code{\link[checkmate]{AssertCollection}}.} 34 | } 35 | \value{ 36 | Depending on the function prefix: 37 | If the check is successful, the functions 38 | \code{assertClass}/\code{assert_class} return 39 | \code{x} invisibly, whereas 40 | \code{checkClass}/\code{check_class} and 41 | \code{testClass}/\code{test_class} return 42 | \code{TRUE}. 43 | If the check is not successful, 44 | \code{assertClass}/\code{assert_class} 45 | throws an error message, 46 | \code{testClass}/\code{test_class} 47 | returns \code{FALSE}, 48 | and \code{checkClass}/\code{check_class} 49 | return a string with the error message. 50 | The function \code{expect_class} always returns an 51 | \code{\link[testthat]{expectation}}. 52 | } 53 | \description{ 54 | Check that argument is reactive. 55 | } 56 | \keyword{internal} 57 | -------------------------------------------------------------------------------- /man/create_app_id.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{create_app_id} 4 | \alias{create_app_id} 5 | \title{Application ID} 6 | \usage{ 7 | create_app_id(data, modules) 8 | } 9 | \arguments{ 10 | \item{data}{(\code{teal_data} or \code{teal_data_module}) as accepted by \code{init}} 11 | 12 | \item{modules}{(\code{teal_modules}) object as accepted by \code{init}} 13 | } 14 | \value{ 15 | A single character string. 16 | } 17 | \description{ 18 | Creates App ID used to match filter snapshots to application. 19 | } 20 | \details{ 21 | Calculate app ID that will be used to stamp filter state snapshots. 22 | App ID is a hash of the app's data and modules. 23 | See "transferring snapshots" section in ?snapshot. 24 | } 25 | \keyword{internal} 26 | -------------------------------------------------------------------------------- /man/decorate_err_msg.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/checkmate.R 3 | \name{decorate_err_msg} 4 | \alias{decorate_err_msg} 5 | \title{Capture error and decorate error message.} 6 | \usage{ 7 | decorate_err_msg(x, pre = character(0), post = character(0)) 8 | } 9 | \arguments{ 10 | \item{x}{object to evaluate} 11 | 12 | \item{pre}{(\code{character(1)}) A string to prepend to error message} 13 | 14 | \item{post}{(\code{character(1)}) A string to append to error message} 15 | } 16 | \value{ 17 | \code{x} if no error, otherwise throws error with decorated message 18 | } 19 | \description{ 20 | Capture error and decorate error message. 21 | } 22 | \keyword{internal} 23 | -------------------------------------------------------------------------------- /man/deep_copy_filter.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/teal_slices.R 3 | \name{deep_copy_filter} 4 | \alias{deep_copy_filter} 5 | \title{Deep copy \code{teal_slices}} 6 | \usage{ 7 | deep_copy_filter(filter) 8 | } 9 | \arguments{ 10 | \item{filter}{(\code{teal_slices})} 11 | } 12 | \value{ 13 | \code{teal_slices} 14 | } 15 | \description{ 16 | it's important to create a new copy of \code{teal_slices} when 17 | starting a new \code{shiny} session. Otherwise, object will be shared 18 | by multiple users as it is created in global environment before 19 | \code{shiny} session starts. 20 | } 21 | \keyword{internal} 22 | -------------------------------------------------------------------------------- /man/dot-add_signature_to_data.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/module_init_data.R 3 | \name{.add_signature_to_data} 4 | \alias{.add_signature_to_data} 5 | \title{Adds signature protection to the \code{datanames} in the data} 6 | \usage{ 7 | .add_signature_to_data(data) 8 | } 9 | \arguments{ 10 | \item{data}{(\code{teal_data})} 11 | } 12 | \value{ 13 | \code{teal_data} with additional code that has signature of the \code{datanames} 14 | } 15 | \description{ 16 | Adds signature protection to the \code{datanames} in the data 17 | } 18 | \keyword{internal} 19 | -------------------------------------------------------------------------------- /man/dot-call_once_when.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/module_nested_tabs.R 3 | \name{.call_once_when} 4 | \alias{.call_once_when} 5 | \title{Calls expression when condition is met} 6 | \usage{ 7 | .call_once_when( 8 | eventExpr, 9 | handlerExpr, 10 | event.env = parent.frame(), 11 | handler.env = parent.frame(), 12 | ... 13 | ) 14 | } 15 | \arguments{ 16 | \item{eventExpr}{A (quoted or unquoted) logical expression that represents the event; 17 | this can be a simple reactive value like input$click, a call to a reactive expression 18 | like dataset(), or even a complex expression inside curly braces.} 19 | 20 | \item{handlerExpr}{The expression to call whenever \code{eventExpr} is 21 | invalidated. This should be a side-effect-producing action (the return 22 | value will be ignored). It will be executed within an \code{\link[shiny:isolate]{isolate()}} 23 | scope.} 24 | 25 | \item{event.env}{The parent environment for the reactive expression. By default, 26 | this is the calling environment, the same as when defining an ordinary 27 | non-reactive expression. If \code{eventExpr} is a quosure and \code{event.quoted} is \code{TRUE}, 28 | then \code{event.env} is ignored.} 29 | 30 | \item{handler.env}{The parent environment for the reactive expression. By default, 31 | this is the calling environment, the same as when defining an ordinary 32 | non-reactive expression. If \code{handlerExpr} is a quosure and \code{handler.quoted} is \code{TRUE}, 33 | then \code{handler.env} is ignored.} 34 | 35 | \item{...}{additional arguments passed to \code{observeEvent} with the exception of \code{eventExpr} that is not allowed.} 36 | } 37 | \value{ 38 | An observer. 39 | } 40 | \description{ 41 | Function postpones \code{handlerExpr} to the moment when \code{eventExpr} (condition) returns \code{TRUE}, 42 | otherwise nothing happens. 43 | } 44 | \keyword{internal} 45 | -------------------------------------------------------------------------------- /man/dot-get_hashes_code.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/module_init_data.R 3 | \name{.get_hashes_code} 4 | \alias{.get_hashes_code} 5 | \title{Get code that tests the integrity of the reproducible data} 6 | \usage{ 7 | .get_hashes_code(data, datanames = names(data)) 8 | } 9 | \arguments{ 10 | \item{data}{(\code{teal_data}) object holding the data} 11 | 12 | \item{datanames}{(\code{character}) names of \code{datasets}} 13 | } 14 | \value{ 15 | A character vector with the code lines. 16 | } 17 | \description{ 18 | Get code that tests the integrity of the reproducible data 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /man/dot-smart_rbind.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{.smart_rbind} 4 | \alias{.smart_rbind} 5 | \title{Smart \code{rbind}} 6 | \usage{ 7 | .smart_rbind(...) 8 | } 9 | \arguments{ 10 | \item{...}{(\code{data.frame})} 11 | } 12 | \description{ 13 | Combine \code{data.frame} objects which have different columns 14 | } 15 | \keyword{internal} 16 | -------------------------------------------------------------------------------- /man/dot-teal_favicon.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \docType{data} 4 | \name{.teal_favicon} 5 | \alias{.teal_favicon} 6 | \title{The default favicon for the teal app.} 7 | \format{ 8 | An object of class \code{character} of length 1. 9 | } 10 | \usage{ 11 | .teal_favicon 12 | } 13 | \description{ 14 | The default favicon for the teal app. 15 | } 16 | \keyword{internal} 17 | -------------------------------------------------------------------------------- /man/example_module.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dummy_functions.R 3 | \name{example_module} 4 | \alias{example_module} 5 | \title{An example \code{teal} module} 6 | \usage{ 7 | example_module( 8 | label = "example teal module", 9 | datanames = "all", 10 | transformators = list(), 11 | decorators = list() 12 | ) 13 | } 14 | \arguments{ 15 | \item{label}{(\code{character(1)}) Label shown in the navigation item for the module or module group. 16 | For \code{modules()} defaults to \code{"root"}. See \code{Details}.} 17 | 18 | \item{datanames}{(\code{character}) Names of the datasets relevant to the item. 19 | There are 2 reserved values that have specific behaviors: 20 | \itemize{ 21 | \item The keyword \code{"all"} includes all datasets available in the data passed to the teal application. 22 | \item \code{NULL} hides the sidebar panel completely. 23 | \item If \code{transformators} are specified, their \code{datanames} are automatically added to this \code{datanames} 24 | argument. 25 | }} 26 | 27 | \item{transformators}{(\code{list} of \code{teal_transform_module}) that will be applied to transform module's data input. 28 | To learn more check \code{vignette("transform-input-data", package = "teal")}.} 29 | 30 | \item{decorators}{\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} (\code{list} of \code{teal_transform_module}) optional, 31 | decorator for \code{object} included in the module.} 32 | } 33 | \value{ 34 | A \code{teal} module which can be included in the \code{modules} argument to \code{\link[=init]{init()}}. 35 | } 36 | \description{ 37 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} 38 | } 39 | \details{ 40 | This module creates an object called \code{object} that can be modified with decorators. 41 | The \code{object} is determined by what's selected in \verb{Choose a dataset} input in UI. 42 | The object can be anything that can be handled by \code{renderPrint()}. 43 | See the \code{vignette("transform-module-output", package = "teal")} or \code{\link{teal_transform_module}} 44 | to read more about decorators. 45 | } 46 | \examples{ 47 | app <- init( 48 | data = teal_data(IRIS = iris, MTCARS = mtcars), 49 | modules = example_module() 50 | ) 51 | if (interactive()) { 52 | shinyApp(app$ui, app$server) 53 | } 54 | } 55 | \section{Examples in Shinylive}{ 56 | \describe{ 57 | \item{example-1}{ 58 | \href{https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKcqagSgB0ItMnGYFStAG5wABAB4AtNIBmAVwhjaJdj2kAVLAFUAogIFpUcxUNql2A6dIAmUUlGkBeaV2oB9Z6-YASSxAgGUPaVpGWgBnXGkAWV0AYQBBLHDPGFICFhieXHtpGCJHFWo4GIi4AA9YVAqfErKK7QF+QSVpdiFyUXEpbR0QIpiACyFWVPR2cwASFVp4+ZiRKUYOgF8wTYBdIA}{Open in Shinylive} 59 | \if{html}{\out{<iframe class="iframe_shinylive" src="https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKcqagSgB0ItMnGYFStAG5wABAB4AtNIBmAVwhjaJdj2kAVLAFUAogIFpUcxUNql2A6dIAmUUlGkBeaV2oB9Z6-YASSxAgGUPaVpGWgBnXGkAWV0AYQBBLHDPGFICFhieXHtpGCJHFWo4GIi4AA9YVAqfErKK7QF+QSVpdiFyUXEpbR0QIpiACyFWVPR2cwASFVp4+ZiRKUYOgF8wTYBdIA" style="height: 800px; width: 100vw; max-width: 1400px; border: 1px solid rgba(0,0,0,0.175); border-radius: .375rem; position: absolute; left: 50\%; margin-top: 30px; transform: translateX(-50\%); z-index: 1"></iframe>}} 60 | \if{html}{\out{<a style='height: 800px; display: block;'></a>}} 61 | } 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /man/extract_transformators.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/teal_transform_module.R 3 | \name{extract_transformators} 4 | \alias{extract_transformators} 5 | \title{Extract all \code{transformators} from \code{modules}.} 6 | \usage{ 7 | extract_transformators(modules) 8 | } 9 | \arguments{ 10 | \item{modules}{\code{teal_modules} or \code{teal_module}} 11 | } 12 | \value{ 13 | A list of \code{teal_transform_module} nested in the same way as input \code{modules}. 14 | } 15 | \description{ 16 | Extract all \code{transformators} from \code{modules}. 17 | } 18 | \keyword{internal} 19 | -------------------------------------------------------------------------------- /man/figures/filterpanel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insightsengineering/teal/3d6b93310c969e0a6fecab41102846c94d99d4f1/man/figures/filterpanel.png -------------------------------------------------------------------------------- /man/figures/lifecycle-archived.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="110" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="110" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h53v20H0z"/><path fill="#e05d44" d="M53 0h57v20H53z"/><path fill="url(#b)" d="M0 0h110v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"> <text x="275" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">lifecycle</text><text x="275" y="140" transform="scale(.1)" textLength="430">lifecycle</text><text x="805" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="470">archived</text><text x="805" y="140" transform="scale(.1)" textLength="470">archived</text></g> </svg> -------------------------------------------------------------------------------- /man/figures/lifecycle-defunct.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="104" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="104" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h53v20H0z"/><path fill="#e05d44" d="M53 0h51v20H53z"/><path fill="url(#b)" d="M0 0h104v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><text x="275" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">lifecycle</text><text x="275" y="140" transform="scale(.1)" textLength="430">lifecycle</text><text x="775" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="410">defunct</text><text x="775" y="140" transform="scale(.1)" textLength="410">defunct</text></g> </svg> -------------------------------------------------------------------------------- /man/figures/lifecycle-deprecated.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="124" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="124" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h53v20H0z"/><path fill="#fe7d37" d="M53 0h71v20H53z"/><path fill="url(#b)" d="M0 0h124v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><text x="275" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">lifecycle</text><text x="275" y="140" transform="scale(.1)" textLength="430">lifecycle</text><text x="875" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="610">deprecated</text><text x="875" y="140" transform="scale(.1)" textLength="610">deprecated</text></g> </svg> -------------------------------------------------------------------------------- /man/figures/lifecycle-experimental.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="136" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="136" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h53v20H0z"/><path fill="#fe7d37" d="M53 0h83v20H53z"/><path fill="url(#b)" d="M0 0h136v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><text x="275" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">lifecycle</text><text x="275" y="140" transform="scale(.1)" textLength="430">lifecycle</text><text x="935" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="730">experimental</text><text x="935" y="140" transform="scale(.1)" textLength="730">experimental</text></g> </svg> -------------------------------------------------------------------------------- /man/figures/lifecycle-maturing.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="114" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="114" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h53v20H0z"/><path fill="#007ec6" d="M53 0h61v20H53z"/><path fill="url(#b)" d="M0 0h114v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><text x="275" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">lifecycle</text><text x="275" y="140" transform="scale(.1)" textLength="430">lifecycle</text><text x="825" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="510">maturing</text><text x="825" y="140" transform="scale(.1)" textLength="510">maturing</text></g> </svg> -------------------------------------------------------------------------------- /man/figures/lifecycle-questioning.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="126" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="126" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h53v20H0z"/><path fill="#007ec6" d="M53 0h73v20H53z"/><path fill="url(#b)" d="M0 0h126v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><text x="275" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">lifecycle</text><text x="275" y="140" transform="scale(.1)" textLength="430">lifecycle</text><text x="885" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="630">questioning</text><text x="885" y="140" transform="scale(.1)" textLength="630">questioning</text></g> </svg> -------------------------------------------------------------------------------- /man/figures/lifecycle-soft-deprecated.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="150" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="150" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h53v20H0z"/><path fill="#007ec6" d="M53 0h97v20H53z"/><path fill="url(#b)" d="M0 0h150v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><text x="275" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">lifecycle</text><text x="275" y="140" transform="scale(.1)" textLength="430">lifecycle</text><text x="1005" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="870">soft-deprecated</text><text x="1005" y="140" transform="scale(.1)" textLength="870">soft-deprecated</text></g> </svg> -------------------------------------------------------------------------------- /man/figures/lifecycle-stable.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="96" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="96" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h53v20H0z"/><path fill="#4c1" d="M53 0h43v20H53z"/><path fill="url(#b)" d="M0 0h96v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><text x="275" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">lifecycle</text><text x="275" y="140" transform="scale(.1)" textLength="430">lifecycle</text><text x="735" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="330">stable</text><text x="735" y="140" transform="scale(.1)" textLength="330">stable</text></g> </svg> -------------------------------------------------------------------------------- /man/figures/lifecycle-superseded.svg: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="128" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h55v20H0z"/><path fill="#007ec6" d="M55 0h73v20H55z"/><path fill="url(#b)" d="M0 0h128v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"> <text x="285" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="450">lifecycle</text><text x="285" y="140" transform="scale(.1)" textLength="450">lifecycle</text><text x="905" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="630">superseded</text><text x="905" y="140" transform="scale(.1)" textLength="630">superseded</text></g> </svg> -------------------------------------------------------------------------------- /man/figures/readme_app.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insightsengineering/teal/3d6b93310c969e0a6fecab41102846c94d99d4f1/man/figures/readme_app.webp -------------------------------------------------------------------------------- /man/figures/reporter.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insightsengineering/teal/3d6b93310c969e0a6fecab41102846c94d99d4f1/man/figures/reporter.jpg -------------------------------------------------------------------------------- /man/figures/showrcode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insightsengineering/teal/3d6b93310c969e0a6fecab41102846c94d99d4f1/man/figures/showrcode.jpg -------------------------------------------------------------------------------- /man/get_client_timezone.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{get_client_timezone} 4 | \alias{get_client_timezone} 5 | \title{Get client timezone} 6 | \usage{ 7 | get_client_timezone(ns) 8 | } 9 | \arguments{ 10 | \item{ns}{(\code{function}) namespace function passed from the \code{session} object in the \code{shiny} server. 11 | For \code{shiny} modules this will allow for proper name spacing of the registered input.} 12 | } 13 | \value{ 14 | \code{NULL}, invisibly. 15 | } 16 | \description{ 17 | User timezone in the browser may be different to the one on the server. 18 | This script can be run to register a \code{shiny} input which contains information about the timezone in the browser. 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /man/get_unique_labels.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{get_unique_labels} 4 | \alias{get_unique_labels} 5 | \title{Get unique labels} 6 | \usage{ 7 | get_unique_labels(labels) 8 | } 9 | \arguments{ 10 | \item{labels}{(\code{character}) vector of labels} 11 | } 12 | \value{ 13 | (\code{character}) vector of unique labels 14 | } 15 | \description{ 16 | Get unique labels for the modules to avoid namespace conflicts. 17 | } 18 | \keyword{internal} 19 | -------------------------------------------------------------------------------- /man/include_css_files.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/include_css_js.R 3 | \name{include_css_files} 4 | \alias{include_css_files} 5 | \title{Include \code{CSS} files from \verb{/inst/css/} package directory to application header} 6 | \usage{ 7 | include_css_files(pattern = "*") 8 | } 9 | \arguments{ 10 | \item{pattern}{(\code{character}) pattern of files to be included} 11 | } 12 | \value{ 13 | HTML code that includes \code{CSS} files. 14 | } 15 | \description{ 16 | \code{system.file} should not be used to access files in other packages, it does 17 | not work with \code{devtools}. Therefore, we redefine this method in each package 18 | as needed. Thus, we do not export this method. 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /man/include_js_files.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/include_css_js.R 3 | \name{include_js_files} 4 | \alias{include_js_files} 5 | \title{Include \code{JS} files from \verb{/inst/js/} package directory to application header} 6 | \usage{ 7 | include_js_files(pattern = NULL, except = NULL) 8 | } 9 | \arguments{ 10 | \item{pattern}{(\code{character}) pattern of files to be included, passed to \code{system.file}} 11 | 12 | \item{except}{(\code{character}) vector of basename filenames to be excluded} 13 | } 14 | \value{ 15 | HTML code that includes \code{JS} files. 16 | } 17 | \description{ 18 | \code{system.file} should not be used to access files in other packages, it does 19 | not work with \code{devtools}. Therefore, we redefine this method in each package 20 | as needed. Thus, we do not export this method 21 | } 22 | \keyword{internal} 23 | -------------------------------------------------------------------------------- /man/include_teal_css_js.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/include_css_js.R 3 | \name{include_teal_css_js} 4 | \alias{include_teal_css_js} 5 | \title{Code to include \code{teal} \code{CSS} and \code{JavaScript} files} 6 | \usage{ 7 | include_teal_css_js() 8 | } 9 | \value{ 10 | A \code{shiny.tag.list}. 11 | } 12 | \description{ 13 | This is useful when you want to use the same \code{JavaScript} and \code{CSS} files that are 14 | used with the \code{teal} application. 15 | This is also useful for running standalone modules in \code{teal} with the correct 16 | styles. 17 | Also initializes \code{shinyjs} so you can use it. 18 | } 19 | \details{ 20 | Simply add \code{include_teal_css_js()} as one of the UI elements. 21 | } 22 | \keyword{internal} 23 | -------------------------------------------------------------------------------- /man/is_arg_used.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/modules.R 3 | \name{is_arg_used} 4 | \alias{is_arg_used} 5 | \title{Does the object make use of the \code{arg}} 6 | \usage{ 7 | is_arg_used(modules, arg) 8 | } 9 | \arguments{ 10 | \item{modules}{(\code{teal_module} or \code{teal_modules}) object} 11 | 12 | \item{arg}{(\code{character(1)}) names of the arguments to be checked against formals of \code{teal} modules.} 13 | } 14 | \value{ 15 | \code{logical} whether the object makes use of \code{arg}. 16 | } 17 | \description{ 18 | Does the object make use of the \code{arg} 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /man/landing_popup_module.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/landing_popup_module.R 3 | \name{landing_popup_module} 4 | \alias{landing_popup_module} 5 | \title{Landing popup module} 6 | \usage{ 7 | landing_popup_module( 8 | label = "Landing Popup", 9 | title = NULL, 10 | content = NULL, 11 | buttons = modalButton("Accept") 12 | ) 13 | } 14 | \arguments{ 15 | \item{label}{(\code{character(1)}) Label of the module.} 16 | 17 | \item{title}{(\code{character(1)}) Text to be displayed as popup title.} 18 | 19 | \item{content}{(\code{character(1)}, \code{shiny.tag} or \code{shiny.tag.list}) with the content of the popup. 20 | Passed to \code{...} of \code{shiny::modalDialog}. See examples.} 21 | 22 | \item{buttons}{(\code{shiny.tag} or \code{shiny.tag.list}) Typically a \code{modalButton} or \code{actionButton}. See examples.} 23 | } 24 | \value{ 25 | A \code{teal_module} (extended with \code{teal_landing_module} class) to be used in \code{teal} applications. 26 | } 27 | \description{ 28 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Creates a landing welcome popup for \code{teal} applications. 29 | 30 | This module is used to display a popup dialog when the application starts. 31 | The dialog blocks access to the application and must be closed with a button before the application can be viewed. 32 | This function is deprecated, please use \code{add_landing_modal()} on the teal app object instead. 33 | } 34 | -------------------------------------------------------------------------------- /man/make_teal_transform_server.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/teal_transform_module.R 3 | \name{make_teal_transform_server} 4 | \alias{make_teal_transform_server} 5 | \title{Make teal_transform_module's server} 6 | \usage{ 7 | make_teal_transform_server(expr) 8 | } 9 | \arguments{ 10 | \item{expr}{(\code{language}) 11 | An R call which will be evaluated within \code{\link[teal.data:teal_data]{teal.data::teal_data}} environment.} 12 | } 13 | \value{ 14 | \verb{function(id, data)} returning \code{shiny} module 15 | } 16 | \description{ 17 | A factory function to simplify creation of a \code{\link{teal_transform_module}}'s server. Specified \code{expr} 18 | is wrapped in a shiny module function and output can be passed to the \code{server} argument in 19 | \code{\link[=teal_transform_module]{teal_transform_module()}} call. Such a server function can be linked with ui and values from the 20 | inputs can be used in the expression. Object names specified in the expression will be substituted 21 | with the value of the respective input (matched by the name) - for example in 22 | \code{expression(graph <- graph + ggtitle(title))} object \code{title} will be replaced with the value of 23 | \code{input$title}. 24 | } 25 | \examples{ 26 | 27 | trim_iris <- teal_transform_module( 28 | label = "Simplified interactive transformator for iris", 29 | datanames = "iris", 30 | ui = function(id) { 31 | ns <- NS(id) 32 | numericInput(ns("n_rows"), "Subset n rows", value = 6, min = 1, max = 150, step = 1) 33 | }, 34 | server = make_teal_transform_server(expression(iris <- head(iris, n_rows))) 35 | ) 36 | 37 | app <- init( 38 | data = teal_data(iris = iris), 39 | modules = example_module(transformators = trim_iris) 40 | ) 41 | if (interactive()) { 42 | shinyApp(app$ui, app$server) 43 | } 44 | 45 | } 46 | \section{Examples in Shinylive}{ 47 | \describe{ 48 | \item{example-1}{ 49 | \href{https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKcqagSgB0ItMnGYFStAG5wABAB4AtNIBmAVwhjaJdj2kAVLAFUAogNNlGtGAH1aFgM5zFXaldLMIdpUUbWYRACYq1HDsAtLS1FD0cNTSALzSfGAAypaodEq0cP7SQuSi4lLSblAeXj5QpN7K1ba0dkm4YdL+laWwcA4JSXUNeM0qtPHKahpatP46IM3hHo7SAHLJ7BP8EOGzKvAWBACSEKgqpOweoZBWjEQA7n08uIkpKvR2cKTS65c3jdIS3CoyCQAbPcYEJhgBGEFQAAeEIArAAGe52cioCFrcIAXya62kL0YUkYwxgUAA1nBXHBuK53J5vNZ8YT2HBoahGJ07JoICt7PMABZU-w8+r3CAXa52HhSgRrARoNEKXKCY7NVqkKDDZxWNVQYVdXL2O7NPyBYL6lmwdIUk1BEIlMr0yrefVuSw2Q0ygS0JTSFbCAqSEJS6TTXF2PlCVgAQXQ7HlABJBvcE4yRGtMQIwJiALpAA}{Open in Shinylive} 50 | \if{html}{\out{<iframe class="iframe_shinylive" src="https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKcqagSgB0ItMnGYFStAG5wABAB4AtNIBmAVwhjaJdj2kAVLAFUAogNNlGtGAH1aFgM5zFXaldLMIdpUUbWYRACYq1HDsAtLS1FD0cNTSALzSfGAAypaodEq0cP7SQuSi4lLSblAeXj5QpN7K1ba0dkm4YdL+laWwcA4JSXUNeM0qtPHKahpatP46IM3hHo7SAHLJ7BP8EOGzKvAWBACSEKgqpOweoZBWjEQA7n08uIkpKvR2cKTS65c3jdIS3CoyCQAbPcYEJhgBGEFQAAeEIArAAGe52cioCFrcIAXya62kL0YUkYwxgUAA1nBXHBuK53J5vNZ8YT2HBoahGJ07JoICt7PMABZU-w8+r3CAXa52HhSgRrARoNEKXKCY7NVqkKDDZxWNVQYVdXL2O7NPyBYL6lmwdIUk1BEIlMr0yrefVuSw2Q0ygS0JTSFbCAqSEJS6TTXF2PlCVgAQXQ7HlABJBvcE4yRGtMQIwJiALpAA" style="height: 800px; width: 100vw; max-width: 1400px; border: 1px solid rgba(0,0,0,0.175); border-radius: .375rem; position: absolute; left: 50\%; margin-top: 30px; transform: translateX(-50\%); z-index: 1"></iframe>}} 51 | \if{html}{\out{<a style='height: 800px; display: block;'></a>}} 52 | } 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /man/module_bookmark_manager.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/module_bookmark_manager.R 3 | \name{module_bookmark_manager} 4 | \alias{module_bookmark_manager} 5 | \alias{bookmark} 6 | \alias{bookmark_manager} 7 | \alias{bookmark_manager_module} 8 | \alias{ui_bookmark_panel} 9 | \alias{srv_bookmark_panel} 10 | \alias{get_bookmarking_option} 11 | \alias{need_bookmarking} 12 | \title{App state management.} 13 | \usage{ 14 | ui_bookmark_panel(id, modules) 15 | 16 | srv_bookmark_panel(id, modules) 17 | 18 | get_bookmarking_option() 19 | 20 | need_bookmarking(modules) 21 | } 22 | \arguments{ 23 | \item{id}{(\code{character(1)}) \code{shiny} module instance id.} 24 | 25 | \item{modules}{(\code{teal_modules}) 26 | \code{teal_modules} object. These are the specific output modules which 27 | will be displayed in the \code{teal} application. See \code{\link[=modules]{modules()}} and \code{\link[=module]{module()}} for 28 | more details.} 29 | } 30 | \value{ 31 | Invisible \code{NULL}. 32 | } 33 | \description{ 34 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} 35 | 36 | Capture and restore the global (app) input state. 37 | } 38 | \details{ 39 | This module introduces bookmarks into \code{teal} apps: the \code{shiny} bookmarking mechanism becomes enabled 40 | and server-side bookmarks can be created. 41 | 42 | The bookmark manager presents a button with the bookmark icon and is placed in the tab-bar. 43 | When clicked, the button creates a bookmark and opens a modal which displays the bookmark URL. 44 | 45 | \code{teal} does not guarantee that all modules (\code{teal_module} objects) are bookmarkable. 46 | Those that are, have a \code{teal_bookmarkable} attribute set to \code{TRUE}. If any modules are not bookmarkable, 47 | the bookmark manager modal displays a warning and the bookmark button displays a flag. 48 | In order to communicate that a external module is bookmarkable, the module developer 49 | should set the \code{teal_bookmarkable} attribute to \code{TRUE}. 50 | } 51 | \section{Server logic}{ 52 | 53 | A bookmark is a URL that contains the app address with a \verb{/?_state_id_=<bookmark_dir>} suffix. 54 | \verb{<bookmark_dir>} is a directory created on the server, where the state of the application is saved. 55 | Accessing the bookmark URL opens a new session of the app that starts in the previously saved state. 56 | } 57 | 58 | \section{Note}{ 59 | 60 | To enable bookmarking use either: 61 | \itemize{ 62 | \item \code{shiny} app by using \code{shinyApp(..., enableBookmarking = "server")} (not supported in \code{shinytest2}) 63 | \item set \code{options(shiny.bookmarkStore = "server")} before running the app 64 | } 65 | } 66 | 67 | \keyword{internal} 68 | -------------------------------------------------------------------------------- /man/module_data_summary.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/module_data_summary.R 3 | \name{module_data_summary} 4 | \alias{module_data_summary} 5 | \alias{ui_data_summary} 6 | \alias{srv_data_summary} 7 | \alias{get_filter_overview_wrapper} 8 | \alias{get_filter_overview} 9 | \alias{get_filter_overview_array} 10 | \alias{get_filter_overview_MultiAssayExperiment} 11 | \title{Data summary} 12 | \usage{ 13 | ui_data_summary(id) 14 | 15 | srv_data_summary(id, data) 16 | 17 | get_filter_overview_wrapper(teal_data) 18 | 19 | get_filter_overview(current_data, initial_data, dataname, subject_keys) 20 | 21 | get_filter_overview_array(current_data, initial_data, dataname, subject_keys) 22 | 23 | get_filter_overview_MultiAssayExperiment(current_data, initial_data, dataname) 24 | } 25 | \arguments{ 26 | \item{id}{(\code{character(1)}) \code{shiny} module instance id.} 27 | 28 | \item{data}{(\code{reactive} returning \code{teal_data})} 29 | 30 | \item{current_data}{(\code{object}) current object (after filtering and transforming).} 31 | 32 | \item{initial_data}{(\code{object}) initial object.} 33 | 34 | \item{dataname}{(\code{character(1)})} 35 | 36 | \item{subject_keys}{(\code{character}) names of the columns which determine a single unique subjects} 37 | } 38 | \value{ 39 | \code{NULL}. 40 | } 41 | \description{ 42 | Module and its utils to display the number of rows and subjects in the filtered and unfiltered data. 43 | } 44 | \details{ 45 | Handling different data classes: 46 | \code{get_filter_overview()} is a pseudo S3 method which has variants for: 47 | \itemize{ 48 | \item \code{array} (\code{data.frame}, \code{DataFrame}, \code{array}, \code{Matrix} and \code{SummarizedExperiment}): Method variant 49 | can be applied to any two-dimensional objects on which \code{\link[=ncol]{ncol()}} can be used. 50 | \item \code{MultiAssayExperiment}: for which summary contains counts for \code{colData} and all \code{experiments}. 51 | \item For other data types module displays data name with warning icon and no more details. 52 | } 53 | 54 | Module includes also "Show/Hide unsupported" button to toggle rows of the summary table 55 | containing datasets where number of observations are not calculated. 56 | } 57 | \keyword{internal} 58 | -------------------------------------------------------------------------------- /man/module_filter_data.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/module_filter_data.R 3 | \name{module_filter_data} 4 | \alias{module_filter_data} 5 | \alias{ui_filter_data} 6 | \alias{srv_filter_data} 7 | \alias{.make_filtered_teal_data} 8 | \alias{.observe_active_filter_changed} 9 | \alias{.get_filter_expr} 10 | \title{Filter panel module in teal} 11 | \usage{ 12 | ui_filter_data(id) 13 | 14 | srv_filter_data(id, datasets, active_datanames, data, is_active) 15 | 16 | .make_filtered_teal_data(modules, data, datasets = NULL, datanames) 17 | 18 | .observe_active_filter_changed(datasets, is_active, active_datanames, data) 19 | 20 | .get_filter_expr(datasets, datanames) 21 | } 22 | \arguments{ 23 | \item{id}{(\code{character(1)}) \code{shiny} module instance id.} 24 | 25 | \item{datasets}{(\code{reactive} returning \code{FilteredData} or \code{NULL}) 26 | When \code{datasets} is passed from the parent module (\code{srv_teal}) then \code{dataset} is a singleton 27 | which implies in filter-panel to be "global". When \code{NULL} then filter-panel is "module-specific".} 28 | 29 | \item{active_datanames}{(\code{reactive} returning \code{character}) this module's data names} 30 | 31 | \item{data}{(\code{reactive} returning \code{teal_data})} 32 | 33 | \item{modules}{(\code{teal_modules}) 34 | \code{teal_modules} object. These are the specific output modules which 35 | will be displayed in the \code{teal} application. See \code{\link[=modules]{modules()}} and \code{\link[=module]{module()}} for 36 | more details.} 37 | } 38 | \value{ 39 | A \code{eventReactive} containing \code{teal_data} containing filtered objects and filter code. 40 | \code{eventReactive} triggers only if all conditions are met: 41 | \itemize{ 42 | \item tab is selected (\code{is_active}) 43 | \item when filters are changed (\code{get_filter_expr} is different than previous) 44 | } 45 | } 46 | \description{ 47 | Creates filter panel module from \code{teal_data} object and returns \code{teal_data}. It is build in a way 48 | that filter panel changes and anything what happens before (e.g. \code{\link{module_init_data}}) is triggering 49 | further reactive events only if something has changed and if the module is visible. Thanks to 50 | this special implementation all modules' data are recalculated only for those modules which are 51 | currently displayed. 52 | } 53 | \keyword{internal} 54 | -------------------------------------------------------------------------------- /man/module_filter_manager.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/module_filter_manager.R 3 | \docType{class} 4 | \encoding{UTF-8} 5 | \name{module_filter_manager} 6 | \alias{module_filter_manager} 7 | \alias{ui_filter_manager_panel} 8 | \alias{srv_filter_manager_panel} 9 | \alias{ui_filter_manager} 10 | \alias{srv_filter_manager} 11 | \alias{srv_module_filter_manager} 12 | \alias{.slicesGlobal-class} 13 | \alias{.slicesGlobal} 14 | \title{Manage multiple \code{FilteredData} objects} 15 | \usage{ 16 | ui_filter_manager_panel(id) 17 | 18 | srv_filter_manager_panel(id, slices_global) 19 | 20 | ui_filter_manager(id) 21 | 22 | srv_filter_manager(id, slices_global) 23 | 24 | srv_module_filter_manager(id, module_fd, slices_global) 25 | } 26 | \arguments{ 27 | \item{id}{(\code{character(1)}) 28 | \code{shiny} module instance id.} 29 | 30 | \item{slices_global}{(\code{reactiveVal}) 31 | containing \code{teal_slices}.} 32 | 33 | \item{module_fd}{(\code{FilteredData}) 34 | Object containing the data to be filtered in a single \code{teal} module.} 35 | } 36 | \value{ 37 | Module returns a \code{slices_global} (\code{reactiveVal}) containing a \code{teal_slices} object with mapping. 38 | } 39 | \description{ 40 | Oversee filter states across the entire application. 41 | } 42 | 43 | \section{Slices global}{ 44 | 45 | The key role in maintaining the module-specific filter states is played by the \code{.slicesGlobal} 46 | object. It is a reference class that holds the following fields: 47 | \itemize{ 48 | \item \code{all_slices} (\code{reactiveVal}) - reactive value containing all filters registered in an app. 49 | \item \code{module_slices_api} (\code{reactiveValues}) - reactive field containing references to each modules' 50 | \code{FilteredData} object methods. At this moment it is used only in \code{srv_filter_manager} to display 51 | the filter states in a table combining informations from \code{all_slices} and from 52 | \code{FilteredData$get_available_teal_slices()}. 53 | } 54 | 55 | During a session only new filters are added to \code{all_slices} unless \code{\link{module_snapshot_manager}} is 56 | used to restore previous state. Filters from \code{all_slices} can be activated or deactivated in a 57 | module which is linked (both ways) by \code{attr(, "mapping")} so that: 58 | \itemize{ 59 | \item If module's filter is added or removed in its \code{FilteredData} object, this information is passed 60 | to \code{SlicesGlobal} which updates \code{attr(, "mapping")} accordingly. 61 | \item When mapping changes in a \code{SlicesGlobal}, filters are set or removed from module's 62 | \code{FilteredData}. 63 | } 64 | } 65 | 66 | \section{Filter manager}{ 67 | 68 | Filter-manager is split into two parts: 69 | \enumerate{ 70 | \item \code{ui/srv_filter_manager_panel} - Called once for the whole app. This module observes changes in 71 | the filters in \code{slices_global} and displays them in a table utilizing information from \code{mapping}: 72 | } 73 | \itemize{ 74 | \item (\code{TRUE}) - filter is active in the module 75 | \item (\code{FALSE}) - filter is inactive in the module 76 | \item (\code{NA}) - filter is not available in the module 77 | } 78 | \enumerate{ 79 | \item \code{ui/srv_module_filter_manager} - Called once for each \code{teal_module}. Handling filter states 80 | for of single module and keeping module \code{FilteredData} consistent with \code{slices_global}, so that 81 | local filters are always reflected in the \code{slices_global} and its mapping and vice versa. 82 | } 83 | } 84 | 85 | \keyword{internal} 86 | -------------------------------------------------------------------------------- /man/module_init_data.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/module_init_data.R 3 | \name{module_init_data} 4 | \alias{module_init_data} 5 | \alias{ui_init_data} 6 | \alias{srv_init_data} 7 | \title{Data Module for teal} 8 | \usage{ 9 | ui_init_data(id) 10 | 11 | srv_init_data(id, data) 12 | } 13 | \arguments{ 14 | \item{id}{(\code{character(1)}) \code{shiny} module instance id.} 15 | 16 | \item{data}{(\code{teal_data}, \code{teal_data_module}, or \code{reactive} returning \code{teal_data}) 17 | The data which application will depend on.} 18 | } 19 | \value{ 20 | A \code{reactive} object that returns: 21 | Output of the \code{data}. If \code{data} fails then returned error is handled (after \code{\link[=tryCatch]{tryCatch()}}) so that 22 | rest of the application can respond to this respectively. 23 | } 24 | \description{ 25 | This module manages the \code{data} argument for \code{srv_teal}. The \code{teal} framework uses \code{\link[teal.data:teal_data]{teal.data::teal_data()}}, 26 | which can be provided in various ways: 27 | \enumerate{ 28 | \item Directly as a \code{\link[teal.data:teal_data]{teal.data::teal_data()}} object. This will automatically convert it into a \code{reactive} \code{teal_data}. 29 | \item As a \code{reactive} object that returns a \code{\link[teal.data:teal_data]{teal.data::teal_data()}} object. 30 | } 31 | } 32 | \details{ 33 | \subsection{Reactive \code{teal_data}:}{ 34 | 35 | The data in the application can be reactively updated, prompting \code{\link[=srv_teal]{srv_teal()}} to rebuild the 36 | content accordingly. There are two methods for creating interactive \code{teal_data}: 37 | \enumerate{ 38 | \item Using a \code{reactive} object provided from outside the \code{teal} application. In this scenario, 39 | reactivity is controlled by an external module, and \code{srv_teal} responds to changes. 40 | \item Using \code{\link[=teal_data_module]{teal_data_module()}}, which is embedded within the \code{teal} application, allowing data to 41 | be resubmitted by the user as needed. 42 | } 43 | 44 | Since the server of \code{\link[=teal_data_module]{teal_data_module()}} must return a \code{reactive} \code{teal_data} object, both 45 | methods (1 and 2) produce the same reactive behavior within a \code{teal} application. The distinction 46 | lies in data control: the first method involves external control, while the second method 47 | involves control from a custom module within the app. 48 | 49 | For more details, see \code{\link{module_teal_data}}. 50 | } 51 | } 52 | \keyword{internal} 53 | -------------------------------------------------------------------------------- /man/module_labels.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/modules.R 3 | \name{module_labels} 4 | \alias{module_labels} 5 | \title{Retrieve labels from \code{teal_modules}} 6 | \usage{ 7 | module_labels(modules) 8 | } 9 | \arguments{ 10 | \item{modules}{(\code{teal_modules})} 11 | } 12 | \value{ 13 | A \code{list} containing the labels of the modules. If the modules are nested, 14 | the function returns a nested \code{list} of labels. 15 | } 16 | \description{ 17 | Retrieve labels from \code{teal_modules} 18 | } 19 | \keyword{internal} 20 | -------------------------------------------------------------------------------- /man/module_management.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/modules.R 3 | \name{extract_module} 4 | \alias{extract_module} 5 | \alias{drop_module} 6 | \title{Extract/Remove module(s) of specific class} 7 | \usage{ 8 | extract_module(modules, class) 9 | 10 | drop_module(modules, class) 11 | } 12 | \arguments{ 13 | \item{modules}{(\code{teal_modules})} 14 | 15 | \item{class}{The class name of \code{teal_module} to be extracted or dropped.} 16 | } 17 | \value{ 18 | \itemize{ 19 | \item For \code{extract_module}, a \code{teal_module} of class \code{class} or \code{teal_modules} containing modules of class \code{class}. 20 | \item For \code{drop_module}, the opposite, which is all \code{teal_modules} of class other than \code{class}. 21 | } 22 | 23 | \code{teal_modules} 24 | } 25 | \description{ 26 | Given a \code{teal_module} or a \code{teal_modules}, return the elements of the structure according to \code{class}. 27 | } 28 | \keyword{internal} 29 | -------------------------------------------------------------------------------- /man/module_session_info.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/module_session_info.R 3 | \name{module_session_info} 4 | \alias{module_session_info} 5 | \alias{ui_session_info} 6 | \alias{srv_session_info} 7 | \title{\code{teal} user session info module} 8 | \usage{ 9 | ui_session_info(id) 10 | 11 | srv_session_info(id) 12 | } 13 | \arguments{ 14 | \item{id}{(\code{character(1)}) \code{shiny} module instance id.} 15 | } 16 | \value{ 17 | \code{NULL} invisibly 18 | } 19 | \description{ 20 | Module to display the user session info popup and to download a lockfile. Module is included 21 | when running \code{\link[=init]{init()}} but skipped when using \code{\link{module_teal}}. Please be aware that session info 22 | contains R session information, so multiple module's calls will share the same information. 23 | } 24 | \examples{ 25 | ui <- fluidPage( 26 | ui_session_info("session_info") 27 | ) 28 | 29 | server <- function(input, output, session) { 30 | srv_session_info("session_info") 31 | } 32 | 33 | if (interactive()) { 34 | shinyApp(ui, server) 35 | } 36 | 37 | } 38 | \section{Examples in Shinylive}{ 39 | \describe{ 40 | \item{example-1}{ 41 | \href{https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKcqagSgB0ItMnGYFStAG5wABAB4AtNIBmAVwhjaJdj2kAVLAFUAogIEracxUurmAJgAUoAczjsB06eYD6AZzg+fTQgvISUiNzA-AKCQiDC+MH4IJIE-RilGS2U1DS0hVBVSXGkiQoKi6SjAkh0Qd0r0339q4NDwhKqYtoSkgF9TQSVpdiFyUXEpbVr6nwALIVYAQXR2c2K0jL6BMF6AXSA}{Open in Shinylive} 42 | \if{html}{\out{<iframe class="iframe_shinylive" src="https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKcqagSgB0ItMnGYFStAG5wABAB4AtNIBmAVwhjaJdj2kAVLAFUAogIEracxUurmAJgAUoAczjsB06eYD6AZzg+fTQgvISUiNzA-AKCQiDC+MH4IJIE-RilGS2U1DS0hVBVSXGkiQoKi6SjAkh0Qd0r0339q4NDwhKqYtoSkgF9TQSVpdiFyUXEpbVr6nwALIVYAQXR2c2K0jL6BMF6AXSA" style="height: 800px; width: 100vw; max-width: 1400px; border: 1px solid rgba(0,0,0,0.175); border-radius: .375rem; position: absolute; left: 50\%; margin-top: 30px; transform: translateX(-50\%); z-index: 1"></iframe>}} 43 | \if{html}{\out{<a style='height: 800px; display: block;'></a>}} 44 | } 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /man/module_teal.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/module_teal.R 3 | \name{module_teal} 4 | \alias{module_teal} 5 | \alias{ui_teal} 6 | \alias{srv_teal} 7 | \title{\code{teal} main module} 8 | \usage{ 9 | ui_teal(id, modules) 10 | 11 | srv_teal(id, data, modules, filter = teal_slices()) 12 | } 13 | \arguments{ 14 | \item{id}{(\code{character(1)}) \code{shiny} module instance id.} 15 | 16 | \item{modules}{(\code{teal_modules}) 17 | \code{teal_modules} object. These are the specific output modules which 18 | will be displayed in the \code{teal} application. See \code{\link[=modules]{modules()}} and \code{\link[=module]{module()}} for 19 | more details.} 20 | 21 | \item{data}{(\code{teal_data}, \code{teal_data_module}, or \code{reactive} returning \code{teal_data}) 22 | The data which application will depend on.} 23 | 24 | \item{filter}{(\code{teal_slices}) Optionally, 25 | specifies the initial filter using \code{\link[=teal_slices]{teal_slices()}}.} 26 | } 27 | \value{ 28 | \code{NULL} invisibly 29 | } 30 | \description{ 31 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 32 | Module to create a \code{teal} app as a Shiny Module. 33 | } 34 | \details{ 35 | This module can be used instead of \code{\link[=init]{init()}} in custom Shiny applications. Unlike \code{\link[=init]{init()}}, it doesn't 36 | automatically include \code{\link{module_session_info}}. 37 | 38 | Module is responsible for creating the main \code{shiny} app layout and initializing all the necessary 39 | components. This module establishes reactive connection between the input \code{data} and every other 40 | component in the app. Reactive change of the \code{data} passed as an argument, reloads the app and 41 | possibly keeps all input settings the same so the user can continue where one left off. 42 | \subsection{data flow in \code{teal} application}{ 43 | 44 | This module supports multiple data inputs but eventually, they are all converted to \code{reactive} 45 | returning \code{teal_data} in this module. On this \verb{reactive teal_data} object several actions are 46 | performed: 47 | \itemize{ 48 | \item data loading in \code{\link{module_init_data}} 49 | \item data filtering in \code{\link{module_filter_data}} 50 | \item data transformation in \code{\link{module_transform_data}} 51 | } 52 | } 53 | 54 | \subsection{Fallback on failure}{ 55 | 56 | \code{teal} is designed in such way that app will never crash if the error is introduced in any 57 | custom \code{shiny} module provided by app developer (e.g. \code{\link[=teal_data_module]{teal_data_module()}}, \code{\link[=teal_transform_module]{teal_transform_module()}}). 58 | If any module returns a failing object, the app will halt the evaluation and display a warning message. 59 | App user should always have a chance to fix the improper input and continue without restarting the session. 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /man/module_teal_data.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/module_teal_data.R 3 | \name{module_teal_data} 4 | \alias{module_teal_data} 5 | \alias{ui_teal_data_module} 6 | \alias{ui_teal_data} 7 | \alias{srv_teal_data_module} 8 | \alias{srv_teal_data} 9 | \alias{ui_validate_reactive_teal_data} 10 | \alias{srv_validate_reactive_teal_data} 11 | \title{Execute and validate \code{teal_data_module}} 12 | \usage{ 13 | ui_teal_data_module(id, data_module = function(id) NULL) 14 | 15 | srv_teal_data_module( 16 | id, 17 | data_module = function(id) NULL, 18 | modules = NULL, 19 | validate_shiny_silent_error = TRUE, 20 | is_transform_failed = reactiveValues() 21 | ) 22 | 23 | ui_validate_reactive_teal_data(id) 24 | 25 | srv_validate_reactive_teal_data( 26 | id, 27 | data, 28 | modules = NULL, 29 | validate_shiny_silent_error = FALSE, 30 | hide_validation_error = reactive(FALSE) 31 | ) 32 | } 33 | \arguments{ 34 | \item{id}{(\code{character(1)}) \code{shiny} module instance id.} 35 | 36 | \item{data_module}{(\code{teal_data_module})} 37 | 38 | \item{modules}{(\code{teal_modules} or \code{teal_module}) For \code{datanames} validation purpose} 39 | 40 | \item{validate_shiny_silent_error}{(\code{logical}) If \code{TRUE}, then \code{shiny.silent.error} is validated and} 41 | 42 | \item{is_transform_failed}{(\code{reactiveValues}) contains \code{logical} flags named after each transformator. 43 | Help to determine if any previous transformator failed, so that following transformators can be disabled 44 | and display a generic failure message.} 45 | 46 | \item{data}{(\code{reactive} returning \code{teal_data})} 47 | } 48 | \value{ 49 | \code{reactive} \code{teal_data} 50 | } 51 | \description{ 52 | This is a low level module to handle \code{teal_data_module} execution and validation. 53 | \code{\link[=teal_transform_module]{teal_transform_module()}} inherits from \code{\link[=teal_data_module]{teal_data_module()}} so it is handled by this module too. 54 | \code{\link[=srv_teal]{srv_teal()}} accepts various \code{data} objects and eventually they are all transformed to \code{reactive} 55 | \code{\link[teal.data:teal_data]{teal.data::teal_data()}} which is a standard data class in whole \code{teal} framework. 56 | } 57 | \note{ 58 | \code{ui_teal_data_module} was renamed from \code{ui_teal_data}. 59 | 60 | \code{srv_teal_data_module} was renamed from \code{srv_teal_data}. 61 | } 62 | \section{data validation}{ 63 | 64 | 65 | Executed \code{\link[=teal_data_module]{teal_data_module()}} is validated and output is validated for consistency. 66 | Output \code{data} is invalid if: 67 | \enumerate{ 68 | \item \code{\link[=teal_data_module]{teal_data_module()}} is invalid if server doesn't return \code{reactive}. \strong{Immediately crashes an app!} 69 | \item \code{reactive} throws a \code{shiny.error} - happens when module creating \code{\link[teal.data:teal_data]{teal.data::teal_data()}} fails. 70 | \item \code{reactive} returns \code{qenv.error} - happens when \code{\link[teal.data:teal_data]{teal.data::teal_data()}} evaluates a failing code. 71 | \item \code{reactive} object doesn't return \code{\link[teal.data:teal_data]{teal.data::teal_data()}}. 72 | \item \code{\link[teal.data:teal_data]{teal.data::teal_data()}} object lacks any \code{datanames} specified in the \code{modules} argument. 73 | } 74 | 75 | \code{teal} (observers in \code{srv_teal}) always waits to render an app until \code{reactive} \code{teal_data} is 76 | returned. If error 2-4 occurs, relevant error message is displayed to the app user. Once the issue is 77 | resolved, the app will continue to run. \code{teal} guarantees that errors in data don't crash the app 78 | (except error 1). 79 | } 80 | 81 | \keyword{internal} 82 | -------------------------------------------------------------------------------- /man/module_teal_lockfile.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/module_teal_lockfile.R 3 | \name{module_teal_lockfile} 4 | \alias{module_teal_lockfile} 5 | \alias{ui_teal_lockfile} 6 | \alias{srv_teal_lockfile} 7 | \alias{.teal_lockfile_process_invoke} 8 | \alias{.renv_snapshot} 9 | \alias{.is_lockfile_deps_installed} 10 | \alias{.is_disabled_lockfile_scenario} 11 | \title{Generate lockfile for application's environment reproducibility} 12 | \usage{ 13 | ui_teal_lockfile(id) 14 | 15 | srv_teal_lockfile(id) 16 | 17 | .teal_lockfile_process_invoke(lockfile_path) 18 | 19 | .renv_snapshot(lockfile_path) 20 | 21 | .is_lockfile_deps_installed() 22 | 23 | .is_disabled_lockfile_scenario() 24 | } 25 | \arguments{ 26 | \item{id}{(\code{character(1)}) \code{shiny} module instance id.} 27 | 28 | \item{lockfile_path}{(\code{character}) path to the lockfile.} 29 | } 30 | \value{ 31 | \code{NULL} 32 | } 33 | \description{ 34 | Generate lockfile for application's environment reproducibility 35 | } 36 | \section{Different ways of creating lockfile}{ 37 | 38 | \code{teal} leverages \code{\link[renv:snapshot]{renv::snapshot()}}, which offers multiple methods for lockfile creation. 39 | \itemize{ 40 | \item \strong{Working directory lockfile}: \code{teal}, by default, will create an \code{implicit} type lockfile that uses 41 | \code{renv::dependencies()} to detect all R packages in the current project's working directory. 42 | \item \strong{\code{DESCRIPTION}-based lockfile}: To generate a lockfile based on a \code{DESCRIPTION} file in your working 43 | directory, set \code{renv::settings$snapshot.type("explicit")}. The naming convention for \code{type} follows 44 | \code{renv::snapshot()}. For the \code{"explicit"} type, refer to \code{renv::settings$package.dependency.fields()} for the 45 | \code{DESCRIPTION} fields included in the lockfile. 46 | \item \strong{Custom files-based lockfile}: To specify custom files as the basis for the lockfile, set 47 | \code{renv::settings$snapshot.type("custom")} and configure the \code{renv.snapshot.filter} option. 48 | } 49 | } 50 | 51 | \section{lockfile usage}{ 52 | 53 | After creating the lockfile, you can restore the application's environment using \code{renv::restore()}. 54 | } 55 | 56 | \seealso{ 57 | \code{\link[renv:snapshot]{renv::snapshot()}}, \code{\link[renv:restore]{renv::restore()}}. 58 | } 59 | \keyword{internal} 60 | -------------------------------------------------------------------------------- /man/module_teal_with_splash.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/module_teal_with_splash.R 3 | \name{module_teal_with_splash} 4 | \alias{module_teal_with_splash} 5 | \alias{ui_teal_with_splash} 6 | \alias{srv_teal_with_splash} 7 | \title{UI and server modules of \code{teal}} 8 | \usage{ 9 | ui_teal_with_splash( 10 | id, 11 | data, 12 | modules, 13 | title = build_app_title(), 14 | header = tags$p(), 15 | footer = tags$p() 16 | ) 17 | 18 | srv_teal_with_splash(id, data, modules, filter = teal_slices()) 19 | } 20 | \arguments{ 21 | \item{id}{(\code{character(1)}) \code{shiny} module instance id.} 22 | 23 | \item{data}{(\code{teal_data}, \code{teal_data_module}, or \code{reactive} returning \code{teal_data}) 24 | The data which application will depend on.} 25 | 26 | \item{modules}{(\code{teal_modules}) 27 | \code{teal_modules} object. These are the specific output modules which 28 | will be displayed in the \code{teal} application. See \code{\link[=modules]{modules()}} and \code{\link[=module]{module()}} for 29 | more details.} 30 | 31 | \item{title}{(\code{shiny.tag} or \code{character(1)}) \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Optionally, 32 | the browser window title. Defaults to a title "teal app" with the icon of NEST. 33 | Can be created using the \code{build_app_title()} or 34 | by passing a valid \code{shiny.tag} which is a head tag with title and link tag. 35 | This parameter is no longer supported. Use \code{modify_title()} on the teal app object instead.} 36 | 37 | \item{header}{(\code{shiny.tag} or \code{character(1)}) \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Optionally, 38 | the header of the app. 39 | This parameter is no longer supported. Use \code{modify_header()} on the teal app object instead.} 40 | 41 | \item{footer}{(\code{shiny.tag} or \code{character(1)}) \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Optionally, 42 | the footer of the app. 43 | This parameter is no longer supported. Use \code{modify_footer()} on the teal app object instead.} 44 | 45 | \item{filter}{(\code{teal_slices}) Optionally, 46 | specifies the initial filter using \code{\link[=teal_slices]{teal_slices()}}.} 47 | } 48 | \value{ 49 | Returns a \code{reactive} expression containing a \code{teal_data} object when data is loaded or \code{NULL} when it is not. 50 | } 51 | \description{ 52 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} 53 | Please use \code{\link{module_teal}} instead. 54 | } 55 | -------------------------------------------------------------------------------- /man/module_transform_data.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/module_transform_data.R 3 | \name{module_transform_data} 4 | \alias{module_transform_data} 5 | \alias{ui_transform_teal_data} 6 | \alias{srv_transform_teal_data} 7 | \title{Module to transform \code{reactive} \code{teal_data}} 8 | \usage{ 9 | ui_transform_teal_data(id, transformators, class = "well") 10 | 11 | srv_transform_teal_data( 12 | id, 13 | data, 14 | transformators, 15 | modules = NULL, 16 | is_transform_failed = reactiveValues() 17 | ) 18 | } 19 | \arguments{ 20 | \item{id}{(\code{character(1)}) \code{shiny} module instance id.} 21 | 22 | \item{transformators}{(\code{list} of \code{teal_transform_module}) that will be applied to transform module's data input. 23 | To learn more check \code{vignette("transform-input-data", package = "teal")}.} 24 | 25 | \item{class}{(character(1)) CSS class to be added in the \code{div} wrapper tag.} 26 | 27 | \item{data}{(\code{reactive} returning \code{teal_data})} 28 | 29 | \item{modules}{(\code{teal_modules} or \code{teal_module}) For \code{datanames} validation purpose} 30 | 31 | \item{is_transform_failed}{(\code{reactiveValues}) contains \code{logical} flags named after each transformator. 32 | Help to determine if any previous transformator failed, so that following transformators can be disabled 33 | and display a generic failure message.} 34 | } 35 | \value{ 36 | \code{reactive} \code{teal_data} 37 | } 38 | \description{ 39 | Module calls \code{\link[=teal_transform_module]{teal_transform_module()}} in sequence so that \verb{reactive teal_data} output 40 | from one module is handed over to the following module's input. 41 | } 42 | -------------------------------------------------------------------------------- /man/modules_bookmarkable.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/modules.R 3 | \name{modules_bookmarkable} 4 | \alias{modules_bookmarkable} 5 | \title{Retrieve \code{teal_bookmarkable} attribute from \code{teal_modules}} 6 | \usage{ 7 | modules_bookmarkable(modules) 8 | } 9 | \arguments{ 10 | \item{modules}{(\code{teal_modules} or \code{teal_module}) object} 11 | } 12 | \value{ 13 | named list of the same structure as \code{modules} with \code{TRUE} or \code{FALSE} values indicating 14 | whether the module is bookmarkable. 15 | } 16 | \description{ 17 | Retrieve \code{teal_bookmarkable} attribute from \code{teal_modules} 18 | } 19 | \keyword{internal} 20 | -------------------------------------------------------------------------------- /man/modules_depth.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/modules.R 3 | \name{modules_depth} 4 | \alias{modules_depth} 5 | \title{Get module depth} 6 | \usage{ 7 | modules_depth(modules, depth = 0L) 8 | } 9 | \arguments{ 10 | \item{modules}{(\code{list} or \code{teal_modules} or \code{teal_module}) 11 | Nested list of \code{teal_modules} or \code{teal_module} objects or a single 12 | \code{teal_modules} or \code{teal_module} object. These are the specific output modules which 13 | will be displayed in the \code{teal} application. See \code{\link[=modules]{modules()}} and \code{\link[=module]{module()}} for 14 | more details.} 15 | 16 | \item{depth}{optional integer determining current depth level} 17 | } 18 | \value{ 19 | Depth level for given module. 20 | } 21 | \description{ 22 | Depth starts at 0, so a single \code{teal.module} has depth 0. 23 | Nesting it increases overall depth by 1. 24 | } 25 | \keyword{internal} 26 | -------------------------------------------------------------------------------- /man/pluralize.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{pluralize} 4 | \alias{pluralize} 5 | \title{Pluralize a word depending on the size of the input} 6 | \usage{ 7 | pluralize(x, singular, plural = NULL) 8 | } 9 | \arguments{ 10 | \item{x}{(\code{object}) to check length for plural.} 11 | 12 | \item{singular}{(\code{character}) singular form of the word.} 13 | 14 | \item{plural}{(optional \code{character}) plural form of the word. If not given an "s" 15 | is added to the singular form.} 16 | } 17 | \value{ 18 | A \code{character} that correctly represents the size of the \code{x} argument. 19 | } 20 | \description{ 21 | Pluralize a word depending on the size of the input 22 | } 23 | \keyword{internal} 24 | -------------------------------------------------------------------------------- /man/report_card_template.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{report_card_template} 4 | \alias{report_card_template} 5 | \title{Template function for \code{TealReportCard} creation and customization} 6 | \usage{ 7 | report_card_template( 8 | title, 9 | label, 10 | description = NULL, 11 | with_filter, 12 | filter_panel_api 13 | ) 14 | } 15 | \arguments{ 16 | \item{title}{(\code{character(1)}) title of the card (unless overwritten by label)} 17 | 18 | \item{label}{(\code{character(1)}) label provided by the user when adding the card} 19 | 20 | \item{description}{(\code{character(1)}) optional, additional description} 21 | 22 | \item{with_filter}{(\code{logical(1)}) flag indicating to add filter state} 23 | 24 | \item{filter_panel_api}{(\code{FilterPanelAPI}) object with API that allows the generation 25 | of the filter state in the report} 26 | } 27 | \value{ 28 | (\code{TealReportCard}) populated with a title, description and filter state. 29 | } 30 | \description{ 31 | This function generates a report card with a title, 32 | an optional description, and the option to append the filter state list. 33 | } 34 | -------------------------------------------------------------------------------- /man/reporter_previewer_module.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/reporter_previewer_module.R 3 | \name{reporter_previewer_module} 4 | \alias{reporter_previewer_module} 5 | \title{Create a \code{teal} module for previewing a report} 6 | \usage{ 7 | reporter_previewer_module(label = "Report previewer", server_args = list()) 8 | } 9 | \arguments{ 10 | \item{label}{(\code{character(1)}) Label shown in the navigation item for the module or module group. 11 | For \code{modules()} defaults to \code{"root"}. See \code{Details}.} 12 | 13 | \item{server_args}{(named \code{list}) 14 | Arguments passed to \code{\link[teal.reporter:reporter_previewer]{teal.reporter::reporter_previewer_srv()}}.} 15 | } 16 | \value{ 17 | \code{teal_module} (extended with \code{teal_module_previewer} class) containing the \code{teal.reporter} previewer functionality. 18 | } 19 | \description{ 20 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} 21 | 22 | This function wraps \code{\link[teal.reporter:reporter_previewer]{teal.reporter::reporter_previewer_ui()}} and 23 | \code{\link[teal.reporter:reporter_previewer]{teal.reporter::reporter_previewer_srv()}} into a \code{teal_module} to be 24 | used in \code{teal} applications. 25 | 26 | If you are creating a \code{teal} application using \code{\link[=init]{init()}} then this 27 | module will be added to your application automatically if any of your \code{teal_modules} 28 | support report generation. 29 | } 30 | -------------------------------------------------------------------------------- /man/restoreValue.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/module_bookmark_manager.R 3 | \name{restoreValue} 4 | \alias{restoreValue} 5 | \title{Restore value from bookmark.} 6 | \usage{ 7 | restoreValue(value, default) 8 | } 9 | \arguments{ 10 | \item{value}{(\code{character(1)}) name of value to restore} 11 | 12 | \item{default}{fallback value} 13 | } 14 | \value{ 15 | In an application restored from a server-side bookmark, 16 | the variable specified by \code{value} from the \code{values} environment. 17 | Otherwise \code{default}. 18 | } 19 | \description{ 20 | Get value from bookmark or return default. 21 | } 22 | \details{ 23 | Bookmarks can store not only inputs but also arbitrary values. 24 | These values are stored by \code{onBookmark} callbacks and restored by \code{onBookmarked} callbacks, 25 | and they are placed in the \code{values} environment in the \code{session$restoreContext} field. 26 | Using \code{teal_data_module} makes it impossible to run the callbacks 27 | because the app becomes ready before modules execute and callbacks are registered. 28 | In those cases the stored values can still be recovered from the \code{session} object directly. 29 | 30 | Note that variable names in the \code{values} environment are prefixed with module name space names, 31 | therefore, when using this function in modules, \code{value} must be run through the name space function. 32 | } 33 | \keyword{internal} 34 | -------------------------------------------------------------------------------- /man/run_js_files.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/include_css_js.R 3 | \name{run_js_files} 4 | \alias{run_js_files} 5 | \title{Run \code{JS} file from \verb{/inst/js/} package directory} 6 | \usage{ 7 | run_js_files(files) 8 | } 9 | \arguments{ 10 | \item{files}{(\code{character}) vector of filenames.} 11 | } 12 | \value{ 13 | \code{NULL}, invisibly. 14 | } 15 | \description{ 16 | This is triggered from the server to execute on the client 17 | rather than triggered directly on the client. 18 | Unlike \code{include_js_files} which includes \code{JavaScript} functions, 19 | the \code{run_js} actually executes \code{JavaScript} functions. 20 | } 21 | \details{ 22 | \code{system.file} should not be used to access files in other packages, it does 23 | not work with \code{devtools}. Therefore, we redefine this method in each package 24 | as needed. Thus, we do not export this method. 25 | } 26 | \keyword{internal} 27 | -------------------------------------------------------------------------------- /man/show_rcode_modal.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/show_rcode_modal.R 3 | \name{show_rcode_modal} 4 | \alias{show_rcode_modal} 5 | \title{Show \code{R} code modal} 6 | \usage{ 7 | show_rcode_modal(title = NULL, rcode, session = getDefaultReactiveDomain()) 8 | } 9 | \arguments{ 10 | \item{title}{(\code{character(1)}) 11 | Title of the modal, displayed in the first comment of the \code{R} code.} 12 | 13 | \item{rcode}{(\code{character}) 14 | vector with \code{R} code to show inside the modal.} 15 | 16 | \item{session}{(\code{ShinySession}) optional 17 | \code{shiny} session object, defaults to \code{\link[shiny:domains]{shiny::getDefaultReactiveDomain()}}.} 18 | } 19 | \description{ 20 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} 21 | 22 | Use the \code{\link[shiny:showModal]{shiny::showModal()}} function to show the \code{R} code inside. 23 | } 24 | \references{ 25 | \code{\link[shiny:showModal]{shiny::showModal()}} 26 | } 27 | -------------------------------------------------------------------------------- /man/slices_store.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/teal_slices-store.R 3 | \name{slices_store} 4 | \alias{slices_store} 5 | \alias{slices_restore} 6 | \title{Store and restore \code{teal_slices} object} 7 | \usage{ 8 | slices_store(tss, file) 9 | 10 | slices_restore(file) 11 | } 12 | \arguments{ 13 | \item{tss}{(\code{teal_slices}) object to be stored.} 14 | 15 | \item{file}{(\code{character(1)}) file path where \code{teal_slices} object will be 16 | saved and restored. The file extension should be \code{".json"}.} 17 | } 18 | \value{ 19 | \code{slices_store} returns \code{NULL}, invisibly. 20 | 21 | \code{slices_restore} returns a \code{teal_slices} object restored from the file. 22 | } 23 | \description{ 24 | Functions that write a \code{teal_slices} object to a file in the \code{JSON} format, 25 | and also restore the object from disk. 26 | } 27 | \details{ 28 | Date and date time objects are stored in the following formats: 29 | \itemize{ 30 | \item \code{Date} class is converted to the \code{"ISO8601"} standard (\code{YYYY-MM-DD}). 31 | \item \code{POSIX*t} classes are converted to character by using 32 | \code{format.POSIX*t(usetz = TRUE, tz = "UTC")} (\verb{YYYY-MM-DD HH:MM:SS UTC}, where 33 | \code{UTC} is the \verb{Coordinated Universal Time} timezone short-code). 34 | } 35 | 36 | This format is assumed during \code{slices_restore}. All \code{POSIX*t} objects in 37 | \code{selected} or \code{choices} fields of \code{teal_slice} objects are always printed in 38 | \code{UTC} timezone as well. 39 | } 40 | \seealso{ 41 | \code{\link[=teal_slices]{teal_slices()}} 42 | } 43 | \keyword{internal} 44 | -------------------------------------------------------------------------------- /man/tdata.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tdata.R 3 | \name{tdata} 4 | \alias{tdata} 5 | \alias{new_tdata} 6 | \alias{tdata2env} 7 | \alias{get_code_tdata} 8 | \alias{join_keys.tdata} 9 | \alias{get_metadata} 10 | \alias{as_tdata} 11 | \title{Create a \code{tdata} object} 12 | \usage{ 13 | new_tdata(...) 14 | 15 | tdata2env(...) 16 | 17 | get_code_tdata(...) 18 | 19 | \method{join_keys}{tdata}(...) 20 | 21 | get_metadata(...) 22 | 23 | as_tdata(...) 24 | } 25 | \arguments{ 26 | \item{...}{ignored} 27 | } 28 | \value{ 29 | nothing 30 | } 31 | \description{ 32 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\strong{[Superseded]}} 33 | 34 | Recent changes in \code{teal} cause modules to fail because modules expect a \code{tdata} object 35 | to be passed to the \code{data} argument but instead they receive a \code{teal_data} object, 36 | which is additionally wrapped in a reactive expression in the server functions. 37 | In order to easily adapt such modules without a proper refactor, 38 | use this function to downgrade the \code{data} argument. 39 | } 40 | -------------------------------------------------------------------------------- /man/teal-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/teal.R 3 | \docType{package} 4 | \name{teal-package} 5 | \alias{teal} 6 | \alias{teal-package} 7 | \title{\code{teal}: Interactive exploration of clinical trials data} 8 | \description{ 9 | The \code{teal} package provides a \code{shiny} based framework for creating an 10 | interactive data analysis environment. 11 | } 12 | \details{ 13 | To learn mode about the package, visit the \href{https://insightsengineering.github.io/teal/latest-tag/}{project website} 14 | or read the \code{\link[=init]{init()}} manual page. 15 | } 16 | \seealso{ 17 | Useful links: 18 | \itemize{ 19 | \item \url{https://insightsengineering.github.io/teal/} 20 | \item \url{https://github.com/insightsengineering/teal/} 21 | \item Report bugs at \url{https://github.com/insightsengineering/teal/issues} 22 | } 23 | 24 | } 25 | \author{ 26 | \strong{Maintainer}: Dawid Kaledkowski \email{dawid.kaledkowski@roche.com} (\href{https://orcid.org/0000-0001-9533-457X}{ORCID}) 27 | 28 | Authors: 29 | \itemize{ 30 | \item Pawel Rucki \email{pawel.rucki@roche.com} 31 | \item Aleksander Chlebowski \email{aleksander.chlebowski@contractors.roche.com} (\href{https://orcid.org/0000-0001-5018-6294}{ORCID}) 32 | \item Andre Verissimo \email{andre.verissimo@roche.com} (\href{https://orcid.org/0000-0002-2212-339X}{ORCID}) 33 | \item Kartikeya Kirar \email{kartikeya.kirar@businesspartner.roche.com} 34 | \item Vedha Viyash \email{vedha.viyash@roche.com} 35 | \item Marcin Kosinski \email{marcin.kosinski.mk1@roche.com} 36 | \item Adrian Waddell \email{adrian.waddell@gene.com} 37 | \item Nikolas Burkoff 38 | \item Mahmoud Hallal 39 | \item Maciej Nasinski 40 | \item Konrad Pagacz 41 | \item Junlue Zhao 42 | \item Tadeusz Lewandowski 43 | } 44 | 45 | Other contributors: 46 | \itemize{ 47 | \item Chendi Liao \email{chendi.liao@roche.com} [reviewer] 48 | \item Dony Unardi \email{unardid@gene.com} [reviewer] 49 | \item F. Hoffmann-La Roche AG [copyright holder, funder] 50 | \item Maximilian Mordig [contributor] 51 | } 52 | 53 | } 54 | \keyword{internal} 55 | -------------------------------------------------------------------------------- /man/teal_data_to_filtered_data.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{teal_data_to_filtered_data} 4 | \alias{teal_data_to_filtered_data} 5 | \title{Create a \code{FilteredData}} 6 | \usage{ 7 | teal_data_to_filtered_data(x, datanames = names(x)) 8 | } 9 | \arguments{ 10 | \item{x}{(\code{teal_data}) object} 11 | 12 | \item{datanames}{(\code{character}) vector of data set names to include; must be subset of \code{names(x)}} 13 | } 14 | \value{ 15 | A \code{FilteredData} object. 16 | } 17 | \description{ 18 | Create a \code{FilteredData} object from a \code{teal_data} object. 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /man/teal_data_utilities.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/teal_data_utils.R 3 | \name{teal_data_utilities} 4 | \alias{teal_data_utilities} 5 | \alias{.append_evaluated_code} 6 | \alias{.append_modified_data} 7 | \title{\code{teal_data} utils} 8 | \usage{ 9 | .append_evaluated_code(data, code) 10 | 11 | .append_modified_data(data, objects) 12 | } 13 | \arguments{ 14 | \item{data}{(\code{teal_data})} 15 | 16 | \item{code}{(\code{character}) code to append to the object's code slot.} 17 | 18 | \item{objects}{(\code{list}) objects to append to object's environment.} 19 | } 20 | \value{ 21 | modified \code{teal_data} 22 | } 23 | \description{ 24 | In \code{teal} we need to recreate the \code{teal_data} object due to two operations: 25 | \itemize{ 26 | \item we need to append filter-data code and objects which have been evaluated in \code{FilteredData} and 27 | we want to avoid double-evaluation. 28 | \item we need to subset \code{teal_data} to \code{datanames} used by the module, to shorten obtainable R-code 29 | } 30 | } 31 | \details{ 32 | Due to above recreation of \code{teal_data} object can't be done simply by using public 33 | \code{teal.code} and \code{teal.data} methods. 34 | } 35 | \keyword{internal} 36 | -------------------------------------------------------------------------------- /man/teal_extend_server.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/teal_modifiers.R 3 | \name{teal_extend_server} 4 | \alias{teal_extend_server} 5 | \title{Add a Custom Server Logic to \code{teal} Application} 6 | \usage{ 7 | teal_extend_server(x, custom_server, module_id = character(0)) 8 | } 9 | \arguments{ 10 | \item{x}{(\code{teal_app}) A \code{teal_app} object created using the \code{init} function.} 11 | 12 | \item{custom_server}{(\verb{function(input, output, session)} or \verb{function(id, ...)}) 13 | The custom server function or server module to set.} 14 | 15 | \item{module_id}{(\code{character(1)}) The ID of the module when a module server function is passed.} 16 | } 17 | \description{ 18 | Adds a custom server function to the \code{teal} app. This function can define additional server logic. 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /man/validate_app_title_tag.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{validate_app_title_tag} 4 | \alias{validate_app_title_tag} 5 | \title{Function for validating the title parameter of \code{teal::init}} 6 | \usage{ 7 | validate_app_title_tag(shiny_tag) 8 | } 9 | \arguments{ 10 | \item{shiny_tag}{(\code{shiny.tag}) Object to validate for a valid title.} 11 | } 12 | \description{ 13 | Checks if the input of the title from \code{teal::init} will create a valid title and favicon tag. 14 | } 15 | \keyword{internal} 16 | -------------------------------------------------------------------------------- /man/validate_has_data.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/validations.R 3 | \name{validate_has_data} 4 | \alias{validate_has_data} 5 | \title{Validate that dataset has a minimum number of observations} 6 | \usage{ 7 | validate_has_data( 8 | x, 9 | min_nrow = NULL, 10 | complete = FALSE, 11 | allow_inf = TRUE, 12 | msg = NULL 13 | ) 14 | } 15 | \arguments{ 16 | \item{x}{(\code{data.frame})} 17 | 18 | \item{min_nrow}{(\code{numeric(1)}) Minimum allowed number of rows in \code{x}.} 19 | 20 | \item{complete}{(\code{logical(1)}) Flag specifying whether to check only complete cases. Defaults to \code{FALSE}.} 21 | 22 | \item{allow_inf}{(\code{logical(1)}) Flag specifying whether to allow infinite values. Defaults to \code{TRUE}.} 23 | 24 | \item{msg}{(\code{character(1)}) Additional message to display alongside the default message.} 25 | } 26 | \description{ 27 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 28 | } 29 | \details{ 30 | This function is a wrapper for \code{shiny::validate}. 31 | } 32 | \examples{ 33 | library(teal) 34 | ui <- fluidPage( 35 | sliderInput("len", "Max Length of Sepal", 36 | min = 4.3, max = 7.9, value = 5 37 | ), 38 | plotOutput("plot") 39 | ) 40 | 41 | server <- function(input, output) { 42 | output$plot <- renderPlot({ 43 | iris_df <- iris[iris$Sepal.Length <= input$len, ] 44 | validate_has_data( 45 | iris_df, 46 | min_nrow = 10, 47 | complete = FALSE, 48 | msg = "Please adjust Max Length of Sepal" 49 | ) 50 | 51 | hist(iris_df$Sepal.Length, breaks = 5) 52 | }) 53 | } 54 | if (interactive()) { 55 | shinyApp(ui, server) 56 | } 57 | 58 | } 59 | \section{Examples in Shinylive}{ 60 | \describe{ 61 | \item{example-1}{ 62 | \href{https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKcqagSgB0ItMnGYFStAG5wABAB4AtNIBmAVwhjaJdj2kAVLAFUAogIF0mLDl14CVtOYqXU7AEwAKUAOZx2A6dIBnOhcRAEkIVBVSXxoKPjxpeIBZKAAPaQAZCk9SAAtpIiVpAGU4VG543D9-aRghaQBeaQAWDABmXFq0xukAdgwATk6JbhUZJoBWap4qiH9UaiJSAHkoyOj4haX4-ghdgQCRKUYHZTUNLSF1zqI1qJ0QatvSdYASLdJTxgoQxjdF6KPOY1WiMWgBAD6LiKCmkoPBwHhAVepXK1AwWQgOXysiaVyir2oFE6AF1qv4RsEoOQIbkoJCXNSoL5gTU4WCGUpZmz-HUIBCIIwiAB3HoARgADNyecQYAs4OQegAxACCGWKRmlbJgAU8PXi-zg9JkUBcACsVAFPil0pjsQUiqiKmBydJ9qzpLlwdEkVClCiytwMdk8p0mEaANYBHoTXb+AC+u3jAloRXYQnIonEUm0D2qAS9EFYKvQ7DsnUOjGOSYEYHjJKAA}{Open in Shinylive} 63 | \if{html}{\out{<iframe class="iframe_shinylive" src="https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKcqagSgB0ItMnGYFStAG5wABAB4AtNIBmAVwhjaJdj2kAVLAFUAogIF0mLDl14CVtOYqXU7AEwAKUAOZx2A6dIBnOhcRAEkIVBVSXxoKPjxpeIBZKAAPaQAZCk9SAAtpIiVpAGU4VG543D9-aRghaQBeaQAWDABmXFq0xukAdgwATk6JbhUZJoBWap4qiH9UaiJSAHkoyOj4haX4-ghdgQCRKUYHZTUNLSF1zqI1qJ0QatvSdYASLdJTxgoQxjdF6KPOY1WiMWgBAD6LiKCmkoPBwHhAVepXK1AwWQgOXysiaVyir2oFE6AF1qv4RsEoOQIbkoJCXNSoL5gTU4WCGUpZmz-HUIBCIIwiAB3HoARgADNyecQYAs4OQegAxACCGWKRmlbJgAU8PXi-zg9JkUBcACsVAFPil0pjsQUiqiKmBydJ9qzpLlwdEkVClCiytwMdk8p0mEaANYBHoTXb+AC+u3jAloRXYQnIonEUm0D2qAS9EFYKvQ7DsnUOjGOSYEYHjJKAA" style="height: 800px; width: 100vw; max-width: 1400px; border: 1px solid rgba(0,0,0,0.175); border-radius: .375rem; position: absolute; left: 50\%; margin-top: 30px; transform: translateX(-50\%); z-index: 1"></iframe>}} 64 | \if{html}{\out{<a style='height: 800px; display: block;'></a>}} 65 | } 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /man/validate_has_elements.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/validations.R 3 | \name{validate_has_elements} 4 | \alias{validate_has_elements} 5 | \title{Validates that vector has length greater than 0} 6 | \usage{ 7 | validate_has_elements(x, msg) 8 | } 9 | \arguments{ 10 | \item{x}{vector} 11 | 12 | \item{msg}{message to display} 13 | } 14 | \description{ 15 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 16 | } 17 | \details{ 18 | This function is a wrapper for \code{shiny::validate}. 19 | } 20 | \examples{ 21 | data <- data.frame( 22 | id = c(1:10, 11:20, 1:10), 23 | strata = rep(c("A", "B"), each = 15) 24 | ) 25 | ui <- fluidPage( 26 | selectInput("ref1", "Select strata1 to compare", 27 | choices = c("A", "B", "C"), selected = "A" 28 | ), 29 | selectInput("ref2", "Select strata2 to compare", 30 | choices = c("A", "B", "C"), selected = "B" 31 | ), 32 | verbatimTextOutput("arm_summary") 33 | ) 34 | 35 | server <- function(input, output) { 36 | output$arm_summary <- renderText({ 37 | sample_1 <- data$id[data$strata == input$ref1] 38 | sample_2 <- data$id[data$strata == input$ref2] 39 | 40 | validate_has_elements(sample_1, "No subjects in strata1.") 41 | validate_has_elements(sample_2, "No subjects in strata2.") 42 | 43 | paste0( 44 | "Number of samples in: strata1=", length(sample_1), 45 | " comparions strata2=", length(sample_2) 46 | ) 47 | }) 48 | } 49 | if (interactive()) { 50 | shinyApp(ui, server) 51 | } 52 | } 53 | \section{Examples in Shinylive}{ 54 | \describe{ 55 | \item{example-1}{ 56 | \href{https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKcqagSgB0ItMnGYFStAG5wABAB4AtNIBmAVwhjaJdj2kAVLAFUAogIEATKKShzFFqxiXN47AdOm0z0gLzSC7AIyI-gAMuNL+gQBMoeFBwTy4rtIAzqTMVt7SjHCo7H58YACCBWEFAEIFCdJwUAQAFpn+AKz8EK0qtDbK1B1mAApQAOZwLhBuyXDUcGIAkhCoKqQuYNlK-iXSBQDKk9OkKWmWUP7SpES+RDCoLHAlSW71RLQEcMmZ+UUb5V9gAMKVYQmUzEcE8PgKxTASQSSSBezmCyWBVWkR+O2B+1S6SgkVO52IVxudzGbl8dSeLzePg+kNKYAqeE2fwBKV2ILBTIZ0MSJKkjHolloMF0cAAHqQAPKLRHLFgwAD6yRUMBgLFYlQErQEE0YfK6qnU4i0QkRYSI0sWOhASXNpERABI5Yrlaq2F1shAzCIReL2NaSeNYKgpvKTgppHYoPaPMBI-asUdvD4TYt7at-ABde4pIMh3HhuMxuMJjJeZPzVMorMQbMSbgeSxweV1KDJeW7eBkZLsZK5pv+OkAOXOSvoACs9m8hAdsf4MBqA9I63Q7E2W22OxRSN3e1c80ORypx5P3GMSzj52AtYvrqk4MFRqTSQVB8r6CJpEQlDm969T4gZyOfwvA2KYIEGUg6h7PtQxhRc3AKC5CUYTQIDec9IhAxkwIgqDd2DJtIlaJ9iOkABfVoyIEWhv3YIRyFEcQpG0K1YTqIRWEKdB2A6QERD5SiwDIjMgA}{Open in Shinylive} 57 | \if{html}{\out{<iframe class="iframe_shinylive" src="https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKcqagSgB0ItMnGYFStAG5wABAB4AtNIBmAVwhjaJdj2kAVLAFUAogIEATKKShzFFqxiXN47AdOm0z0gLzSC7AIyI-gAMuNL+gQBMoeFBwTy4rtIAzqTMVt7SjHCo7H58YACCBWEFAEIFCdJwUAQAFpn+AKz8EK0qtDbK1B1mAApQAOZwLhBuyXDUcGIAkhCoKqQuYNlK-iXSBQDKk9OkKWmWUP7SpES+RDCoLHAlSW71RLQEcMmZ+UUb5V9gAMKVYQmUzEcE8PgKxTASQSSSBezmCyWBVWkR+O2B+1S6SgkVO52IVxudzGbl8dSeLzePg+kNKYAqeE2fwBKV2ILBTIZ0MSJKkjHolloMF0cAAHqQAPKLRHLFgwAD6yRUMBgLFYlQErQEE0YfK6qnU4i0QkRYSI0sWOhASXNpERABI5Yrlaq2F1shAzCIReL2NaSeNYKgpvKTgppHYoPaPMBI-asUdvD4TYt7at-ABde4pIMh3HhuMxuMJjJeZPzVMorMQbMSbgeSxweV1KDJeW7eBkZLsZK5pv+OkAOXOSvoACs9m8hAdsf4MBqA9I63Q7E2W22OxRSN3e1c80ORypx5P3GMSzj52AtYvrqk4MFRqTSQVB8r6CJpEQlDm969T4gZyOfwvA2KYIEGUg6h7PtQxhRc3AKC5CUYTQIDec9IhAxkwIgqDd2DJtIlaJ9iOkABfVoyIEWhv3YIRyFEcQpG0K1YTqIRWEKdB2A6QERD5SiwDIjMgA" style="height: 800px; width: 100vw; max-width: 1400px; border: 1px solid rgba(0,0,0,0.175); border-radius: .375rem; position: absolute; left: 50\%; margin-top: 30px; transform: translateX(-50\%); z-index: 1"></iframe>}} 58 | \if{html}{\out{<a style='height: 800px; display: block;'></a>}} 59 | } 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /man/validate_has_variable.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/validations.R 3 | \name{validate_has_variable} 4 | \alias{validate_has_variable} 5 | \title{Validates that dataset contains specific variable} 6 | \usage{ 7 | validate_has_variable(data, varname, msg) 8 | } 9 | \arguments{ 10 | \item{data}{(\code{data.frame})} 11 | 12 | \item{varname}{(\code{character(1)}) name of variable to check for in \code{data}} 13 | 14 | \item{msg}{(\code{character(1)}) message to display if \code{data} does not include \code{varname}} 15 | } 16 | \description{ 17 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 18 | } 19 | \details{ 20 | This function is a wrapper for \code{shiny::validate}. 21 | } 22 | \examples{ 23 | data <- data.frame( 24 | one = rep("a", length.out = 20), 25 | two = rep(c("a", "b"), length.out = 20) 26 | ) 27 | ui <- fluidPage( 28 | selectInput( 29 | "var", 30 | "Select variable", 31 | choices = c("one", "two", "three", "four"), 32 | selected = "one" 33 | ), 34 | verbatimTextOutput("summary") 35 | ) 36 | 37 | server <- function(input, output) { 38 | output$summary <- renderText({ 39 | validate_has_variable(data, input$var) 40 | paste0("Selected treatment variables: ", paste(input$var, collapse = ", ")) 41 | }) 42 | } 43 | if (interactive()) { 44 | shinyApp(ui, server) 45 | } 46 | } 47 | \section{Examples in Shinylive}{ 48 | \describe{ 49 | \item{example-1}{ 50 | \href{https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKcqagSgB0ItMnGYFStAG5wABAB4AtNIBmAVwhjaJdj2kAVLAFUAogIEATKKShzFFqxiXN47AdOkkZAXmmM4qFyh8eNLUFADmpAAWGEQqpNLeAEwADDy4rtKkAO5ECT5+7AQBUEG40kH0QWkh4VExcXkp-BDNKrQ2ytRtZgAKUGFwLhBuAM5woWIAkhCocUNubkESLKUZi2AAyuNwYtLLjLRQ9KGrwwsEkUS0BHAjeUVBHqXlYNlEz0FRvnAfYEqxjCq6TOo22YjgZjyjwgPzAGTSGSkjHolloMF0cAAHqQAPJxWakAIjFQwGAsVhVATNARjRhIjqqdTiLRCAllWKkAk6EAZDkEgAkxNJ5I6vggZhEGOx7B5IL23FodjgAH1IlARsr9odjoM7FAyqy4vz9s0FtJUOryMkAlsJuRIaRfJZ4GR5QcjqERogXmULSNyOxDaRjSwysRqNQ0GMocEqqbpABfZoJgS0JTSQPCUTiKTabkZEaRISsACC6HYbTKtKRybACYAukA}{Open in Shinylive} 51 | \if{html}{\out{<iframe class="iframe_shinylive" src="https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKcqagSgB0ItMnGYFStAG5wABAB4AtNIBmAVwhjaJdj2kAVLAFUAogIEATKKShzFFqxiXN47AdOkkZAXmmM4qFyh8eNLUFADmpAAWGEQqpNLeAEwADDy4rtKkAO5ECT5+7AQBUEG40kH0QWkh4VExcXkp-BDNKrQ2ytRtZgAKUGFwLhBuAM5woWIAkhCocUNubkESLKUZi2AAyuNwYtLLjLRQ9KGrwwsEkUS0BHAjeUVBHqXlYNlEz0FRvnAfYEqxjCq6TOo22YjgZjyjwgPzAGTSGSkjHolloMF0cAAHqQAPJxWakAIjFQwGAsVhVATNARjRhIjqqdTiLRCAllWKkAk6EAZDkEgAkxNJ5I6vggZhEGOx7B5IL23FodjgAH1IlARsr9odjoM7FAyqy4vz9s0FtJUOryMkAlsJuRIaRfJZ4GR5QcjqERogXmULSNyOxDaRjSwysRqNQ0GMocEqqbpABfZoJgS0JTSQPCUTiKTabkZEaRISsACC6HYbTKtKRybACYAukA" style="height: 800px; width: 100vw; max-width: 1400px; border: 1px solid rgba(0,0,0,0.175); border-radius: .375rem; position: absolute; left: 50\%; margin-top: 30px; transform: translateX(-50\%); z-index: 1"></iframe>}} 52 | \if{html}{\out{<a style='height: 800px; display: block;'></a>}} 53 | } 54 | } 55 | } 56 | 57 | -------------------------------------------------------------------------------- /man/validate_in.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/validations.R 3 | \name{validate_in} 4 | \alias{validate_in} 5 | \title{Validates that vector includes all expected values} 6 | \usage{ 7 | validate_in(x, choices, msg) 8 | } 9 | \arguments{ 10 | \item{x}{Vector of values to test.} 11 | 12 | \item{choices}{Vector to test against.} 13 | 14 | \item{msg}{(\code{character(1)}) Error message to display if some elements of \code{x} are not elements of \code{choices}.} 15 | } 16 | \description{ 17 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 18 | } 19 | \details{ 20 | This function is a wrapper for \code{shiny::validate}. 21 | } 22 | \examples{ 23 | ui <- fluidPage( 24 | selectInput( 25 | "species", 26 | "Select species", 27 | choices = c("setosa", "versicolor", "virginica", "unknown species"), 28 | selected = "setosa", 29 | multiple = FALSE 30 | ), 31 | verbatimTextOutput("summary") 32 | ) 33 | 34 | server <- function(input, output) { 35 | output$summary <- renderPrint({ 36 | validate_in(input$species, iris$Species, "Species does not exist.") 37 | nrow(iris[iris$Species == input$species, ]) 38 | }) 39 | } 40 | if (interactive()) { 41 | shinyApp(ui, server) 42 | } 43 | 44 | } 45 | \section{Examples in Shinylive}{ 46 | \describe{ 47 | \item{example-1}{ 48 | \href{https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKcqagSgB0ItMnGYFStAG5wABAB4AtNIBmAVwhjaJdj2kAVLAFUAogIEracxUurmAJgAUoAczjsB06QGc41OGICSEKgqpG4QHh58YJ6ofrRwnlG47hFRAMo+fqResQTxiXgpHgQAFkS0BAnSALzSBG7RcKREnlBJ0lFSjJ4VRNREjO2dtIxOQhVteB1gagDWEEQA7uExcQlRPMnhEd6+YnC2NdPeza1JRdIwKtTiqL5HAGIAggAyaSbbmyld9FDiMLo4AAPUgAeRCwVCUU8KhgMBYrA2An4EAE3kYXUsyjUGi0QkhuGkRAhIR0IBSxNIkIAJDC4QisYwKLYRPZGEJQuTth4JNxaLY-nAAPpCdj4kK03L5QkjWiealpKUJQnpJWeaS2IhVBbZYFy0gYJHc6QQRhLMXszzAWXyxVrdXVWri0iS+2EgC6KI8AF8Ud6BLQlNIxcJROIpNoySlPCUhKwnuh2OZCeiun6BGBve6gA}{Open in Shinylive} 49 | \if{html}{\out{<iframe class="iframe_shinylive" src="https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKcqagSgB0ItMnGYFStAG5wABAB4AtNIBmAVwhjaJdj2kAVLAFUAogIEracxUurmAJgAUoAczjsB06QGc41OGICSEKgqpG4QHh58YJ6ofrRwnlG47hFRAMo+fqResQTxiXgpHgQAFkS0BAnSALzSBG7RcKREnlBJ0lFSjJ4VRNREjO2dtIxOQhVteB1gagDWEEQA7uExcQlRPMnhEd6+YnC2NdPeza1JRdIwKtTiqL5HAGIAggAyaSbbmyld9FDiMLo4AAPUgAeRCwVCUU8KhgMBYrA2An4EAE3kYXUsyjUGi0QkhuGkRAhIR0IBSxNIkIAJDC4QisYwKLYRPZGEJQuTth4JNxaLY-nAAPpCdj4kK03L5QkjWiealpKUJQnpJWeaS2IhVBbZYFy0gYJHc6QQRhLMXszzAWXyxVrdXVWri0iS+2EgC6KI8AF8Ud6BLQlNIxcJROIpNoySlPCUhKwnuh2OZCeiun6BGBve6gA" style="height: 800px; width: 100vw; max-width: 1400px; border: 1px solid rgba(0,0,0,0.175); border-radius: .375rem; position: absolute; left: 50\%; margin-top: 30px; transform: translateX(-50\%); z-index: 1"></iframe>}} 50 | \if{html}{\out{<a style='height: 800px; display: block;'></a>}} 51 | } 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /man/validate_one_row_per_id.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/validations.R 3 | \name{validate_one_row_per_id} 4 | \alias{validate_one_row_per_id} 5 | \title{Validate that dataset has unique rows for key variables} 6 | \usage{ 7 | validate_one_row_per_id(x, key = c("USUBJID", "STUDYID")) 8 | } 9 | \arguments{ 10 | \item{x}{(\code{data.frame})} 11 | 12 | \item{key}{(\code{character}) Vector of ID variables from \code{x} that identify unique records.} 13 | } 14 | \description{ 15 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 16 | } 17 | \details{ 18 | This function is a wrapper for \code{shiny::validate}. 19 | } 20 | \examples{ 21 | iris$id <- rep(1:50, times = 3) 22 | ui <- fluidPage( 23 | selectInput( 24 | inputId = "species", 25 | label = "Select species", 26 | choices = c("setosa", "versicolor", "virginica"), 27 | selected = "setosa", 28 | multiple = TRUE 29 | ), 30 | plotOutput("plot") 31 | ) 32 | server <- function(input, output) { 33 | output$plot <- renderPlot({ 34 | iris_f <- iris[iris$Species \%in\% input$species, ] 35 | validate_one_row_per_id(iris_f, key = c("id")) 36 | 37 | hist(iris_f$Sepal.Length, breaks = 5) 38 | }) 39 | } 40 | if (interactive()) { 41 | shinyApp(ui, server) 42 | } 43 | 44 | } 45 | \section{Examples in Shinylive}{ 46 | \describe{ 47 | \item{example-1}{ 48 | \href{https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKcqagSgB0ItMnGYFStAG5wABAB4AtNIBmAVwhjaJdj2kAVLAFUAogIG1GtAM4ASWgBM5ixnFTsAjIgCsABlzTx8JbSALzSAMz8ECq0jsrU0XYAClAA5nDsAtLSlnDUcGIAkhCoKqQZEFlZQiWkBQ6hfGCWqPm0cJaNuJmV1FD0uSHSjQDKufmk2S0EbR143VkEABZEtATtgwQZTXCkRJZQnUNgUoyWq0TURIyHjRLmKUKrB2A8XRWVOXlicPVHObv7TrzaQwFTUcSoPKDfTGbqvbqQoikADypRqW0RpEakUiOUYJ1iqnU4i01VKfiIaNKOhA3UppBq1kxsWcEDsIkSlzKtPeVQslgA+kpYuYrMBRTZhlMZtIAKRCWXSMmkazNVrtPwAXWBEm49ig5AFJDgAsYRAA7gKWowBfZ2BKhX4ANZwVgbLb2bGRYGLKxlB1KayjVDcDAAGQoKVIiz8TDgUCdQVCnkiWQAvpE02ZhfbhKJxFJtDTupZfRBWABBdDsaJ+PEnTMCMBpzVAA}{Open in Shinylive} 49 | \if{html}{\out{<iframe class="iframe_shinylive" src="https://shinylive.io/r/app/#code=NobwRAdghgtgpmAXGKAHVA6ASmANGAYwHsIAXOMpMAGwEsAjAJykYE8AKcqagSgB0ItMnGYFStAG5wABAB4AtNIBmAVwhjaJdj2kAVLAFUAogIG1GtAM4ASWgBM5ixnFTsAjIgCsABlzTx8JbSALzSAMz8ECq0jsrU0XYAClAA5nDsAtLSlnDUcGIAkhCoKqQZEFlZQiWkBQ6hfGCWqPm0cJaNuJmV1FD0uSHSjQDKufmk2S0EbR143VkEABZEtATtgwQZTXCkRJZQnUNgUoyWq0TURIyHjRLmKUKrB2A8XRWVOXlicPVHObv7TrzaQwFTUcSoPKDfTGbqvbqQoikADypRqW0RpEakUiOUYJ1iqnU4i01VKfiIaNKOhA3UppBq1kxsWcEDsIkSlzKtPeVQslgA+kpYuYrMBRTZhlMZtIAKRCWXSMmkazNVrtPwAXWBEm49ig5AFJDgAsYRAA7gKWowBfZ2BKhX4ANZwVgbLb2bGRYGLKxlB1KayjVDcDAAGQoKVIiz8TDgUCdQVCnkiWQAvpE02ZhfbhKJxFJtDTupZfRBWABBdDsaJ+PEnTMCMBpzVAA" style="height: 800px; width: 100vw; max-width: 1400px; border: 1px solid rgba(0,0,0,0.175); border-radius: .375rem; position: absolute; left: 50\%; margin-top: 30px; transform: translateX(-50\%); z-index: 1"></iframe>}} 50 | \if{html}{\out{<a style='height: 800px; display: block;'></a>}} 51 | } 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /revdep/.gitignore: -------------------------------------------------------------------------------- 1 | checks 2 | library 3 | checks.noindex 4 | library.noindex 5 | cloud.noindex 6 | data.sqlite 7 | *.html 8 | -------------------------------------------------------------------------------- /staged_dependencies.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | current_repo: 3 | repo: insightsengineering/teal 4 | host: https://github.com 5 | upstream_repos: 6 | insightsengineering/roxy.shinylive: 7 | repo: insightsengineering/roxy.shinylive 8 | host: https://github.com 9 | insightsengineering/teal.widgets: 10 | repo: insightsengineering/teal.widgets 11 | host: https://github.com 12 | insightsengineering/teal.code: 13 | repo: insightsengineering/teal.code 14 | host: https://github.com 15 | insightsengineering/teal.data: 16 | repo: insightsengineering/teal.data 17 | host: https://github.com 18 | insightsengineering/teal.slice: 19 | repo: insightsengineering/teal.slice 20 | host: https://github.com 21 | insightsengineering/teal.logger: 22 | repo: insightsengineering/teal.logger 23 | host: https://github.com 24 | insightsengineering/teal.reporter: 25 | repo: insightsengineering/teal.reporter 26 | host: https://github.com 27 | downstream_repos: 28 | insightsengineering/teal.modules.general: 29 | repo: insightsengineering/teal.modules.general 30 | host: https://github.com 31 | insightsengineering/teal.modules.clinical: 32 | repo: insightsengineering/teal.modules.clinical 33 | host: https://github.com 34 | insightsengineering/teal.osprey: 35 | repo: insightsengineering/teal.osprey 36 | host: https://github.com 37 | insightsengineering/teal.goshawk: 38 | repo: insightsengineering/teal.goshawk 39 | host: https://github.com 40 | insightsengineering/teal.modules.hermes: 41 | repo: insightsengineering/teal.modules.hermes 42 | host: https://github.com 43 | insightsengineering/teal.modules.helios: 44 | repo: insightsengineering/teal.modules.helios 45 | host: https://github.com 46 | -------------------------------------------------------------------------------- /teal.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageBuildBinaryArgs: --no-build-vignettes 22 | PackageCheckArgs: --as-cran 23 | PackageRoxygenize: rd,collate,namespace 24 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | pkg_name <- "teal" 2 | library(pkg_name, character.only = TRUE) 3 | testthat::test_check(pkg_name) 4 | unlink(".renv") 5 | unlink("BiocManager") 6 | -------------------------------------------------------------------------------- /tests/testthat/helper-shinytest2.R: -------------------------------------------------------------------------------- 1 | simple_teal_data <- function() { 2 | data <- within(teal_data(), { 3 | iris <- iris 4 | mtcars <- mtcars 5 | }) 6 | data 7 | } 8 | 9 | report_module <- function(label = "example teal module") { 10 | module( 11 | label = label, 12 | server = function(id, data, reporter) { 13 | moduleServer(id, function(input, output, session) { 14 | teal.reporter::simple_reporter_srv( 15 | id = "reporter", 16 | reporter = reporter, 17 | card_fun = function(card) card 18 | ) 19 | updateSelectInput(session, "dataname", choices = isolate(names(data()))) 20 | output$dataset <- renderPrint({ 21 | req(input$dataname) 22 | data()[[input$dataname]] 23 | }) 24 | }) 25 | }, 26 | ui = function(id) { 27 | ns <- NS(id) 28 | sidebarLayout( 29 | sidebarPanel( 30 | teal.reporter::simple_reporter_ui(ns("reporter")), 31 | selectInput(ns("dataname"), "Choose a dataset", choices = NULL) 32 | ), 33 | mainPanel(verbatimTextOutput(ns("dataset"))) 34 | ) 35 | } 36 | ) 37 | } 38 | -------------------------------------------------------------------------------- /tests/testthat/setup-logger.R: -------------------------------------------------------------------------------- 1 | logger::log_appender(function(...) NULL, namespace = "teal") 2 | -------------------------------------------------------------------------------- /tests/testthat/setup-options.R: -------------------------------------------------------------------------------- 1 | # `opts_partial_match_old` is left for exclusions due to partial matching in dependent packages (i.e. not fixable here) 2 | # it might happen that it is not used right now, but it is left for possible future use 3 | # use with: `withr::with_options(opts_partial_match_old, { ... })` inside the test 4 | opts_partial_match_old <- list( 5 | warnPartialMatchDollar = getOption("warnPartialMatchDollar"), 6 | warnPartialMatchArgs = getOption("warnPartialMatchArgs"), 7 | warnPartialMatchAttr = getOption("warnPartialMatchAttr") 8 | ) 9 | opts_partial_match_new <- list( 10 | warnPartialMatchDollar = TRUE, 11 | warnPartialMatchArgs = TRUE, 12 | warnPartialMatchAttr = TRUE 13 | ) 14 | 15 | if (isFALSE(getFromNamespace("on_cran", "testthat")()) && requireNamespace("withr", quietly = TRUE)) { 16 | withr::local_options( 17 | opts_partial_match_new, 18 | .local_envir = testthat::teardown_env() 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /tests/testthat/setup-testing_depth.R: -------------------------------------------------------------------------------- 1 | #' Returns testing depth set by session option or by environmental variable. 2 | #' 3 | #' @details Looks for the session option `TESTING_DEPTH` first. 4 | #' If not set, takes the system environmental variable `TESTING_DEPTH`. 5 | #' If neither is set, then returns 3 by default. 6 | #' If the value of `TESTING_DEPTH` is not a numeric of length 1, then returns 3. 7 | #' 8 | #' @return `numeric(1)` the testing depth. 9 | #' 10 | get_testing_depth <- function() { 11 | default_depth <- 3 12 | depth <- getOption("TESTING_DEPTH", Sys.getenv("TESTING_DEPTH", default_depth)) 13 | depth <- tryCatch( 14 | as.numeric(depth), 15 | error = function(error) default_depth, 16 | warning = function(warning) default_depth 17 | ) 18 | if (length(depth) != 1) depth <- default_depth 19 | depth 20 | } 21 | 22 | #' Skipping tests in the testthat pipeline under specific scope 23 | #' @description This function should be used per each `testthat::test_that` call. 24 | #' Each of the call should specify an appropriate depth value. 25 | #' The depth value will set the appropriate scope so more/less time consuming tests could be recognized. 26 | #' The environment variable `TESTING_DEPTH` is used for changing the scope of `testthat` pipeline. 27 | #' `TESTING_DEPTH` interpretation for each possible value: 28 | #' \itemize{ 29 | #' \item{0}{no tests at all} 30 | #' \item{1}{fast - small scope - executed on every commit} 31 | #' \item{3}{medium - medium scope - daily integration pipeline} 32 | #' \item{5}{slow - all tests - daily package tests} 33 | #' } 34 | #' @param depth `numeric` the depth of the testing evaluation, 35 | #' has opposite interpretation to environment variable `TESTING_DEPTH`. 36 | #' So e.g. `0` means run it always and `5` means a heavy test which should be run rarely. 37 | #' If the `depth` argument is larger than `TESTING_DEPTH` then the test is skipped. 38 | #' @importFrom testthat skip 39 | #' @return `NULL` or invoke an error produced by `testthat::skip` 40 | #' @note By default `TESTING_DEPTH` is equal to 3 if there is no environment variable for it. 41 | #' By default `depth` argument lower or equal to 3 will not be skipped because by default `TESTING_DEPTH` 42 | #' is equal to 3. To skip <= 3 depth tests then the environment variable has to be lower than 3 respectively. 43 | skip_if_too_deep <- function(depth) { # nolintr 44 | checkmate::assert_numeric(depth, len = 1, lower = 0, upper = 5) 45 | testing_depth <- get_testing_depth() # by default 3 if there are no env variable 46 | if (testing_depth < depth) { 47 | testthat::skip(paste("testing depth", testing_depth, "is below current testing specification", depth)) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tests/testthat/test-module_session_info.R: -------------------------------------------------------------------------------- 1 | testthat::describe("srv_session_info lockfile", { 2 | testthat::it(paste0( 3 | "creation process is invoked for teal.lockfile.mode = \"enabled\" ", 4 | "and snapshot is copied to teal_app.lock and removed after session ended" 5 | ), { 6 | testthat::skip_if_not_installed("mirai") 7 | testthat::skip_if_not_installed("renv") 8 | withr::with_options( 9 | list(teal.lockfile.mode = "enabled"), 10 | { 11 | renv_filename <- "teal_app.lock" 12 | shiny::testServer( 13 | app = srv_session_info, 14 | args = list(id = "test"), 15 | expr = { 16 | iter <- 1 17 | while (!file.exists(renv_filename) && iter <= 1000) { 18 | Sys.sleep(0.5) 19 | iter <- iter + 1 # max wait time is 500 seconds 20 | } 21 | testthat::expect_true(file.exists(renv_filename)) 22 | } 23 | ) 24 | testthat::expect_false(file.exists(renv_filename)) 25 | } 26 | ) 27 | }) 28 | testthat::it("creation process is not invoked for teal.lockfile.mode = \"disabled\"", { 29 | testthat::skip_if_not_installed("mirai") 30 | testthat::skip_if_not_installed("renv") 31 | withr::with_options( 32 | list(teal.lockfile.mode = "disabled"), 33 | { 34 | renv_filename <- "teal_app.lock" 35 | shiny::testServer( 36 | app = srv_session_info, 37 | args = list(id = "test"), 38 | expr = { 39 | testthat::expect_false(file.exists(renv_filename)) 40 | } 41 | ) 42 | } 43 | ) 44 | }) 45 | }) 46 | -------------------------------------------------------------------------------- /tests/testthat/test-report_previewer_module.R: -------------------------------------------------------------------------------- 1 | testthat::test_that("report_previewer_module has specific classes", { 2 | testthat::expect_s3_class( 3 | reporter_previewer_module(), 4 | c("teal_module_previewer", "teal_module") 5 | ) 6 | }) 7 | 8 | testthat::test_that("report_previewer_module throws error if label is not string", { 9 | testthat::expect_error( 10 | reporter_previewer_module(label = 5), "Assertion on 'label' failed: Must be of type 'string'" 11 | ) 12 | testthat::expect_error( 13 | reporter_previewer_module(label = c("A", "B")), "Assertion on 'label' failed: Must have length 1." 14 | ) 15 | }) 16 | 17 | testthat::test_that("report_previewer_module throws no error and stores label if label is string", { 18 | testthat::expect_no_error(r_p_m <- reporter_previewer_module(label = "My label")) 19 | testthat::expect_equal(r_p_m$label, "My label") 20 | }) 21 | 22 | testthat::test_that("report_previewer_module default label is Report previewer ", { 23 | r_p_m <- reporter_previewer_module() 24 | testthat::expect_equal(r_p_m$label, "Report previewer") 25 | }) 26 | 27 | testthat::test_that( 28 | "report_previewer_module does not accept server_args out of formals(teal.reporter::reporter_previewer_srv) ", 29 | { 30 | error_pattern <- ".*Assertion on \\'all\\(names\\(server_args" 31 | testthat::expect_error( 32 | reporter_previewer_module(server_args = list(x = "A")), 33 | error_pattern 34 | ) 35 | testthat::expect_error( 36 | reporter_previewer_module(server_args = list(reporter = "A", global_knitr = 5, d = 1)), 37 | error_pattern 38 | ) 39 | } 40 | ) 41 | -------------------------------------------------------------------------------- /tests/testthat/test-shinytest2-init.R: -------------------------------------------------------------------------------- 1 | testthat::skip_if_not_installed("shinytest2") 2 | testthat::skip_if_not_installed("rvest") 3 | 4 | testthat::test_that("e2e: teal app initializes with no errors", { 5 | testthat::skip("chromium") 6 | skip_if_too_deep(5) 7 | app <- TealAppDriver$new( 8 | data = simple_teal_data(), 9 | modules = example_module(label = "Example Module") 10 | ) 11 | app$expect_no_shiny_error() 12 | app$stop() 13 | }) 14 | 15 | testthat::test_that("e2e: teal app initializes with sessionInfo modal", { 16 | testthat::skip("chromium") 17 | skip_if_too_deep(5) 18 | app <- TealAppDriver$new( 19 | data = simple_teal_data(), 20 | modules = example_module(label = "Example Module") 21 | ) 22 | 23 | # Check if button exists. 24 | button_selector <- "#teal-footer-session_info-sessionInfo-button" 25 | testthat::expect_equal( 26 | app$get_text(button_selector), 27 | "Session Info" 28 | ) 29 | 30 | app$click(selector = button_selector) 31 | 32 | # Check header and title content. 33 | testthat::expect_equal( 34 | app$get_text("#shiny-modal > div > div > div.modal-header > h4"), 35 | "SessionInfo" 36 | ) 37 | 38 | # There are two Copy buttons with similar id and the same label. 39 | testthat::expect_setequal( 40 | testthat::expect_length( 41 | app$get_text( 42 | "#shiny-modal [id^='teal-footer-session_info-sessionInfo-copy_button']" 43 | ), 44 | 2 45 | ), 46 | "Copy to Clipboard" 47 | ) 48 | # There are two Dismiss buttons with similar id and the same label. 49 | testthat::expect_setequal( 50 | testthat::expect_length( 51 | app$get_text("#shiny-modal button[data-dismiss]"), 52 | 2 53 | ), 54 | "Dismiss" 55 | ) 56 | 57 | # Check session info output. 58 | session_info <- app$get_text("#teal-footer-session_info-sessionInfo-verbatim_content") 59 | 60 | testthat::expect_match(session_info, "R version", fixed = TRUE) 61 | testthat::expect_match(session_info, "attached base packages:", fixed = TRUE) 62 | testthat::expect_match(session_info, "loaded via a namespace (and not attached):", fixed = TRUE) 63 | 64 | testthat::expect_match(session_info, "shiny", fixed = TRUE) 65 | testthat::expect_match(session_info, "teal.slice", fixed = TRUE) 66 | testthat::expect_match(session_info, "teal.reporter", fixed = TRUE) 67 | 68 | app$stop() 69 | }) 70 | 71 | testthat::test_that("e2e: init creates UI containing specified title, favicon, header and footer", { 72 | testthat::skip("chromium") 73 | skip_if_too_deep(5) 74 | app <- TealAppDriver$new( 75 | data = simple_teal_data(), 76 | modules = example_module(label = "Example Module"), 77 | title_args = list( 78 | title = "Custom Teal App Title", 79 | something_else = "asdfsdf", 80 | favicon = "https://raw.githubusercontent.com/insightsengineering/hex-stickers/main/PNG/teal.png" 81 | ), 82 | header = "Custom Teal App Header", 83 | footer = "Custom Teal App Footer" 84 | ) 85 | 86 | testthat::expect_equal( 87 | app$get_text("head > title")[1], 88 | "Custom Teal App Title" 89 | ) 90 | testthat::expect_equal( 91 | rvest::html_attr( 92 | rvest::html_elements(app$get_html_rvest("head > link[rel='icon']"), "link"), 93 | "href" 94 | ), 95 | "https://raw.githubusercontent.com/insightsengineering/hex-stickers/main/PNG/teal.png" 96 | ) 97 | testthat::expect_match( 98 | app$get_text("header"), 99 | "Custom Teal App Header" 100 | ) 101 | testthat::expect_match( 102 | app$get_text("footer"), 103 | "Custom Teal App Footer" 104 | ) 105 | app$stop() 106 | }) 107 | -------------------------------------------------------------------------------- /tests/testthat/test-shinytest2-module_bookmark_manager.R: -------------------------------------------------------------------------------- 1 | testthat::skip_if_not_installed("shinytest2") 2 | testthat::skip_if_not_installed("rvest") 3 | 4 | testthat::test_that("bookmark_manager_button is not rendered by default", { 5 | testthat::skip("chromium") 6 | skip_if_too_deep(5) 7 | app <- TealAppDriver$new( 8 | data = simple_teal_data(), 9 | modules = example_module(label = "Example Module"), 10 | options = list() 11 | ) 12 | on.exit(app$stop()) 13 | testthat::expect_null( 14 | app$get_html(".bookmark_manager_button") 15 | ) 16 | }) 17 | 18 | 19 | testthat::test_that("bookmark_manager_button is not rendered when enableBookmarking = 'url'", { 20 | testthat::skip("chromium") 21 | skip_if_too_deep(5) 22 | app <- TealAppDriver$new( 23 | data = simple_teal_data(), 24 | modules = example_module(label = "Example Module"), 25 | options = list(shiny.bookmarkStore = "url") 26 | ) 27 | on.exit(app$stop()) 28 | testthat::expect_null( 29 | app$get_html(".bookmark_manager_button") 30 | ) 31 | }) 32 | 33 | 34 | testthat::test_that("bookmark_manager_button is rendered when enableBookmarking = 'server'", { 35 | testthat::skip("chromium") 36 | skip_if_too_deep(5) 37 | app <- TealAppDriver$new( 38 | data = simple_teal_data(), 39 | modules = example_module(label = "Example Module"), 40 | options = list(shiny.bookmarkStore = "server") 41 | ) 42 | on.exit(app$stop()) 43 | testthat::expect_true(!is.null(app$get_html(".bookmark_manager_button"))) 44 | }) 45 | 46 | testthat::test_that("bookmark_manager_button shows modal with url containing state_id when clicked", { 47 | testthat::skip("chromium") 48 | skip_if_too_deep(5) 49 | app <- TealAppDriver$new( 50 | data = simple_teal_data(), 51 | modules = example_module(label = "Example Module"), 52 | options = list(shiny.bookmarkStore = "server") 53 | ) 54 | bookmark_button_id <- app$get_attr(".bookmark_manager_button", "id") 55 | app$click(bookmark_button_id) 56 | 57 | testthat::expect_match( 58 | rvest::html_text(app$get_html_rvest("div[id$=bookmark_modal] pre")), 59 | "_state_id_" 60 | ) 61 | }) 62 | -------------------------------------------------------------------------------- /tests/testthat/test-shinytest2-modules.R: -------------------------------------------------------------------------------- 1 | testthat::skip_if_not_installed("shinytest2") 2 | testthat::skip_if_not_installed("rvest") 3 | 4 | testthat::test_that("e2e: the module server logic is only triggered when the teal module becomes active", { 5 | testthat::skip("chromium") 6 | skip_if_too_deep(5) 7 | value_export_module <- function(label = "custom module") { 8 | module( 9 | label = label, 10 | server = function(id, data) { 11 | moduleServer(id, function(input, output, session) { 12 | shiny::exportTestValues( 13 | value = rnorm(1) 14 | ) 15 | }) 16 | }, 17 | ui = function(id) { 18 | ns <- NS(id) 19 | h1("Module that exports a random value for testing") 20 | } 21 | ) 22 | } 23 | 24 | app <- TealAppDriver$new( 25 | data = simple_teal_data(), 26 | modules = modules( 27 | value_export_module(label = "Module 1"), 28 | value_export_module(label = "Module 2") 29 | ) 30 | ) 31 | 32 | test_exports <- app$get_values()$export 33 | 34 | expect_equal(length(test_exports), 1) 35 | 36 | app$navigate_teal_tab("Module 2") 37 | test_exports <- app$get_values()$export 38 | 39 | expect_equal(length(test_exports), 2) 40 | app$stop() 41 | }) 42 | 43 | 44 | testthat::test_that("e2e: filter panel only shows the data supplied using datanames", { 45 | testthat::skip("chromium") 46 | skip_if_too_deep(5) 47 | app <- TealAppDriver$new( 48 | data = simple_teal_data(), 49 | modules = modules( 50 | example_module(label = "mtcars", datanames = "mtcars") 51 | ) 52 | ) 53 | 54 | testthat::expect_identical( 55 | app$get_active_filter_vars(), 56 | "mtcars" 57 | ) 58 | app$stop() 59 | }) 60 | 61 | testthat::test_that("e2e: filter panel shows all the datasets when datanames is all", { 62 | testthat::skip("chromium") 63 | skip_if_too_deep(5) 64 | app <- TealAppDriver$new( 65 | data = simple_teal_data(), 66 | modules = modules( 67 | example_module(label = "all", datanames = "all") 68 | ) 69 | ) 70 | 71 | testthat::expect_identical( 72 | app$get_active_filter_vars(), 73 | c("iris", "mtcars") 74 | ) 75 | app$stop() 76 | }) 77 | 78 | 79 | testthat::test_that("e2e: all the nested teal modules are initiated as expected", { 80 | testthat::skip("chromium") 81 | skip_if_too_deep(5) 82 | app <- TealAppDriver$new( 83 | data = simple_teal_data(), 84 | modules = modules( 85 | example_module(label = "Example Module"), 86 | modules( 87 | label = "Nested Modules", 88 | example_module(label = "Nested 1"), 89 | example_module(label = "Nested 2"), 90 | modules( 91 | label = "Sub Nested Modules", 92 | example_module(label = "Nested 1"), 93 | example_module(label = "Nested 1") 94 | ) 95 | ) 96 | ) 97 | ) 98 | app_modules <- app$get_text(selector = "ul.shiny-bound-input li a") 99 | testthat::expect_identical( 100 | app_modules, 101 | c( 102 | "Example Module", "Nested Modules", "Nested 1", "Nested 2", 103 | "Sub Nested Modules", "Nested 1", "Nested 1" 104 | ) 105 | ) 106 | app$stop() 107 | }) 108 | -------------------------------------------------------------------------------- /tests/testthat/test-shinytest2-reporter.R: -------------------------------------------------------------------------------- 1 | testthat::skip_if_not_installed("shinytest2") 2 | testthat::skip_if_not_installed("rvest") 3 | 4 | testthat::test_that("e2e: reporter tab is created when a module has reporter", { 5 | testthat::skip("chromium") 6 | skip_if_too_deep(5) 7 | app <- TealAppDriver$new( 8 | data = simple_teal_data(), 9 | modules = report_module(label = "Module with Reporter") 10 | ) 11 | 12 | teal_tabs <- rvest::html_elements(app$get_html_rvest(selector = "#teal-teal_modules-active_tab"), "a") 13 | tab_names <- setNames( 14 | rvest::html_attr(teal_tabs, "data-value"), 15 | rvest::html_text(teal_tabs) 16 | ) 17 | testthat::expect_identical( 18 | tab_names, 19 | c("Module with Reporter" = "module_with_reporter", "Report previewer" = "report_previewer") 20 | ) 21 | 22 | app$stop() 23 | }) 24 | 25 | testthat::test_that("e2e: reporter tab is not created when a module has no reporter", { 26 | testthat::skip("chromium") 27 | skip_if_too_deep(5) 28 | app <- TealAppDriver$new( 29 | data = simple_teal_data(), 30 | modules = example_module(label = "Example Module") 31 | ) 32 | teal_tabs <- rvest::html_elements( 33 | app$get_html_rvest(selector = "#teal-teal_modules-active_tab"), 34 | "a" 35 | ) 36 | tab_names <- setNames( 37 | rvest::html_attr(teal_tabs, "data-value"), 38 | rvest::html_text(teal_tabs) 39 | ) 40 | 41 | testthat::expect_identical( 42 | tab_names, 43 | c("Example Module" = "example_module") 44 | ) 45 | 46 | app$stop() 47 | }) 48 | 49 | testthat::test_that("e2e: adding a report card in a module adds it in the report previewer tab", { 50 | testthat::skip("chromium") 51 | skip_if_too_deep(5) 52 | app <- TealAppDriver$new( 53 | data = simple_teal_data(), 54 | modules = report_module(label = "Module with Reporter") 55 | ) 56 | 57 | app$click(NS(app$active_module_ns(), "reporter-add_report_card_simple-add_report_card_button")) 58 | 59 | app$set_input( 60 | NS(app$active_module_ns(), "reporter-add_report_card_simple-label"), 61 | "Card name" 62 | ) 63 | app$set_input( 64 | NS(app$active_module_ns(), "reporter-add_report_card_simple-comment"), 65 | "Card comment" 66 | ) 67 | 68 | app$click(NS(app$active_module_ns(), "reporter-add_report_card_simple-add_card_ok")) 69 | 70 | app$navigate_teal_tab("Report previewer") 71 | 72 | accordian_selector <- sprintf("#%s-pcards .accordion-toggle", app$active_module_ns()) 73 | app$click(selector = accordian_selector) 74 | 75 | 76 | testthat::expect_match( 77 | app$get_text(selector = accordian_selector), 78 | "Card 1: Card name" 79 | ) 80 | 81 | testthat::expect_match( 82 | app$get_text(selector = "#card1 pre"), 83 | "Card comment" 84 | ) 85 | 86 | app$stop() 87 | }) 88 | 89 | testthat::test_that("e2e: reporter_previewer_module do not show data_summary nor filter_panel", { 90 | testthat::skip("chromium") 91 | skip_if_too_deep(5) 92 | app <- teal:::TealAppDriver$new( 93 | data = simple_teal_data(), 94 | modules = report_module(label = "Module with Reporter") 95 | ) 96 | 97 | app$navigate_teal_tab("Report previewer") 98 | 99 | testthat::expect_null(app$is_visible(app$active_data_summary_element("table"))) 100 | 101 | testthat::expect_null(app$get_active_filter_vars()) 102 | 103 | app$stop() 104 | }) 105 | -------------------------------------------------------------------------------- /tests/testthat/test-shinytest2-show-rcode.R: -------------------------------------------------------------------------------- 1 | testthat::skip_if_not_installed("shinytest2") 2 | testthat::skip_if_not_installed("rvest") 3 | 4 | testthat::test_that("e2e: teal app initializes with Show R Code modal", { 5 | testthat::skip("chromium") 6 | skip_if_too_deep(5) 7 | app <- TealAppDriver$new( 8 | data = simple_teal_data(), 9 | modules = example_module(label = "Example Module") 10 | ) 11 | 12 | # Check if button exists. 13 | button_selector <- app$active_module_element("rcode-button") 14 | testthat::expect_equal( 15 | app$get_text(button_selector), 16 | "Show R code" 17 | ) 18 | 19 | app$click(selector = button_selector) 20 | 21 | # Check header and title content. 22 | testthat::expect_equal( 23 | app$get_text("#shiny-modal div.modal-header > h4"), 24 | "Example Code" 25 | ) 26 | 27 | # There are two Dismiss buttons with similar id and the same label. 28 | testthat::expect_setequal( 29 | testthat::expect_length( 30 | app$get_text("#shiny-modal button[data-dismiss]"), 31 | 2 32 | ), 33 | "Dismiss" 34 | ) 35 | # Check for Copy buttons. 36 | testthat::expect_equal( 37 | app$get_text(app$active_module_element("rcode-copy_button1")), 38 | "Copy to Clipboard" 39 | ) 40 | testthat::expect_equal( 41 | app$get_text(app$active_module_element("rcode-copy_button2")), 42 | "Copy to Clipboard" 43 | ) 44 | 45 | # Check R code output. 46 | testthat::expect_setequal( 47 | strsplit(app$get_text(app$active_module_element("rcode-verbatim_content")), "\n")[[1]], 48 | c( 49 | "iris <- iris", 50 | "mtcars <- mtcars", 51 | sprintf('stopifnot(rlang::hash(iris) == "%s") # @linksto iris', rlang::hash(iris)), 52 | sprintf('stopifnot(rlang::hash(mtcars) == "%s") # @linksto mtcars', rlang::hash(mtcars)), 53 | ".raw_data <- list2env(list(iris = iris, mtcars = mtcars))", 54 | "lockEnvironment(.raw_data) # @linksto .raw_data", 55 | "object <- iris", 56 | "object" 57 | ) 58 | ) 59 | 60 | app$stop() 61 | }) 62 | -------------------------------------------------------------------------------- /tests/testthat/test-shinytest2-wunder_bar.R: -------------------------------------------------------------------------------- 1 | testthat::skip_if_not_installed("shinytest2") 2 | testthat::skip_if_not_installed("rvest") 3 | 4 | testthat::test_that("wunder_bar_srv clicking filter icon opens filter-manager modal", { 5 | testthat::skip("chromium") 6 | skip_if_too_deep(5) 7 | app <- TealAppDriver$new( 8 | data = simple_teal_data(), 9 | modules = example_module(label = "Example Module") 10 | ) 11 | 12 | filter_manager_btn_id <- grep( 13 | "filter_manager", 14 | x = app$get_attr(".wunder_bar_button", "id"), 15 | value = TRUE 16 | ) 17 | 18 | testthat::expect_true(is.null(app$get_text(".teal-filter-manager-modal"))) 19 | app$click(filter_manager_btn_id) 20 | testthat::expect_true(!is.null(app$get_text(".teal-filter-manager-modal"))) 21 | }) 22 | 23 | 24 | testthat::test_that("wunder_bar_srv clicking snapshot icon opens snapshot-manager modal", { 25 | testthat::skip("chromium") 26 | skip_if_too_deep(5) 27 | app <- TealAppDriver$new( 28 | data = simple_teal_data(), 29 | modules = example_module(label = "Example Module") 30 | ) 31 | 32 | snapshot_manager_btn_id <- grep( 33 | "snapshot_manager", 34 | x = app$get_attr(".wunder_bar_button", "id"), 35 | value = TRUE 36 | ) 37 | 38 | testthat::expect_true(is.null(app$get_text(".snapshot_manager_modal"))) 39 | app$click(snapshot_manager_btn_id) 40 | testthat::expect_true(!is.null(app$get_text(".snapshot_manager_modal"))) 41 | }) 42 | -------------------------------------------------------------------------------- /tests/testthat/test-teal_data_module.R: -------------------------------------------------------------------------------- 1 | testthat::test_that("teal_data_module returns teal_data_module", { 2 | testthat::expect_s3_class( 3 | teal_data_module(ui = function(id) tags$div(), server = function(id) NULL), 4 | "teal_data_module" 5 | ) 6 | }) 7 | 8 | testthat::test_that("teal_data_module throws when ui has other formals than id only", { 9 | testthat::expect_error( 10 | teal_data_module(ui = function(id, x) tags$div(), server = function(id) NULL), 11 | "Must have exactly 1 formal arguments" 12 | ) 13 | }) 14 | 15 | testthat::test_that("teal_data_module throws when server has other formals than id only", { 16 | testthat::expect_error( 17 | teal_data_module(ui = function(id) tags$div(), server = function(id, x) NULL), 18 | ".*exactly 1 formal.*" 19 | ) 20 | testthat::expect_error( 21 | teal_data_module(ui = function(id) tags$div(), server = function(id, x) NULL), 22 | ".*formal arguments.*" 23 | ) 24 | }) 25 | -------------------------------------------------------------------------------- /tests/testthat/test-teal_transform_module.R: -------------------------------------------------------------------------------- 1 | testthat::describe("make_teal_transform_server produces a valid teal_transform_module", { 2 | testthat::it("expression", { 3 | label <- "output_decorator" 4 | output_decorator <- teal_transform_module( 5 | label = label, 6 | server = make_teal_transform_server( 7 | expression(data1 <- rev(data1)) 8 | ) 9 | ) 10 | 11 | shiny::testServer( 12 | app = srv_transform_teal_data, 13 | args = list( 14 | id = "test", 15 | data = reactive(teal.data::teal_data(data1 = iris, data2 = mtcars)), 16 | transformators = output_decorator 17 | ), 18 | expr = { 19 | session$flushReact() 20 | testthat::expect_identical(module_output()[["data1"]], rev(iris)) 21 | } 22 | ) 23 | }) 24 | 25 | testthat::it("quote", { 26 | label <- "output_decorator" 27 | output_decorator <- teal_transform_module( 28 | label = label, 29 | server = make_teal_transform_server( 30 | quote(data1 <- rev(data1)) 31 | ) 32 | ) 33 | 34 | shiny::testServer( 35 | app = srv_transform_teal_data, 36 | args = list( 37 | id = "test", 38 | data = reactive(teal.data::teal_data(data1 = iris, data2 = mtcars)), 39 | transformators = output_decorator 40 | ), 41 | expr = { 42 | session$flushReact() 43 | testthat::expect_identical(module_output()[["data1"]], rev(iris)) 44 | } 45 | ) 46 | }) 47 | }) 48 | 49 | testthat::test_that( 50 | "ui_transform_teal_data and srv_transform_teal_data have the same namespace for transform module", 51 | { 52 | ttm <- teal_transform_module( 53 | ui = function(id) tags$div(id = NS(id, "a_div"), "a div"), 54 | server = function(id, data) { 55 | moduleServer(id, function(input, output, session) { 56 | full_id <- session$ns("a_div") 57 | reactive(within(data(), id <- full_id, full_id = full_id)) 58 | }) 59 | } 60 | ) 61 | 62 | initial_id <- "a-path-to-an-inner-namespace" 63 | ui <- ui_transform_teal_data(initial_id, ttm) 64 | # Find element that ends in "-a_div" 65 | expected_id <- unname(unlist(ui)[grepl(".*-a_div$", unlist(ui))][[1]]) 66 | 67 | testServer( 68 | app = srv_transform_teal_data, 69 | args = list( 70 | id = initial_id, 71 | data = reactive(within(teal_data(), iris <- iris)), 72 | transformators = ttm 73 | ), 74 | expr = { 75 | session$flushReact() 76 | testthat::expect_equal(module_output()$id, expected_id) 77 | } 78 | ) 79 | } 80 | ) 81 | -------------------------------------------------------------------------------- /tests/testthat/test-validate_has_data.R: -------------------------------------------------------------------------------- 1 | data <- data.frame(x = 1:10, y = c(1:9, NA), z = c(Inf, 2:10)) 2 | 3 | testthat::test_that("validate_has_data throws no error when data has at least as many rows as min_nrow", { 4 | testthat::expect_silent(validate_has_data(data, 10)) 5 | testthat::expect_silent(validate_has_data(data, 5)) 6 | }) 7 | 8 | testthat::test_that("validate_has_data throws error when min_nrow > #rows of data", { 9 | testthat::expect_error(validate_has_data(data, 11)) 10 | }) 11 | 12 | testthat::test_that("validate_has_data accepts logical complete argument", { 13 | testthat::expect_silent(validate_has_data(data[, c("x", "z")], 10, complete = TRUE)) 14 | testthat::expect_silent(validate_has_data(data[, c("x", "z")], 10, complete = FALSE)) 15 | }) 16 | 17 | testthat::test_that("validate_has_data throws error when data has NA and complete is set to TRUE", { 18 | testthat::expect_error(validate_has_data(data[, c("x", "y")], 10, complete = TRUE)) 19 | }) 20 | 21 | testthat::test_that("validate_has_data accepts logical allow_inf argument", { 22 | testthat::expect_silent(validate_has_data(data[, c("x", "y")], 10, allow_inf = FALSE)) 23 | testthat::expect_error(validate_has_data(data[, c("x", "y")], 10, complete = TRUE, allow_inf = FALSE)) 24 | }) 25 | 26 | testthat::test_that("validate_has_data accepts throws error when data has Inf values and allow_inf is set to FALSE", { 27 | testthat::expect_error(validate_has_data(data[, c("x", "z")], 10, allow_inf = FALSE)) 28 | }) 29 | 30 | testthat::test_that("validate_has_data accepts throws error when data has Inf values and allow_inf is set to FALSE", { 31 | testthat::expect_error(validate_has_data(data[, c("x", "z")], 10, allow_inf = FALSE)) 32 | testthat::expect_error(validate_has_data(data[, c("x", "z")], 10, complete = TRUE, allow_inf = FALSE)) 33 | }) 34 | 35 | testthat::test_that("validate_has_data allow_inf argument ignores non-numeric columns", { 36 | data <- data.frame(x = 3:5, w = c("A", "B", "C"), z = c(Inf, 4, 5)) 37 | testthat::expect_silent(validate_has_data(data[, c("x", "w")], 3, allow_inf = FALSE)) 38 | testthat::expect_error(validate_has_data(data, 3, allow_inf = FALSE)) 39 | }) 40 | 41 | testthat::test_that("validate_has_data returns message when msg argument is set", { 42 | testthat::expect_error( 43 | validate_has_data(data, 11, msg = "Check data."), 44 | "Minimum number of records not met: >= 11 records required.\nCheck data." 45 | ) 46 | }) 47 | 48 | testthat::test_that("validate_has_data returns message msg argument is set and complete is set to TRUE", { 49 | testthat::expect_error( 50 | validate_has_data(data[, c("x", "y")], 11, complete = TRUE, msg = "Check data."), 51 | "Number of complete cases is less than: 11\nCheck data." 52 | ) 53 | }) 54 | 55 | testthat::test_that("validate_has_data returns throws error with non-character msg input", { 56 | testthat::expect_error( 57 | validate_has_data(data, 10, msg = 1), 58 | "Assertion on 'msg' failed: Must be of type 'string' \\(or 'NULL'\\), not 'double'" 59 | ) 60 | 61 | testthat::expect_error( 62 | validate_has_data(data, 10, msg = TRUE), 63 | "Assertion on 'msg' failed: Must be of type 'string' \\(or 'NULL'\\), not 'logical'." 64 | ) 65 | }) 66 | -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | *.R 3 | -------------------------------------------------------------------------------- /vignettes/blueprint/_setup.Rmd: -------------------------------------------------------------------------------- 1 | 2 | ```{css, echo=FALSE} 3 | pre.mermaid { 4 | background: transparent; 5 | } 6 | ``` 7 | 8 | ```{r, echo=FALSE} 9 | shiny::tags$script(type = "module", "import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid/+esm'") 10 | ``` 11 | -------------------------------------------------------------------------------- /vignettes/blueprint/dataflow.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Data Flow" 3 | author: "NEST CoreDev" 4 | output: rmarkdown::html_vignette 5 | vignette: > 6 | %\VignetteIndexEntry{Data Flow} 7 | %\VignetteEngine{knitr::rmarkdown} 8 | %\VignetteEncoding{UTF-8} 9 | --- 10 | 11 | ```{r, child="_setup.Rmd"} 12 | ``` 13 | 14 | ```{r dataflow_mermaid1, echo=FALSE} 15 | shiny::pre( 16 | class = "mermaid", 17 | " 18 | %% This is a mermaid diagram, if you see this the plot failed to render. Sorry. 19 | sequenceDiagram; 20 | autonumber 21 | participant data 22 | participant filters 23 | participant filtered data 24 | participant teal module 25 | data->filters: gets 26 | filters->>filtered data: becomes 27 | filtered data->>teal module: sent to 28 | " 29 | ) 30 | ``` 31 | 32 | The sequence diagram above illustrates the different stages that data goes through within the `teal` framework, supported by the `teal.slice` package: 33 | 34 | 1. Data is created and loaded into `teal` app; 35 | - Data sets are wrapped in a `teal_data` before being passed to the app; 36 | - The [`teal_data` class](input_data.html) facilitates reproducibility; 37 | 2. Data is passed to the filter panel; 38 | - Users _(or app developers)_ can specify filters to apply; 39 | - Filters can be specified globally, for the whole app, or for specific modules; 40 | - Filtering code is appended to the data; 41 | - See the [Filter panel vignette](filter_panel.html) for details; 42 | 3. Filtered data is sent to `teal` modules for analysis; 43 | - Each module receives a `teal_data` object so analysis code applied to the data is tracked _(and can be used to reproduce the whole analysis)_; 44 | 45 | Whenever filters are added or removed, the data coming into modules is re-computed, providing the `teal` module with new filtered data to conduct the required analysis. 46 | -------------------------------------------------------------------------------- /vignettes/blueprint/filter_panel.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Filter Panel" 3 | author: "NEST CoreDev" 4 | output: rmarkdown::html_vignette 5 | vignette: > 6 | %\VignetteIndexEntry{Filter Panel} 7 | %\VignetteEngine{knitr::rmarkdown} 8 | %\VignetteEncoding{UTF-8} 9 | --- 10 | 11 | ## Introduction 12 | 13 | <a href="../../reference/figures/filterpanel.png" target="_blank"> 14 | <img src="../../man/figures/filterpanel.png" align="right" style="max-width: 33%;"/> 15 | </a> 16 | 17 | The `teal.slice` package provides `teal` applications with the **filter panel**, a powerful tool for exploring and analyzing data, and a key component of the `teal` framework. 18 | 19 | One of the great things about the filter panel is that it comes built-in with `teal`, requiring no programming knowledge to use. 20 | 21 | The filter panel provides a convenient way for users to subset their data, simplifying the process of exploration and comprehension. 22 | Moreover, users can activate or deactivate filter states interactively, either individually or globally, using the filter panel. 23 | 24 | 25 | <div style="clear: both"></div> 26 | 27 | ## Filter flow 28 | 29 | ```{r, child="_setup.Rmd"} 30 | ``` 31 | 32 | ```{r dataflow_mermaid1, echo=FALSE} 33 | shiny::pre( 34 | class = "mermaid", 35 | " 36 | %% This is a mermaid diagram, if you see this the plot failed to render. Sorry. 37 | sequenceDiagram 38 | autonumber 39 | data->teal.slice: processed by 40 | teal.slice->>shiny inputs: creates 41 | Note over teal.slice,shiny inputs: based on data type 42 | shiny inputs->>reactive dataset: updates 43 | reactive dataset->>teal modules: processed by 44 | " 45 | ) 46 | ``` 47 | 48 | The filter panel creates subsets of data. Subsetting is achieved by creating filter states, each of which holds a logical predicate (filter condition) that is applied to single variables. These filter conditions are composed into a single expression, a call to a particular function (e.g. `dplyr::filter`), and that expression is evaluated to create a filtered data subset. 49 | 50 | The process is entirely interactive. Filter states can be created, removed, and changed at will, however, the app developer may choose to constrain or even restrict them. 51 | 52 | When a filter state is created, the filter panel generates a _filter card_ with `shiny` inputs appropriate to the type of the variable, e.g. range selectors for numeric columns and sets of checkboxes or drop-down menus for categorical ones. 53 | 54 | As users interact with the filter cards, the subsetting complete expression is updated and filtered data is recomputed. 55 | 56 | The filtered data is passed to `teal` modules for downstream analysis. The subsetting expression is returned along with the data, ensuring an unbroken track record of the entire analysis. Signature of the data are also stored to ensure reproducible results. 57 | 58 | -------------------------------------------------------------------------------- /vignettes/blueprint/in_app_data.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "In-App Data" 3 | author: "NEST CoreDev" 4 | output: rmarkdown::html_vignette 5 | vignette: > 6 | %\VignetteIndexEntry{In-App Data} 7 | %\VignetteEngine{knitr::rmarkdown} 8 | %\VignetteEncoding{UTF-8} 9 | --- 10 | 11 | ## Building data in the App 12 | 13 | Typically the data that is passed into a `teal` application is available before the app is run. 14 | However, this is not always true and in some cases the data will be built only after the app has started. 15 | A good example is pulling the data from an external repository, like a database, or uploading a file. 16 | Additional authentication may be required. 17 | 18 | ### `teal_data_module` 19 | 20 | Preprocessing actions can be performed in-app using the `teal_data_module`. 21 | Rather than passing a `teal_data` object to the app, one may pass a _`shiny` module_ that _returns_ a `teal_data` object (wrapped in a reactive expression). 22 | This allows the app developer to include user actions data creation, fetching, and even pre-filtering modification. 23 | 24 | ## Further reading 25 | 26 | A complete explanation of using the `teal_data_module` can be found in [this `teal` vignette](../data-as-shiny-module.html) 27 | -------------------------------------------------------------------------------- /vignettes/blueprint/index.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "About Technical Blueprint" 3 | author: "NEST CoreDev" 4 | output: rmarkdown::html_vignette 5 | vignette: > 6 | %\VignetteIndexEntry{About Technical Blueprint} 7 | %\VignetteEngine{knitr::rmarkdown} 8 | %\VignetteEncoding{UTF-8} 9 | --- 10 | 11 | Welcome to `teal` Technical Blueprint documentation! 12 | 13 | The purpose of this material is to aid new developer's comprehension of the fundamental principles of the `teal` framework. 14 | We will explore crucial `teal` concepts such as data flow, actors, and filter panel, among others. 15 | 16 | While this material will be presented at a high-level, we will direct you to our vignettes for a more in-depth understanding. 17 | 18 | Our hope is that this resource will provide new developers with a strong grasp of `teal` products, enabling them to contribute to code with confidence. 19 | -------------------------------------------------------------------------------- /vignettes/blueprint/input_data.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Input Data" 3 | author: "NEST CoreDev" 4 | output: rmarkdown::html_vignette 5 | vignette: > 6 | %\VignetteIndexEntry{Input Data} 7 | %\VignetteEngine{knitr::rmarkdown} 8 | %\VignetteEncoding{UTF-8} 9 | --- 10 | 11 | ## Introduction 12 | 13 | Reproducibility is paramount in the pharmaceutical industry. 14 | Accurate and consistent results are essential to ensure high-quality research and the safety of patients. 15 | By prioritizing reproducibility, researchers can validate their methods, confirm their findings, and contribute to the advancement of the field. 16 | 17 | The `teal.code` package provides the [`qenv` class](https://insightsengineering.github.io/teal.code/latest-tag/articles/qenv.html) that facilitates code reproducibility. 18 | Code is passed to a `qenv` object, where is evaluated in a specific environment. 19 | `qenv` also stores the code so that it can be retrieved on request. 20 | 21 | The `teal_data` class, which serves as the primary data interface for `teal` applications, inherits this code tracking behavior from `qenv`. 22 | 23 | ## Preparing data for a `teal` application 24 | 25 | All `teal` applications run on data provided in a `teal_data` object. 26 | Data objects are stored and modified within the environment of the `teal_data` object and all `R` code used is tracked, which allows for the code to be evaluated and executed in the `teal` application, and reproduced outside the `teal` application. 27 | This includes data loading, preprocessing, filtering, transformations, and plotting, etc. 28 | 29 | The `teal_data` object makes it easy for users to reproduce and validate the results of their analyses. 30 | 31 | ```{dot teal_data_dot_diagram, echo=FALSE} 32 | digraph G { 33 | teal_data [label = "teal_data"]; 34 | node [shape=box]; 35 | teal_modules [label = "teal modules analysis R code"]; 36 | library [label = "R library() calls"]; 37 | filter_states [label = "filter states R code"]; 38 | data [label = "data preprocessing R code"]; 39 | teal_modules -> teal_data; 40 | library -> teal_data; 41 | edge [dir="back"]; 42 | teal_data -> filter_states; 43 | teal_data -> data; 44 | } 45 | ``` 46 | 47 | Learn more about the use of `teal_data` in the [`teal.data` package vignettes](https://insightsengineering.github.io/teal.data/latest-tag/articles). 48 | 49 | ## `Show R Code` and `Reporter` 50 | 51 | In both the `teal.modules.clinical` and `teal.modules.general` packages, you'll find that most modules include a convenient `Show R Code` button. 52 | When this button is clicked, a modal window appears, revealing the `R` code responsible for generating the module's output. 53 | This functionality is achieved by inspecting the `teal_data` object and retrieving code from it. 54 | With the `Show R Code` button, users can easily copy and independently run the code to reproduce the analysis presented in the teal module. 55 | 56 | ![Show R Code](../../man/figures/showrcode.jpg){width=50%} 57 | 58 | The Reporter feature also leverages the `teal_data` object in its operation. 59 | Much like the `Show R Code` mechanism, the code displayed in a Reporter Card is extracted from the `teal_data` object. 60 | 61 | ![Reporter](../../man/figures/reporter.jpg){width=50%} 62 | 63 | To learn more about the `Reporter` feature, please visit the [`teal.reporter` documentation](https://insightsengineering.github.io/teal.reporter/latest-tag/index.html). 64 | 65 | Overall, `qenv` from `teal.code` and its child class, `teal_data`, are powerful tools for ensuring code reproducibility and promoting high-quality research in the `R` programming language. 66 | -------------------------------------------------------------------------------- /vignettes/blueprint/intro.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Introduction" 3 | author: "NEST CoreDev" 4 | output: rmarkdown::html_vignette 5 | vignette: > 6 | %\VignetteIndexEntry{Introduction} 7 | %\VignetteEngine{knitr::rmarkdown} 8 | %\VignetteEncoding{UTF-8} 9 | --- 10 | 11 | `teal` is an interactive data exploration framework based on `shiny`, designed primarily to analyze CDISC clinical trial data. 12 | 13 | A `shiny` Application created with `teal` offers users the ability to: 14 | 15 | - Import data from external sources; 16 | - Dynamically filter data for analysis; 17 | - Generate reproducible code for future analysis; 18 | - Create and download reports of analysis results _(for analysis modules that support reporting)_. 19 | 20 | Moreover, the `teal` framework provides application developers with a wide range of customizable standard analysis modules to integrate into their applications, along with a logging framework that facilitates debugging. 21 | Additionally, advanced users of the framework can develop new analysis modules and easily integrate them into any `teal` application. 22 | 23 | The `teal` framework's functionality draws heavily from the following packages: 24 | 25 | | R package | Description | 26 | |----------------------|:------------------------------------------------------------------------| 27 | |[`teal`](https://insightsengineering.github.io/teal) | `shiny`-based interactive exploration framework for analyzing data| 28 | |[`teal.widgets`](https://insightsengineering.github.io/teal.widgets) | `shiny` UI components used within `teal`| 29 | |[`teal.data`](https://insightsengineering.github.io/teal.data) | provides the data structure used in all `teal` applications| 30 | |[`teal.slice`](https://insightsengineering.github.io/teal.slice) | provides the filter panel to allow dynamic filtering of data| 31 | |[`teal.code`](https://insightsengineering.github.io/teal.code) | provides a mechanism for tracking code to reproduce an analysis| 32 | |[`teal.logger`](https://insightsengineering.github.io/teal.logger) | standardizes logging within `teal` framework| 33 | |[`teal.reporter`](https://insightsengineering.github.io/teal.reporter) | allows `teal` applications to generate reports| 34 | 35 | Although these packages are mentioned in the material, we strongly recommend visiting their vignettes to learn more about them. 36 | 37 | Learn on how to make your first `teal` application [here](../getting-started-with-teal.html)! 38 | -------------------------------------------------------------------------------- /vignettes/blueprint/module_encapsulation.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Module Encapsulation" 3 | author: "NEST CoreDev" 4 | output: rmarkdown::html_vignette 5 | vignette: > 6 | %\VignetteIndexEntry{Module Encapsulation} 7 | %\VignetteEngine{knitr::rmarkdown} 8 | %\VignetteEncoding{UTF-8} 9 | --- 10 | 11 | ## Introduction 12 | 13 | The `teal` framework leverages the [`shiny` module concept](https://rstudio.github.io/shiny/reference/moduleServer.html) to enable encapsulation of analytical actions in `teal` modules, while maintaining seamless communication between the modules and the application. 14 | 15 | 16 | ## Benefits 17 | 18 | By implementing the modular app technique from the `shiny` module into the creation of the `teal` module, several benefits are realized: 19 | 20 | 1. Streamlined maintenance 21 | The development of the `teal` module becomes more manageable, as it can function independently from the `teal` framework. 22 | This separation allows developers to maintain the module with ease. This approach has been successfully applied in `R` packages dedicated to `teal` module development, such as `teal.modules.general` and `teal.modules.clinical`. 23 | 24 | 1. Enhanced focus on output 25 | `teal` module developers can concentrate solely on refining parameters or encoding, and output aspects (such as data summarization and visualization) without the need to concern themselves with the intricacies of the `teal` framework. 26 | When developed correctly, the module seamlessly integrates with `teal`. 27 | 28 | 1. Facilitated collaboration 29 | `teal` module development becomes an accessible entry point for developers interested in collaborating. 30 | This approach encourages user collaboration for the improvement of `teal` modules, as developers gain a deeper understanding of the mechanics of the `teal` framework. 31 | -------------------------------------------------------------------------------- /vignettes/blueprint/product_map.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Product Map" 3 | author: "NEST CoreDev" 4 | output: rmarkdown::html_vignette 5 | vignette: > 6 | %\VignetteIndexEntry{Product Map} 7 | %\VignetteEngine{knitr::rmarkdown} 8 | %\VignetteEncoding{UTF-8} 9 | --- 10 | 11 | ```{r, child="_setup.Rmd"} 12 | ``` 13 | 14 | ```{r, echo=FALSE} 15 | shiny::pre( 16 | class = "mermaid", 17 | " 18 | %% This is a mermaid diagram, if you see this the plot failed to render. Sorry. 19 | flowchart RL 20 | teal 21 | subgraph features 22 | direction LR 23 | teal.data 24 | teal.slice 25 | teal.code 26 | teal.logger 27 | teal.widgets 28 | end 29 | subgraph modules 30 | direction RL 31 | teal.modules.general 32 | teal.modules.clinical 33 | teal.osprey 34 | teal.goshawk 35 | teal.modules.hermes 36 | end 37 | teal--has-->features 38 | features--builds-->modules 39 | modules--creates-->teal 40 | subgraph modules 41 | teal.modules.general 42 | teal.modules.clinical 43 | teal.osprey 44 | teal.goshawk 45 | teal.modules.hermes 46 | end 47 | subgraph calculations 48 | direction RL 49 | tern 50 | osprey 51 | goshawk 52 | hermes 53 | end 54 | tern--supports-->teal.modules.clinical 55 | osprey--supports-->teal.osprey 56 | goshawk--supports-->teal.goshawk 57 | hermes--supports-->teal.modules.hermes 58 | style teal fill:lightblue 59 | style features fill:lightgreen 60 | style modules fill:pink 61 | " 62 | ) 63 | ``` 64 | 65 | `teal` is a modular framework that relies on a suite of related packages, as illustrated in the above diagram, to provide a wide range of functionalities. 66 | 67 | `teal`'s primary function is to create web app for analyzing clinical trial data but it **has** a multitude of features distributed across various packages. 68 | 69 | Developers can selectively leverage these packages, such as `teal.widgets`, `teal.code`, and `teal.logger`, to **build** `teal` modules for a `teal` app. 70 | This approach gives the developers the tools that speed up their work and avoid re-implementing existing logic and UI elements. 71 | 72 | The `teal` modules utilize various packages such as `tern`, `osprey`, and `goshawk` to perform calculations and analyses. 73 | These packages provide **support** to the `teal` modules by performing all computations while the modules only have to focus on how to wrap the input options and the output. 74 | 75 | Once developed, new and existing modules can be integrated into `teal` to **create** a functional `teal` app. 76 | 77 | ## Why so many packages? 78 | 79 | By breaking down `teal` features, modules, and calculations into dedicated packages, maintenance is made significantly more manageable. 80 | -------------------------------------------------------------------------------- /vignettes/images/bs-corners.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insightsengineering/teal/3d6b93310c969e0a6fecab41102846c94d99d4f1/vignettes/images/bs-corners.png -------------------------------------------------------------------------------- /vignettes/images/bs-final.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insightsengineering/teal/3d6b93310c969e0a6fecab41102846c94d99d4f1/vignettes/images/bs-final.png -------------------------------------------------------------------------------- /vignettes/images/bs-font-size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insightsengineering/teal/3d6b93310c969e0a6fecab41102846c94d99d4f1/vignettes/images/bs-font-size.png -------------------------------------------------------------------------------- /vignettes/images/bs-launch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insightsengineering/teal/3d6b93310c969e0a6fecab41102846c94d99d4f1/vignettes/images/bs-launch.png -------------------------------------------------------------------------------- /vignettes/images/bs-theme-set.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insightsengineering/teal/3d6b93310c969e0a6fecab41102846c94d99d4f1/vignettes/images/bs-theme-set.png -------------------------------------------------------------------------------- /vignettes/images/custom_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insightsengineering/teal/3d6b93310c969e0a6fecab41102846c94d99d4f1/vignettes/images/custom_app.png -------------------------------------------------------------------------------- /vignettes/images/reporter.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insightsengineering/teal/3d6b93310c969e0a6fecab41102846c94d99d4f1/vignettes/images/reporter.jpg -------------------------------------------------------------------------------- /vignettes/images/show_code_prepro_missing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insightsengineering/teal/3d6b93310c969e0a6fecab41102846c94d99d4f1/vignettes/images/show_code_prepro_missing.png -------------------------------------------------------------------------------- /vignettes/images/show_code_prepro_present.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insightsengineering/teal/3d6b93310c969e0a6fecab41102846c94d99d4f1/vignettes/images/show_code_prepro_present.png -------------------------------------------------------------------------------- /vignettes/teal-as-a-shiny-module.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Teal as a Shiny Module" 3 | author: "NEST CoreDev" 4 | output: 5 | rmarkdown::html_vignette: 6 | toc: true 7 | vignette: > 8 | %\VignetteIndexEntry{Teal as a Shiny Module} 9 | %\VignetteEngine{knitr::rmarkdown} 10 | %\VignetteEncoding{UTF-8} 11 | --- 12 | 13 | ## Introduction 14 | 15 | A `shiny` developer can embed a `teal` application into their own `shiny` app by using `shiny` module components of `teal`: `ui_teal()` and `srv_teal()`. 16 | This approach differs from using `init()` and offers greater flexibility. While `init()` includes a session info footer automatically, 17 | when using `teal` as a `shiny` module you can optionally add it manually with `ui_session_info()` and `srv_session_info()`. 18 | Using `teal` as a `shiny` module offers several advantages: 19 | 20 | - Embedding one or more `teal` applications within a larger `shiny` app 21 | - Creating `teal` applications with dynamically generated components (initial data, modules, filters) 22 | 23 | ## Example 24 | 25 | The following example demonstrates embedding `teal` as a `shiny` module within a larger `shiny` application. 26 | Users can select dataset names which are passed to the embedded `teal` component. 27 | On the server side, `srv_teal()` is called with a reactive `teal_data` object passed from the parent app's server. 28 | 29 | ```{r setup, include=FALSE} 30 | library(teal) 31 | ``` 32 | ```{r app} 33 | library(teal) 34 | 35 | data <- teal_data() |> within({ 36 | iris <- iris 37 | mtcars <- mtcars 38 | df <- data.frame(a = 1:10, b = letters[1:10]) 39 | }) 40 | 41 | mods <- modules( 42 | example_module("mod1"), 43 | example_module("mod2") 44 | ) 45 | 46 | ui_app <- fluidPage( 47 | title = "Your app with teal as a module", 48 | selectInput("datasets", "Select datasets", choices = c("iris", "mtcars", "df"), selected = "iris", multiple = TRUE), 49 | ui_teal("teal", mods), 50 | ui_session_info("session_info") 51 | ) 52 | 53 | srv_app <- function(input, output, session) { 54 | data_subset <- reactive(data[input$datasets]) 55 | srv_teal("teal", data = data_subset, modules = mods) 56 | srv_session_info("session_info") 57 | } 58 | 59 | if (interactive()) { 60 | shinyApp(ui_app, srv_app) 61 | } 62 | ``` 63 | 64 | ```{r shinylive_iframe, echo = FALSE, out.width = '150%', out.extra = 'style = "position: relative; z-index:1"', eval = requireNamespace("roxy.shinylive", quietly = TRUE) && knitr::is_html_output() && identical(Sys.getenv("IN_PKGDOWN"), "true")} 65 | code <- paste0(c( 66 | "interactive <- function() TRUE", 67 | knitr::knit_code$get("app") 68 | ), collapse = "\n") 69 | 70 | url <- roxy.shinylive::create_shinylive_url(code) 71 | knitr::include_url(url, height = "800px") 72 | ``` 73 | --------------------------------------------------------------------------------