[
  {
    "path": ".Rbuildignore",
    "content": "^datamods\\.Rproj$\n^\\.Rproj\\.user$\n^LICENSE\\.md$\n^examples$\n^doc$\n^Meta$\n^\\.github$\n^dev$\n^cran-comments\\.md$\n^CRAN-RELEASE$\n^_pkgdown\\.yml$\n^docs$\n^pkgdown$\n^man-roxygen$\n^README\\.Rmd$\n^CRAN-SUBMISSION$\n^data-raw$\n"
  },
  {
    "path": ".github/.gitignore",
    "content": "*.html\n"
  },
  {
    "path": ".github/workflows/R-CMD-check.yaml",
    "content": "# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples\n# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help\non:\n  push:\n    branches: [main, master]\n  pull_request:\n    branches: [main, master]\n\nname: R-CMD-check\n\njobs:\n  R-CMD-check:\n    runs-on: ${{ matrix.config.os }}\n\n    name: ${{ matrix.config.os }} (${{ matrix.config.r }})\n\n    strategy:\n      fail-fast: false\n      matrix:\n        config:\n          - {os: macos-latest,   r: 'release'}\n          - {os: windows-latest, r: 'release'}\n          - {os: ubuntu-latest,   r: 'devel', http-user-agent: 'release'}\n          - {os: ubuntu-latest,   r: 'release'}\n          - {os: ubuntu-latest,   r: 'oldrel-1'}\n\n    env:\n      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}\n      R_KEEP_PKG_SOURCE: yes\n\n    steps:\n      - uses: actions/checkout@v3\n\n      - uses: r-lib/actions/setup-pandoc@v2\n\n      - uses: r-lib/actions/setup-r@v2\n        with:\n          r-version: ${{ matrix.config.r }}\n          http-user-agent: ${{ matrix.config.http-user-agent }}\n          use-public-rspm: true\n\n      - uses: r-lib/actions/setup-r-dependencies@v2\n        with:\n          extra-packages: any::rcmdcheck\n          needs: check\n\n      - uses: r-lib/actions/check-r-package@v2\n        with:\n          upload-snapshots: true\n"
  },
  {
    "path": ".github/workflows/pkgdown.yaml",
    "content": "# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples\n# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help\non:\n  push:\n    branches: [main, master]\n  pull_request:\n    branches: [main, master]\n  release:\n    types: [published]\n  workflow_dispatch:\n\nname: pkgdown\n\njobs:\n  pkgdown:\n    runs-on: ubuntu-latest\n    # Only restrict concurrency for non-PR jobs\n    concurrency:\n      group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }}\n    env:\n      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}\n    steps:\n      - uses: actions/checkout@v3\n\n      - uses: r-lib/actions/setup-pandoc@v2\n\n      - uses: r-lib/actions/setup-r@v2\n        with:\n          use-public-rspm: true\n\n      - uses: r-lib/actions/setup-r-dependencies@v2\n        with:\n          extra-packages: any::pkgdown, local::.\n          needs: website\n\n      - name: Build site\n        run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE)\n        shell: Rscript {0}\n\n      - name: Deploy to GitHub pages 🚀\n        if: github.event_name != 'pull_request'\n        uses: JamesIves/github-pages-deploy-action@v4.4.1\n        with:\n          clean: false\n          branch: gh-pages\n          folder: docs\n"
  },
  {
    "path": ".github/workflows/test-coverage.yaml",
    "content": "# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples\n# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help\non:\n  push:\n    branches: [main, master]\n  pull_request:\n\nname: test-coverage.yaml\n\npermissions: read-all\n\njobs:\n  test-coverage:\n    runs-on: ubuntu-latest\n    env:\n      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: r-lib/actions/setup-r@v2\n        with:\n          use-public-rspm: true\n\n      - uses: r-lib/actions/setup-r-dependencies@v2\n        with:\n          extra-packages: any::covr, any::xml2\n          needs: coverage\n\n      - name: Test coverage\n        run: |\n          cov <- covr::package_coverage(\n            quiet = FALSE,\n            clean = FALSE,\n            install_path = file.path(normalizePath(Sys.getenv(\"RUNNER_TEMP\"), winslash = \"/\"), \"package\")\n          )\n          covr::to_cobertura(cov)\n        shell: Rscript {0}\n\n      - uses: codecov/codecov-action@v4\n        with:\n          # Fail if error if not on PR, or if on PR and token is given\n          fail_ci_if_error: ${{ github.event_name != 'pull_request' || secrets.CODECOV_TOKEN }}\n          file: ./cobertura.xml\n          plugin: noop\n          disable_search: true\n          token: ${{ secrets.CODECOV_TOKEN }}\n\n      - name: Show testthat output\n        if: always()\n        run: |\n          ## --------------------------------------------------------------------\n          find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \\; || true\n        shell: bash\n\n      - name: Upload test results\n        if: failure()\n        uses: actions/upload-artifact@v4\n        with:\n          name: coverage-test-failures\n          path: ${{ runner.temp }}/package\n"
  },
  {
    "path": ".gitignore",
    "content": ".Rproj.user\n.Rhistory\n.RData\n.Ruserdata\n*.Rproj\ninst/doc\ndoc\nMeta\ndev/\ndocs\nCRAN-SUBMISSION\n"
  },
  {
    "path": "DESCRIPTION",
    "content": "Package: datamods\nTitle: Modules to Import and Manipulate Data in 'Shiny'\nVersion: 1.5.3.9200\nAuthors@R: \n    c(person(given = \"Victor\",\n             family = \"Perrier\",\n             role = c(\"aut\", \"cre\", \"cph\"),\n             email = \"victor.perrier@dreamrs.fr\"),\n      person(given = \"Fanny\",\n             family = \"Meyer\",\n             role = \"aut\"),\n      person(given = \"Samra\",\n             family = \"Goumri\",\n             role = \"aut\"),\n      person(given = \"Zauad Shahreer\",\n             family = \"Abeer\",\n             role = \"aut\",\n             email = \"shahreyar.abeer@gmail.com\"),\n      person(given = \"Eduard\",\n             family = \"Szöcs\",\n             role = \"ctb\",\n             email = \"eduardszoecs@gmail.com\")\n      )\nDescription: 'Shiny' modules to import data into an application or 'addin'\n    from various sources, and to manipulate them after that.\nLicense: GPL-3\nURL: https://github.com/dreamRs/datamods, https://dreamrs.github.io/datamods/\nBugReports: https://github.com/dreamRs/datamods/issues\nEncoding: UTF-8\nRoxygen: list(markdown = TRUE)\nRoxygenNote: 7.3.2\nImports: \n    bslib,\n    classInt,\n    data.table,\n    htmltools,\n    phosphoricons,\n    reactable,\n    readxl,\n    rio,\n    rlang,\n    shiny (>= 1.5.0),\n    shinyWidgets (>= 0.8.4),\n    tibble,\n    toastui (>= 0.3.3),\n    tools,\n    shinybusy,\n    writexl\nSuggests: \n    ggplot2,\n    htmlwidgets,\n    jsonlite,\n    knitr,\n    MASS,\n    rmarkdown,\n    testthat,\n    validate\nVignetteBuilder: knitr\nDepends: \n    R (>= 2.10)\nLazyData: true\n"
  },
  {
    "path": "LICENSE.md",
    "content": "GNU General Public License\n==========================\n\n_Version 3, 29 June 2007_  \n_Copyright © 2007 Free Software Foundation, Inc. &lt;<http://fsf.org/>&gt;_\n\nEveryone is permitted to copy and distribute verbatim copies of this license\ndocument, but changing it is not allowed.\n\n## Preamble\n\nThe GNU General Public License is a free, copyleft license for software and other\nkinds of works.\n\nThe licenses for most software and other practical works are designed to take away\nyour freedom to share and change the works. By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change all versions of a\nprogram--to make sure it remains free software for all its users. We, the Free\nSoftware Foundation, use the GNU General Public License for most of our software; it\napplies also to any other work released this way by its authors. You can apply it to\nyour programs, too.\n\nWhen we speak of free software, we are referring to freedom, not price. Our General\nPublic Licenses are designed to make sure that you have the freedom to distribute\ncopies of free software (and charge for them if you wish), that you receive source\ncode or can get it if you want it, that you can change the software or use pieces of\nit in new free programs, and that you know you can do these things.\n\nTo protect your rights, we need to prevent others from denying you these rights or\nasking you to surrender the rights. Therefore, you have certain responsibilities if\nyou distribute copies of the software, or if you modify it: responsibilities to\nrespect the freedom of others.\n\nFor example, if you distribute copies of such a program, whether gratis or for a fee,\nyou must pass on to the recipients the same freedoms that you received. You must make\nsure that they, too, receive or can get the source code. And you must show them these\nterms so they know their rights.\n\nDevelopers that use the GNU GPL protect your rights with two steps: **(1)** assert\ncopyright on the software, and **(2)** offer you this License giving you legal permission\nto copy, distribute and/or modify it.\n\nFor the developers' and authors' protection, the GPL clearly explains that there is\nno warranty for this free software. For both users' and authors' sake, the GPL\nrequires that modified versions be marked as changed, so that their problems will not\nbe attributed erroneously to authors of previous versions.\n\nSome devices are designed to deny users access to install or run modified versions of\nthe software inside them, although the manufacturer can do so. This is fundamentally\nincompatible with the aim of protecting users' freedom to change the software. The\nsystematic pattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable. Therefore, we have designed\nthis version of the GPL to prohibit the practice for those products. If such problems\narise substantially in other domains, we stand ready to extend this provision to\nthose domains in future versions of the GPL, as needed to protect the freedom of\nusers.\n\nFinally, every program is threatened constantly by software patents. States should\nnot allow patents to restrict development and use of software on general-purpose\ncomputers, but in those that do, we wish to avoid the special danger that patents\napplied to a free program could make it effectively proprietary. To prevent this, the\nGPL assures that patents cannot be used to render the program non-free.\n\nThe precise terms and conditions for copying, distribution and modification follow.\n\n## TERMS AND CONDITIONS\n\n### 0. Definitions\n\n“This License” refers to version 3 of the GNU General Public License.\n\n“Copyright” also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n“The Program” refers to any copyrightable work licensed under this\nLicense. Each licensee is addressed as “you”. “Licensees” and\n“recipients” may be individuals or organizations.\n\nTo “modify” a work means to copy from or adapt all or part of the work in\na fashion requiring copyright permission, other than the making of an exact copy. The\nresulting work is called a “modified version” of the earlier work or a\nwork “based on” the earlier work.\n\nA “covered work” means either the unmodified Program or a work based on\nthe Program.\n\nTo “propagate” a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for infringement under\napplicable copyright law, except executing it on a computer or modifying a private\ncopy. Propagation includes copying, distribution (with or without modification),\nmaking available to the public, and in some countries other activities as well.\n\nTo “convey” a work means any kind of propagation that enables other\nparties to make or receive copies. Mere interaction with a user through a computer\nnetwork, with no transfer of a copy, is not conveying.\n\nAn interactive user interface displays “Appropriate Legal Notices” to the\nextent that it includes a convenient and prominently visible feature that **(1)**\ndisplays an appropriate copyright notice, and **(2)** tells the user that there is no\nwarranty for the work (except to the extent that warranties are provided), that\nlicensees may convey the work under this License, and how to view a copy of this\nLicense. If the interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n### 1. Source Code\n\nThe “source code” for a work means the preferred form of the work for\nmaking modifications to it. “Object code” means any non-source form of a\nwork.\n\nA “Standard Interface” means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of interfaces\nspecified for a particular programming language, one that is widely used among\ndevelopers working in that language.\n\nThe “System Libraries” of an executable work include anything, other than\nthe work as a whole, that **(a)** is included in the normal form of packaging a Major\nComponent, but which is not part of that Major Component, and **(b)** serves only to\nenable use of the work with that Major Component, or to implement a Standard\nInterface for which an implementation is available to the public in source code form.\nA “Major Component”, in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system (if any) on which\nthe executable work runs, or a compiler used to produce the work, or an object code\ninterpreter used to run it.\n\nThe “Corresponding Source” for a work in object code form means all the\nsource code needed to generate, install, and (for an executable work) run the object\ncode and to modify the work, including scripts to control those activities. However,\nit does not include the work's System Libraries, or general-purpose tools or\ngenerally available free programs which are used unmodified in performing those\nactivities but which are not part of the work. For example, Corresponding Source\nincludes interface definition files associated with source files for the work, and\nthe source code for shared libraries and dynamically linked subprograms that the work\nis specifically designed to require, such as by intimate data communication or\ncontrol flow between those subprograms and other parts of the work.\n\nThe Corresponding Source need not include anything that users can regenerate\nautomatically from other parts of the Corresponding Source.\n\nThe Corresponding Source for a work in source code form is that same work.\n\n### 2. Basic Permissions\n\nAll rights granted under this License are granted for the term of copyright on the\nProgram, and are irrevocable provided the stated conditions are met. This License\nexplicitly affirms your unlimited permission to run the unmodified Program. The\noutput from running a covered work is covered by this License only if the output,\ngiven its content, constitutes a covered work. This License acknowledges your rights\nof fair use or other equivalent, as provided by copyright law.\n\nYou may make, run and propagate covered works that you do not convey, without\nconditions so long as your license otherwise remains in force. You may convey covered\nworks to others for the sole purpose of having them make modifications exclusively\nfor you, or provide you with facilities for running those works, provided that you\ncomply with the terms of this License in conveying all material for which you do not\ncontrol copyright. Those thus making or running the covered works for you must do so\nexclusively on your behalf, under your direction and control, on terms that prohibit\nthem from making any copies of your copyrighted material outside their relationship\nwith you.\n\nConveying under any other circumstances is permitted solely under the conditions\nstated below. Sublicensing is not allowed; section 10 makes it unnecessary.\n\n### 3. Protecting Users' Legal Rights From Anti-Circumvention Law\n\nNo covered work shall be deemed part of an effective technological measure under any\napplicable law fulfilling obligations under article 11 of the WIPO copyright treaty\nadopted on 20 December 1996, or similar laws prohibiting or restricting circumvention\nof such measures.\n\nWhen you convey a covered work, you waive any legal power to forbid circumvention of\ntechnological measures to the extent such circumvention is effected by exercising\nrights under this License with respect to the covered work, and you disclaim any\nintention to limit operation or modification of the work as a means of enforcing,\nagainst the work's users, your or third parties' legal rights to forbid circumvention\nof technological measures.\n\n### 4. Conveying Verbatim Copies\n\nYou may convey verbatim copies of the Program's source code as you receive it, in any\nmedium, provided that you conspicuously and appropriately publish on each copy an\nappropriate copyright notice; keep intact all notices stating that this License and\nany non-permissive terms added in accord with section 7 apply to the code; keep\nintact all notices of the absence of any warranty; and give all recipients a copy of\nthis License along with the Program.\n\nYou may charge any price or no price for each copy that you convey, and you may offer\nsupport or warranty protection for a fee.\n\n### 5. Conveying Modified Source Versions\n\nYou may convey a work based on the Program, or the modifications to produce it from\nthe Program, in the form of source code under the terms of section 4, provided that\nyou also meet all of these conditions:\n\n* **a)** The work must carry prominent notices stating that you modified it, and giving a\nrelevant date.\n* **b)** The work must carry prominent notices stating that it is released under this\nLicense and any conditions added under section 7. This requirement modifies the\nrequirement in section 4 to “keep intact all notices”.\n* **c)** You must license the entire work, as a whole, under this License to anyone who\ncomes into possession of a copy. This License will therefore apply, along with any\napplicable section 7 additional terms, to the whole of the work, and all its parts,\nregardless of how they are packaged. This License gives no permission to license the\nwork in any other way, but it does not invalidate such permission if you have\nseparately received it.\n* **d)** If the work has interactive user interfaces, each must display Appropriate Legal\nNotices; however, if the Program has interactive interfaces that do not display\nAppropriate Legal Notices, your work need not make them do so.\n\nA compilation of a covered work with other separate and independent works, which are\nnot by their nature extensions of the covered work, and which are not combined with\nit such as to form a larger program, in or on a volume of a storage or distribution\nmedium, is called an “aggregate” if the compilation and its resulting\ncopyright are not used to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit. Inclusion of a covered work in an aggregate\ndoes not cause this License to apply to the other parts of the aggregate.\n\n### 6. Conveying Non-Source Forms\n\nYou may convey a covered work in object code form under the terms of sections 4 and\n5, provided that you also convey the machine-readable Corresponding Source under the\nterms of this License, in one of these ways:\n\n* **a)** Convey the object code in, or embodied in, a physical product (including a\nphysical distribution medium), accompanied by the Corresponding Source fixed on a\ndurable physical medium customarily used for software interchange.\n* **b)** Convey the object code in, or embodied in, a physical product (including a\nphysical distribution medium), accompanied by a written offer, valid for at least\nthree years and valid for as long as you offer spare parts or customer support for\nthat product model, to give anyone who possesses the object code either **(1)** a copy of\nthe Corresponding Source for all the software in the product that is covered by this\nLicense, on a durable physical medium customarily used for software interchange, for\na price no more than your reasonable cost of physically performing this conveying of\nsource, or **(2)** access to copy the Corresponding Source from a network server at no\ncharge.\n* **c)** Convey individual copies of the object code with a copy of the written offer to\nprovide the Corresponding Source. This alternative is allowed only occasionally and\nnoncommercially, and only if you received the object code with such an offer, in\naccord with subsection 6b.\n* **d)** Convey the object code by offering access from a designated place (gratis or for\na charge), and offer equivalent access to the Corresponding Source in the same way\nthrough the same place at no further charge. You need not require recipients to copy\nthe Corresponding Source along with the object code. If the place to copy the object\ncode is a network server, the Corresponding Source may be on a different server\n(operated by you or a third party) that supports equivalent copying facilities,\nprovided you maintain clear directions next to the object code saying where to find\nthe Corresponding Source. Regardless of what server hosts the Corresponding Source,\nyou remain obligated to ensure that it is available for as long as needed to satisfy\nthese requirements.\n* **e)** Convey the object code using peer-to-peer transmission, provided you inform\nother peers where the object code and Corresponding Source of the work are being\noffered to the general public at no charge under subsection 6d.\n\nA separable portion of the object code, whose source code is excluded from the\nCorresponding Source as a System Library, need not be included in conveying the\nobject code work.\n\nA “User Product” is either **(1)** a “consumer product”, which\nmeans any tangible personal property which is normally used for personal, family, or\nhousehold purposes, or **(2)** anything designed or sold for incorporation into a\ndwelling. In determining whether a product is a consumer product, doubtful cases\nshall be resolved in favor of coverage. For a particular product received by a\nparticular user, “normally used” refers to a typical or common use of\nthat class of product, regardless of the status of the particular user or of the way\nin which the particular user actually uses, or expects or is expected to use, the\nproduct. A product is a consumer product regardless of whether the product has\nsubstantial commercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n“Installation Information” for a User Product means any methods,\nprocedures, authorization keys, or other information required to install and execute\nmodified versions of a covered work in that User Product from a modified version of\nits Corresponding Source. The information must suffice to ensure that the continued\nfunctioning of the modified object code is in no case prevented or interfered with\nsolely because modification has been made.\n\nIf you convey an object code work under this section in, or with, or specifically for\nuse in, a User Product, and the conveying occurs as part of a transaction in which\nthe right of possession and use of the User Product is transferred to the recipient\nin perpetuity or for a fixed term (regardless of how the transaction is\ncharacterized), the Corresponding Source conveyed under this section must be\naccompanied by the Installation Information. But this requirement does not apply if\nneither you nor any third party retains the ability to install modified object code\non the User Product (for example, the work has been installed in ROM).\n\nThe requirement to provide Installation Information does not include a requirement to\ncontinue to provide support service, warranty, or updates for a work that has been\nmodified or installed by the recipient, or for the User Product in which it has been\nmodified or installed. Access to a network may be denied when the modification itself\nmaterially and adversely affects the operation of the network or violates the rules\nand protocols for communication across the network.\n\nCorresponding Source conveyed, and Installation Information provided, in accord with\nthis section must be in a format that is publicly documented (and with an\nimplementation available to the public in source code form), and must require no\nspecial password or key for unpacking, reading or copying.\n\n### 7. Additional Terms\n\n“Additional permissions” are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions. Additional\npermissions that are applicable to the entire Program shall be treated as though they\nwere included in this License, to the extent that they are valid under applicable\nlaw. If additional permissions apply only to part of the Program, that part may be\nused separately under those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\nWhen you convey a copy of a covered work, you may at your option remove any\nadditional permissions from that copy, or from any part of it. (Additional\npermissions may be written to require their own removal in certain cases when you\nmodify the work.) You may place additional permissions on material, added by you to a\ncovered work, for which you have or can give appropriate copyright permission.\n\nNotwithstanding any other provision of this License, for material you add to a\ncovered work, you may (if authorized by the copyright holders of that material)\nsupplement the terms of this License with terms:\n\n* **a)** Disclaiming warranty or limiting liability differently from the terms of\nsections 15 and 16 of this License; or\n* **b)** Requiring preservation of specified reasonable legal notices or author\nattributions in that material or in the Appropriate Legal Notices displayed by works\ncontaining it; or\n* **c)** Prohibiting misrepresentation of the origin of that material, or requiring that\nmodified versions of such material be marked in reasonable ways as different from the\noriginal version; or\n* **d)** Limiting the use for publicity purposes of names of licensors or authors of the\nmaterial; or\n* **e)** Declining to grant rights under trademark law for use of some trade names,\ntrademarks, or service marks; or\n* **f)** Requiring indemnification of licensors and authors of that material by anyone\nwho conveys the material (or modified versions of it) with contractual assumptions of\nliability to the recipient, for any liability that these contractual assumptions\ndirectly impose on those licensors and authors.\n\nAll other non-permissive additional terms are considered “further\nrestrictions” within the meaning of section 10. If the Program as you received\nit, or any part of it, contains a notice stating that it is governed by this License\nalong with a term that is a further restriction, you may remove that term. If a\nlicense document contains a further restriction but permits relicensing or conveying\nunder this License, you may add to a covered work material governed by the terms of\nthat license document, provided that the further restriction does not survive such\nrelicensing or conveying.\n\nIf you add terms to a covered work in accord with this section, you must place, in\nthe relevant source files, a statement of the additional terms that apply to those\nfiles, or a notice indicating where to find the applicable terms.\n\nAdditional terms, permissive or non-permissive, may be stated in the form of a\nseparately written license, or stated as exceptions; the above requirements apply\neither way.\n\n### 8. Termination\n\nYou may not propagate or modify a covered work except as expressly provided under\nthis License. Any attempt otherwise to propagate or modify it is void, and will\nautomatically terminate your rights under this License (including any patent licenses\ngranted under the third paragraph of section 11).\n\nHowever, if you cease all violation of this License, then your license from a\nparticular copyright holder is reinstated **(a)** provisionally, unless and until the\ncopyright holder explicitly and finally terminates your license, and **(b)** permanently,\nif the copyright holder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\nMoreover, your license from a particular copyright holder is reinstated permanently\nif the copyright holder notifies you of the violation by some reasonable means, this\nis the first time you have received notice of violation of this License (for any\nwork) from that copyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\nTermination of your rights under this section does not terminate the licenses of\nparties who have received copies or rights from you under this License. If your\nrights have been terminated and not permanently reinstated, you do not qualify to\nreceive new licenses for the same material under section 10.\n\n### 9. Acceptance Not Required for Having Copies\n\nYou are not required to accept this License in order to receive or run a copy of the\nProgram. Ancillary propagation of a covered work occurring solely as a consequence of\nusing peer-to-peer transmission to receive a copy likewise does not require\nacceptance. However, nothing other than this License grants you permission to\npropagate or modify any covered work. These actions infringe copyright if you do not\naccept this License. Therefore, by modifying or propagating a covered work, you\nindicate your acceptance of this License to do so.\n\n### 10. Automatic Licensing of Downstream Recipients\n\nEach time you convey a covered work, the recipient automatically receives a license\nfrom the original licensors, to run, modify and propagate that work, subject to this\nLicense. You are not responsible for enforcing compliance by third parties with this\nLicense.\n\nAn “entity transaction” is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an organization, or\nmerging organizations. If propagation of a covered work results from an entity\ntransaction, each party to that transaction who receives a copy of the work also\nreceives whatever licenses to the work the party's predecessor in interest had or\ncould give under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if the predecessor\nhas it or can get it with reasonable efforts.\n\nYou may not impose any further restrictions on the exercise of the rights granted or\naffirmed under this License. For example, you may not impose a license fee, royalty,\nor other charge for exercise of rights granted under this License, and you may not\ninitiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging\nthat any patent claim is infringed by making, using, selling, offering for sale, or\nimporting the Program or any portion of it.\n\n### 11. Patents\n\nA “contributor” is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based. The work thus\nlicensed is called the contributor's “contributor version”.\n\nA contributor's “essential patent claims” are all patent claims owned or\ncontrolled by the contributor, whether already acquired or hereafter acquired, that\nwould be infringed by some manner, permitted by this License, of making, using, or\nselling its contributor version, but do not include claims that would be infringed\nonly as a consequence of further modification of the contributor version. For\npurposes of this definition, “control” includes the right to grant patent\nsublicenses in a manner consistent with the requirements of this License.\n\nEach contributor grants you a non-exclusive, worldwide, royalty-free patent license\nunder the contributor's essential patent claims, to make, use, sell, offer for sale,\nimport and otherwise run, modify and propagate the contents of its contributor\nversion.\n\nIn the following three paragraphs, a “patent license” is any express\nagreement or commitment, however denominated, not to enforce a patent (such as an\nexpress permission to practice a patent or covenant not to sue for patent\ninfringement). To “grant” such a patent license to a party means to make\nsuch an agreement or commitment not to enforce a patent against the party.\n\nIf you convey a covered work, knowingly relying on a patent license, and the\nCorresponding Source of the work is not available for anyone to copy, free of charge\nand under the terms of this License, through a publicly available network server or\nother readily accessible means, then you must either **(1)** cause the Corresponding\nSource to be so available, or **(2)** arrange to deprive yourself of the benefit of the\npatent license for this particular work, or **(3)** arrange, in a manner consistent with\nthe requirements of this License, to extend the patent license to downstream\nrecipients. “Knowingly relying” means you have actual knowledge that, but\nfor the patent license, your conveying the covered work in a country, or your\nrecipient's use of the covered work in a country, would infringe one or more\nidentifiable patents in that country that you have reason to believe are valid.\n\nIf, pursuant to or in connection with a single transaction or arrangement, you\nconvey, or propagate by procuring conveyance of, a covered work, and grant a patent\nlicense to some of the parties receiving the covered work authorizing them to use,\npropagate, modify or convey a specific copy of the covered work, then the patent\nlicense you grant is automatically extended to all recipients of the covered work and\nworks based on it.\n\nA patent license is “discriminatory” if it does not include within the\nscope of its coverage, prohibits the exercise of, or is conditioned on the\nnon-exercise of one or more of the rights that are specifically granted under this\nLicense. You may not convey a covered work if you are a party to an arrangement with\na third party that is in the business of distributing software, under which you make\npayment to the third party based on the extent of your activity of conveying the\nwork, and under which the third party grants, to any of the parties who would receive\nthe covered work from you, a discriminatory patent license **(a)** in connection with\ncopies of the covered work conveyed by you (or copies made from those copies), or **(b)**\nprimarily for and in connection with specific products or compilations that contain\nthe covered work, unless you entered into that arrangement, or that patent license\nwas granted, prior to 28 March 2007.\n\nNothing in this License shall be construed as excluding or limiting any implied\nlicense or other defenses to infringement that may otherwise be available to you\nunder applicable patent law.\n\n### 12. No Surrender of Others' Freedom\n\nIf conditions are imposed on you (whether by court order, agreement or otherwise)\nthat contradict the conditions of this License, they do not excuse you from the\nconditions of this License. If you cannot convey a covered work so as to satisfy\nsimultaneously your obligations under this License and any other pertinent\nobligations, then as a consequence you may not convey it at all. For example, if you\nagree to terms that obligate you to collect a royalty for further conveying from\nthose to whom you convey the Program, the only way you could satisfy both those terms\nand this License would be to refrain entirely from conveying the Program.\n\n### 13. Use with the GNU Affero General Public License\n\nNotwithstanding any other provision of this License, you have permission to link or\ncombine any covered work with a work licensed under version 3 of the GNU Affero\nGeneral Public License into a single combined work, and to convey the resulting work.\nThe terms of this License will continue to apply to the part which is the covered\nwork, but the special requirements of the GNU Affero General Public License, section\n13, concerning interaction through a network will apply to the combination as such.\n\n### 14. Revised Versions of this License\n\nThe Free Software Foundation may publish revised and/or new versions of the GNU\nGeneral Public License from time to time. Such new versions will be similar in spirit\nto the present version, but may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number. If the Program specifies that\na certain numbered version of the GNU General Public License “or any later\nversion” applies to it, you have the option of following the terms and\nconditions either of that numbered version or of any later version published by the\nFree Software Foundation. If the Program does not specify a version number of the GNU\nGeneral Public License, you may choose any version ever published by the Free\nSoftware Foundation.\n\nIf the Program specifies that a proxy can decide which future versions of the GNU\nGeneral Public License can be used, that proxy's public statement of acceptance of a\nversion permanently authorizes you to choose that version for the Program.\n\nLater license versions may give you additional or different permissions. However, no\nadditional obligations are imposed on any author or copyright holder as a result of\nyour choosing to follow a later version.\n\n### 15. Disclaimer of Warranty\n\nTHERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.\nEXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER\nEXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE\nQUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE\nDEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n### 16. Limitation of Liability\n\nIN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY\nCOPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS\nPERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,\nINCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE\nPROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE\nOR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE\nWITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n### 17. Interpretation of Sections 15 and 16\n\nIf the disclaimer of warranty and limitation of liability provided above cannot be\ngiven local legal effect according to their terms, reviewing courts shall apply local\nlaw that most closely approximates an absolute waiver of all civil liability in\nconnection with the Program, unless a warranty or assumption of liability accompanies\na copy of the Program in return for a fee.\n\n_END OF TERMS AND CONDITIONS_\n\n## How to Apply These Terms to Your New Programs\n\nIf you develop a new program, and you want it to be of the greatest possible use to\nthe public, the best way to achieve this is to make it free software which everyone\ncan redistribute and change under these terms.\n\nTo do so, attach the following notices to the program. It is safest to attach them\nto the start of each source file to most effectively state the exclusion of warranty;\nand each file should have at least the “copyright” line and a pointer to\nwhere the full notice is found.\n\n    datamods: Modules to Import and Manipulate Data in 'Shiny' Applications\n    Copyright (C) 2020 Victor PERRIER\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program does terminal interaction, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    datamods Copyright (C) 2020 Victor PERRIER\n    This program comes with ABSOLUTELY NO WARRANTY; for details type 'show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type 'show c' for details.\n\nThe hypothetical commands `show w` and `show c` should show the appropriate parts of\nthe General Public License. Of course, your program's commands might be different;\nfor a GUI interface, you would use an “about box”.\n\nYou should also get your employer (if you work as a programmer) or school, if any, to\nsign a “copyright disclaimer” for the program, if necessary. For more\ninformation on this, and how to apply and follow the GNU GPL, see\n&lt;<http://www.gnu.org/licenses/>&gt;.\n\nThe GNU General Public License does not permit incorporating your program into\nproprietary programs. If your program is a subroutine library, you may consider it\nmore useful to permit linking proprietary applications with the library. If this is\nwhat you want to do, use the GNU Lesser General Public License instead of this\nLicense. But first, please read\n&lt;<http://www.gnu.org/philosophy/why-not-lgpl.html>&gt;.\n"
  },
  {
    "path": "NAMESPACE",
    "content": "# Generated by roxygen2: do not edit by hand\n\nexport(create_column_server)\nexport(create_column_ui)\nexport(cut_variable_server)\nexport(cut_variable_ui)\nexport(edit_data_server)\nexport(edit_data_ui)\nexport(filter_data_server)\nexport(filter_data_ui)\nexport(get_data_packages)\nexport(i18n)\nexport(i18n_translations)\nexport(import_copypaste_server)\nexport(import_copypaste_ui)\nexport(import_file_server)\nexport(import_file_ui)\nexport(import_globalenv_server)\nexport(import_globalenv_ui)\nexport(import_googlesheets_server)\nexport(import_googlesheets_ui)\nexport(import_modal)\nexport(import_server)\nexport(import_ui)\nexport(import_url_server)\nexport(import_url_ui)\nexport(list_allowed_operations)\nexport(list_pkg_data)\nexport(modal_create_column)\nexport(modal_cut_variable)\nexport(modal_update_factor)\nexport(sample_server)\nexport(sample_ui)\nexport(select_group_server)\nexport(select_group_ui)\nexport(set_i18n)\nexport(show_data)\nexport(update_factor_server)\nexport(update_factor_ui)\nexport(update_variables_server)\nexport(update_variables_ui)\nexport(validation_server)\nexport(validation_ui)\nexport(winbox_create_column)\nexport(winbox_cut_variable)\nexport(winbox_update_factor)\nimportFrom(bslib,bs_current_theme)\nimportFrom(bslib,bs_get_variables)\nimportFrom(bslib,is_bs_theme)\nimportFrom(classInt,classIntervals)\nimportFrom(data.table,\":=\")\nimportFrom(data.table,.N)\nimportFrom(data.table,.SD)\nimportFrom(data.table,as.data.table)\nimportFrom(data.table,copy)\nimportFrom(data.table,data.table)\nimportFrom(data.table,fread)\nimportFrom(data.table,setattr)\nimportFrom(data.table,setnames)\nimportFrom(data.table,setorderv)\nimportFrom(data.table,uniqueN)\nimportFrom(graphics,abline)\nimportFrom(graphics,axis)\nimportFrom(graphics,hist)\nimportFrom(graphics,par)\nimportFrom(graphics,plot.new)\nimportFrom(graphics,plot.window)\nimportFrom(htmltools,HTML)\nimportFrom(htmltools,css)\nimportFrom(htmltools,div)\nimportFrom(htmltools,doRenderTags)\nimportFrom(htmltools,htmlDependency)\nimportFrom(htmltools,singleton)\nimportFrom(htmltools,tagAppendAttributes)\nimportFrom(htmltools,tagAppendChild)\nimportFrom(htmltools,tagList)\nimportFrom(htmltools,tags)\nimportFrom(htmltools,validateCssUnit)\nimportFrom(phosphoricons,ph)\nimportFrom(reactable,colDef)\nimportFrom(reactable,getReactableState)\nimportFrom(reactable,reactable)\nimportFrom(reactable,reactableOutput)\nimportFrom(reactable,renderReactable)\nimportFrom(reactable,updateReactable)\nimportFrom(readxl,excel_sheets)\nimportFrom(rio,import)\nimportFrom(rlang,\"%||%\")\nimportFrom(rlang,as_function)\nimportFrom(rlang,as_label)\nimportFrom(rlang,call2)\nimportFrom(rlang,enquo)\nimportFrom(rlang,eval_tidy)\nimportFrom(rlang,exec)\nimportFrom(rlang,expr)\nimportFrom(rlang,fn_fmls_names)\nimportFrom(rlang,is_double)\nimportFrom(rlang,is_function)\nimportFrom(rlang,is_list)\nimportFrom(rlang,is_named)\nimportFrom(rlang,is_null)\nimportFrom(rlang,is_vector)\nimportFrom(rlang,parse_expr)\nimportFrom(rlang,set_names)\nimportFrom(rlang,sym)\nimportFrom(rlang,syms)\nimportFrom(shiny,NS)\nimportFrom(shiny,actionButton)\nimportFrom(shiny,actionLink)\nimportFrom(shiny,addResourcePath)\nimportFrom(shiny,bindEvent)\nimportFrom(shiny,checkboxInput)\nimportFrom(shiny,column)\nimportFrom(shiny,conditionalPanel)\nimportFrom(shiny,dateRangeInput)\nimportFrom(shiny,downloadButton)\nimportFrom(shiny,downloadHandler)\nimportFrom(shiny,eventReactive)\nimportFrom(shiny,fileInput)\nimportFrom(shiny,fluidRow)\nimportFrom(shiny,getDefaultReactiveDomain)\nimportFrom(shiny,hideTab)\nimportFrom(shiny,icon)\nimportFrom(shiny,insertUI)\nimportFrom(shiny,is.reactive)\nimportFrom(shiny,isTruthy)\nimportFrom(shiny,isolate)\nimportFrom(shiny,modalDialog)\nimportFrom(shiny,moduleServer)\nimportFrom(shiny,need)\nimportFrom(shiny,numericInput)\nimportFrom(shiny,observe)\nimportFrom(shiny,observeEvent)\nimportFrom(shiny,outputOptions)\nimportFrom(shiny,plotOutput)\nimportFrom(shiny,reactive)\nimportFrom(shiny,reactiveVal)\nimportFrom(shiny,reactiveValues)\nimportFrom(shiny,reactiveValuesToList)\nimportFrom(shiny,removeModal)\nimportFrom(shiny,removeUI)\nimportFrom(shiny,renderPlot)\nimportFrom(shiny,renderUI)\nimportFrom(shiny,req)\nimportFrom(shiny,selectizeInput)\nimportFrom(shiny,showModal)\nimportFrom(shiny,singleton)\nimportFrom(shiny,sliderInput)\nimportFrom(shiny,tabPanel)\nimportFrom(shiny,tabPanelBody)\nimportFrom(shiny,tabsetPanel)\nimportFrom(shiny,tagList)\nimportFrom(shiny,tags)\nimportFrom(shiny,textAreaInput)\nimportFrom(shiny,textInput)\nimportFrom(shiny,uiOutput)\nimportFrom(shiny,updateActionButton)\nimportFrom(shiny,updateSliderInput)\nimportFrom(shiny,updateTabsetPanel)\nimportFrom(shiny,updateTextAreaInput)\nimportFrom(shiny,validate)\nimportFrom(shinyWidgets,WinBox)\nimportFrom(shinyWidgets,airDatepickerInput)\nimportFrom(shinyWidgets,alert)\nimportFrom(shinyWidgets,dropMenu)\nimportFrom(shinyWidgets,html_dependency_pretty)\nimportFrom(shinyWidgets,noUiSliderInput)\nimportFrom(shinyWidgets,numericInputIcon)\nimportFrom(shinyWidgets,numericRangeInput)\nimportFrom(shinyWidgets,pickerInput)\nimportFrom(shinyWidgets,pickerOptions)\nimportFrom(shinyWidgets,prettyCheckbox)\nimportFrom(shinyWidgets,prettySwitch)\nimportFrom(shinyWidgets,radioGroupButtons)\nimportFrom(shinyWidgets,show_alert)\nimportFrom(shinyWidgets,textInputIcon)\nimportFrom(shinyWidgets,updatePickerInput)\nimportFrom(shinyWidgets,updateVirtualSelect)\nimportFrom(shinyWidgets,virtualSelectInput)\nimportFrom(shinyWidgets,wbControls)\nimportFrom(shinyWidgets,wbOptions)\nimportFrom(shinybusy,notify_failure)\nimportFrom(shinybusy,notify_info)\nimportFrom(shinybusy,notify_success)\nimportFrom(shinybusy,notify_warning)\nimportFrom(stats,setNames)\nimportFrom(tibble,as_tibble)\nimportFrom(toastui,datagrid)\nimportFrom(toastui,datagridOutput)\nimportFrom(toastui,datagridOutput2)\nimportFrom(toastui,grid_colorbar)\nimportFrom(toastui,grid_columns)\nimportFrom(toastui,grid_editor)\nimportFrom(toastui,grid_editor_opts)\nimportFrom(toastui,grid_format)\nimportFrom(toastui,grid_selection_row)\nimportFrom(toastui,grid_style_column)\nimportFrom(toastui,renderDatagrid)\nimportFrom(toastui,renderDatagrid2)\nimportFrom(tools,file_ext)\nimportFrom(utils,data)\nimportFrom(utils,getFromNamespace)\nimportFrom(utils,hasName)\nimportFrom(utils,head)\nimportFrom(utils,modifyList)\nimportFrom(utils,packageName)\nimportFrom(utils,packageVersion)\nimportFrom(utils,type.convert)\nimportFrom(utils,write.csv)\nimportFrom(writexl,write_xlsx)\n"
  },
  {
    "path": "NEWS.md",
    "content": "# datamods 1.5.4\n\n* Rename CSS class `show` to `show-block` (used internally).\n* `select_group_server()`: added argument `selected_r =` to set selected values.\n\n\n# datamods 1.5.3\n\n* `update_variables_server`: change of data update management after clicking on the validate button, fixed a problem when input data are the same as output data.\n\n\n# datamods 1.5.2\n\n* `import_file_ui`: back to old parameters layout inside a dropdown button and new argument to switch to inline layout. \n* `edit_data_server`: allow to use reactive function for reactable_options.\n* cut variable module (`cut_variable_ui`/`cut_variable_server`): allow to select fixed breaks.\n\n\n# datamods 1.5.1\n\n* New module `update_factor_ui()` / `update_factor_server()` to reorder levels of a factor.\n* i18n: Updated translations files with new labels, which are automatically translated, if you see incorrect translations, please open an issue or PR : https://github.com/dreamRs/datamods\n\n\n# datamods 1.5.0\n\n* New module `create_column_ui()` / `create_column_server()` to add new column based on an expression to a `data.frame`.\n* New module `cut_variable_ui()` / `cut_variable_server()` to cut a numeric factor into several interval.\n\n\n# datamods 1.4.5\n\n* `edit_data_server()` : fixed default variable labels when `var_labels = NULL`.\n\n\n# datamods 1.4.4\n\n* `edit_data_server()` : added argument `add_default_values = list(...)` to specify default value for input widget when adding a new entry in the table.\n\n\n# datamods 1.4.3\n\n* `edit_data_server()` : added the ability to specify callbacks functions to be executed before performing an action on the table (add, update or delete).\n* `edit_data_server()` : pass reactable option + selection to the table [#82](https://github.com/dreamRs/datamods/pull/82)\n* `edit-data` module : use factor levels and sort theme in edit input form for factors (sorting also applies for characters), thanks to [@Felixmil](https://github.com/Felixmil).\n* `import-file` module : allow to specify string used to identify `NA`, thanks to [@DrFabach](https://github.com/DrFabach).\n* `filter_data_server()` : argument `drop_ids` can now be set via option `datamods.filter.drop_ids` and can be a list like `list(p = 0.9, n = 50)` to specify threshold values to remove IDs columns.\n\n\n# datamods 1.4.2\n\n* i18n: japanese translations added, thanks to [@nissinbo](https://github.com/nissinbo).\n* `select_group_server()` : output value now have an `inputs` attribute with a named list of selected inputs values.\n\n\n# datamods 1.4.1\n\n* i18n: polish translations added, thanks to [@jakub-jedrusiak](https://github.com/jakub-jedrusiak).\n\n### Bug fixes\n* Fixed displaying variable class in View tab (fix [#64](https://github.com/dreamRs/datamods/issues/64)).\n* `select_group_server()` : fix update inputs when `multiple = FALSE`.\n* `filter_data_server()` : sorting choices in select menus (select, picker and virtual) (fix [#66](https://github.com/dreamRs/datamods/issues/64))).\n* `filter_data_server()` : don't use `<`/`>` for empty field to not confuse to an HTML tag (fix [#65](https://github.com/dreamRs/datamods/issues/65))).\n\n\n# datamods 1.4.0\n\n* New module : `edit_data_ui()` / `edit_data_server()` to interactively edit a `data.frame`, thanks to [@ggsamra](https://github.com/ggsamra).\n* New module : `sample_ui()` / `sample_server()` to take a sample from a table, thanks to [@ggsamra](https://github.com/ggsamra).\n\n\n\n# datamods 1.3.4\n\n* i18n: korean translations added, thanks to [@ChangwooLim](https://github.com/ChangwooLim) (migrated from esquisse package).\n* `import_ui()` / `import_modal()`: added `file_extensions` argument passed to `import_file_ui()` (fix [#51](https://github.com/dreamRs/datamods/issues/51)).\n\n\n\n# datamods 1.3.3\n\n* i18n: turkish translations added, thanks to [@sbalci](https://github.com/sbalci).\n* `filter_data` module now support getting and setting filter values, thanks to [@bellma-lilly](https://github.com/bellma-lilly).\n\n\n\n# datamods 1.3.2\n\n* Fix bad link in NEWS.\n\n\n\n# datamods 1.3.1\n\n* Fixed a bug in `update_variables` module.\n\n\n\n# datamods 1.3.0\n\n* New module to read flat data from URLs `import_url_*()`.\n* Error messages displayed to the user are more informative on the actual error.\n* `filter_data_server()`: new argument `value_na` to set default value for NA's filters widgets.\n* `import_copypaste_ui()`: new argument `name_field` to show or not name field.\n* `import_copypaste_server()`: new argument `fread_args` to pass arguments to `data.table::fread`.\n* i18n: chinese translations added, thanks to [@xmusphlkg](https://github.com/xmusphlkg).\n* i18n: spanish translations added, thanks to [@dnldelarosa](https://github.com/dnldelarosa).\n* i18n: german translations added, thanks to [@SteEcker](https://github.com/SteEcker) and joerghenkebuero.\n\n\n\n# datamods 1.2.0\n\n* Switch to [{phosphoricons}](https://github.com/dreamRs/phosphoricons) for icons.\n* `import_file_ui()` has a new argument `file_extensions` to select the files that the user can import.\n* `import_file_server()` has a new argument `read_fns` to define custom function(s) to read data.\n\n### Translations\n* i18n: :macedonia: macedonian translations added, thanks to [@novica](https://github.com/novica).\n* i18n: :albania: albanian translations added, thanks to [@novica](https://github.com/novica).\n* i18n: :portugal: :brazil: brazilian portuguese translations added, thanks to [@gabrielteotonio](https://github.com/gabrielteotonio).\n\n\n\n# datamods 1.1.5\n\n* `import_*_server()` added reset argument to clear the data.\n* `import_copypaste_server()` also return a `reactive` function \"name\" like the others.\n* New function `i18n()` to add internationalization in shiny apps.\n\n\n\n# datamods 1.1.4\n\n* `filter_data_server`: convert data to `data.frame` (fix [esquisse #149](https://github.com/dreamRs/esquisse/issues/149)).\n* `filter_data_server`: fixed bug with timezone if POSIXct.\n* Import data from package: use `pkg::data` notation for data's name.\n\n\n\n# datamods 1.1.3\n\n* Preserve class `sf` in output.\n\n\n\n# datamods 1.1.2\n\n* Fixed a bug when retrieving data from package with parenthesis in name.\n* Fixed test on R-oldrel\n\n\n\n# datamods 1.1.0\n\n* Added internationalization to translate labels used in modules, see corresponding vignette.\n\n\n\n# datamods 1.0.1\n\n* First release on CRAN: Shiny modules import, to update, validate and filter data in interactive applications\n* Added a `NEWS.md` file to track changes to the package.\n"
  },
  {
    "path": "R/create-column.R",
    "content": "\n#' @title Create new column\n#'\n#' @description\n#' This module allow to enter an expression to create a new column in a `data.frame`.\n#'\n#'\n#' @param id Module's ID.\n#'\n#' @return A [shiny::reactive()] function returning the data.\n#'\n#' @note User can only use a subset of function: `r paste(list_allowed_operations(), collapse=\", \")`.\n#'  You can add more operations using the `allowed_operations` argument, for  example if you want to allow to use package lubridate, you can do:\n#'  ```r\n#'  c(list_allowed_operations(), getNamespaceExports(\"lubridate\"))\n#'  ```\n#'\n#' @export\n#'\n#' @importFrom htmltools tagList tags css\n#' @importFrom shiny NS textInput textAreaInput uiOutput actionButton\n#' @importFrom phosphoricons ph\n#' @importFrom shinyWidgets virtualSelectInput\n#'\n#' @name create-column\n#'\n#' @example examples/create_column.R\ncreate_column_ui <- function(id) {\n  ns <- NS(id)\n  tagList(\n    html_dependency_datamods(),\n    fluidRow(\n      column(\n        width = 6,\n        textInput(\n          inputId = ns(\"new_column\"),\n          label = i18n(\"New column name:\"),\n          value = \"new_column1\",\n          width = \"100%\"\n        )\n      ),\n      column(\n        width = 6,\n        virtualSelectInput(\n          inputId = ns(\"group_by\"),\n          label = i18n(\"Group calculation by:\"),\n          choices = NULL,\n          multiple = TRUE,\n          disableSelectAll = TRUE,\n          hasOptionDescription = TRUE,\n          width = \"100%\"\n        )\n      )\n    ),\n    textAreaInput(\n      inputId = ns(\"expression\"),\n      label = i18n(\"Enter an expression to define new column:\"),\n      value = \"\",\n      width = \"100%\",\n      rows = 6\n    ),\n    tags$i(\n      class = \"d-block\",\n      ph(\"info\"),\n      i18n(\"Click on a column name to add it to the expression:\")\n    ),\n    uiOutput(outputId = ns(\"columns\")),\n    uiOutput(outputId = ns(\"feedback\")),\n    tags$div(\n      style = css(\n        display = \"grid\",\n        gridTemplateColumns = \"3fr 1fr\",\n        columnGap = \"10px\",\n        margin = \"10px 0\"\n      ),\n      actionButton(\n        inputId = ns(\"compute\"),\n        label = tagList(\n          ph(\"gear\"), i18n(\"Create column\")\n        ),\n        class = \"btn-outline-primary\",\n        width = \"100%\"\n      ),\n      actionButton(\n        inputId = ns(\"remove\"),\n        label = tagList(\n          ph(\"trash\")\n        ),\n        class = \"btn-outline-danger\",\n        width = \"100%\"\n      )\n    )\n  )\n}\n\n#' @param data_r A [shiny::reactive()] function returning a `data.frame`.\n#' @param allowed_operations A `list` of allowed operations, see below for details.\n#'\n#' @export\n#'\n#' @rdname create-column\n#'\n#' @importFrom shiny moduleServer reactiveValues observeEvent renderUI req\n#'  updateTextAreaInput reactive bindEvent observe\n#' @importFrom shinyWidgets alert updateVirtualSelect\ncreate_column_server <- function(id,\n                                 data_r = reactive(NULL),\n                                 allowed_operations = list_allowed_operations()) {\n  moduleServer(\n    id,\n    function(input, output, session) {\n\n      ns <- session$ns\n\n      info_alert <- alert(\n        status = \"info\",\n        ph(\"question\"),\n        i18n(\"Choose a name for the column to be created or modified,\"),\n        i18n(\"then enter an expression before clicking on the button above to validate or on \"),\n        ph(\"trash\"), i18n(\"to delete it.\")\n      )\n\n      rv <- reactiveValues(\n        data = NULL,\n        feedback =info_alert\n      )\n\n      observeEvent(input$hidden, rv$feedback <- info_alert)\n\n      bindEvent(observe({\n        data <- data_r()\n        updateVirtualSelect(\n          inputId = \"group_by\",\n          choices = make_choices_with_infos(data)\n        )\n      }), data_r(), input$hidden)\n\n      observeEvent(data_r(), rv$data <- data_r())\n\n      output$feedback <- renderUI(rv$feedback)\n\n      output$columns <- renderUI({\n        data <- req(rv$data)\n        col_type <- getFromNamespace(\"col_type\", \"esquisse\")\n        mapply(\n          label = names(data),\n          type = col_type(data),\n          FUN = btn_column,\n          MoreArgs = list(inputId = ns(\"add_column\")),\n          SIMPLIFY = FALSE\n        )\n      })\n\n      observeEvent(input$add_column, {\n        updateTextAreaInput(\n          session = session,\n          inputId = \"expression\",\n          value = paste0(input$expression, input$add_column)\n        )\n      })\n\n      observeEvent(input$new_column, {\n        if (input$new_column == \"\") {\n          rv$feedback <- alert(\n            status = \"warning\",\n            ph(\"warning\"), i18n(\"New column name cannot be empty\")\n          )\n        }\n      })\n\n      observeEvent(input$remove, {\n        rv$data[[input$new_column]] <- NULL\n      })\n      observeEvent(input$compute, {\n        rv$feedback <- try_compute_column(\n          expression = input$expression,\n          name = input$new_column,\n          rv = rv,\n          allowed_operations = allowed_operations,\n          by = input$group_by\n        )\n      })\n\n      return(reactive(rv$data))\n    }\n  )\n}\n\n#' @export\n#'\n#' @rdname create-column\n# @importFrom methods getGroupMembers\nlist_allowed_operations <- function() {\n  c(\n    \"(\", \"c\",\n    # getGroupMembers(\"Arith\"),\n    c(\"+\", \"-\", \"*\", \"^\", \"%%\", \"%/%\", \"/\"),\n    # getGroupMembers(\"Compare\"),\n    c(\"==\", \">\", \"<\", \"!=\", \"<=\", \">=\"),\n    # getGroupMembers(\"Logic\"),\n    c(\"&\", \"|\"),\n    # getGroupMembers(\"Math\"),\n    c(\"abs\", \"sign\", \"sqrt\", \"ceiling\", \"floor\", \"trunc\", \"cummax\",\n      \"cummin\", \"cumprod\", \"cumsum\", \"exp\", \"expm1\", \"log\", \"log10\",\n      \"log2\", \"log1p\", \"cos\", \"cosh\", \"sin\", \"sinh\", \"tan\", \"tanh\",\n      \"acos\", \"acosh\", \"asin\", \"asinh\", \"atan\", \"atanh\", \"cospi\", \"sinpi\",\n      \"tanpi\", \"gamma\", \"lgamma\", \"digamma\", \"trigamma\"),\n    # getGroupMembers(\"Math2\"),\n    c(\"round\", \"signif\"),\n    # getGroupMembers(\"Summary\"),\n    c(\"max\", \"min\", \"range\", \"prod\", \"sum\", \"any\", \"all\"),\n    \"pmin\", \"pmax\", \"mean\",\n    \"paste\", \"paste0\", \"substr\", \"nchar\", \"trimws\",\n    \"gsub\", \"sub\", \"grepl\", \"ifelse\", \"length\",\n    \"as.numeric\", \"as.character\", \"as.integer\", \"as.Date\", \"as.POSIXct\",\n    \"as.factor\", \"factor\"\n  )\n}\n\n\n#' @inheritParams shiny::modalDialog\n#' @export\n#'\n#' @importFrom shiny showModal modalDialog textInput\n#' @importFrom htmltools tagList\n#'\n#' @rdname create-column\nmodal_create_column <- function(id,\n                                title = i18n(\"Create a new column\"),\n                                easyClose = TRUE,\n                                size = \"l\",\n                                footer = NULL) {\n  ns <- NS(id)\n  showModal(modalDialog(\n    title = tagList(title, button_close_modal()),\n    create_column_ui(id),\n    tags$div(\n      style = \"display: none;\",\n      textInput(inputId = ns(\"hidden\"), label = NULL, value = genId())\n    ),\n    easyClose = easyClose,\n    size = size,\n    footer = footer\n  ))\n}\n\n#' @inheritParams shinyWidgets::WinBox\n#' @export\n#'\n#' @importFrom shinyWidgets WinBox wbOptions wbControls\n#' @importFrom htmltools tagList\n#' @rdname create-column\nwinbox_create_column <- function(id,\n                                 title = i18n(\"Create a new column\"),\n                                 options = shinyWidgets::wbOptions(),\n                                 controls = shinyWidgets::wbControls()) {\n  ns <- NS(id)\n  WinBox(\n    title = title,\n    ui = tagList(\n      create_column_ui(id),\n      tags$div(\n        style = \"display: none;\",\n        textInput(inputId = ns(\"hidden\"), label = NULL, value = genId())\n      )\n    ),\n    options = modifyList(\n      shinyWidgets::wbOptions(height = \"550px\", modal = TRUE),\n      options\n    ),\n    controls = controls,\n    auto_height = FALSE\n  )\n}\n\n\n#' @importFrom rlang parse_expr eval_tidy call2 set_names syms\n#' @importFrom data.table as.data.table :=\ntry_compute_column <- function(expression,\n                               name,\n                               rv,\n                               allowed_operations,\n                               by = NULL) {\n  parsed <- try(parse(text = expression, keep.source = FALSE), silent = TRUE)\n  if (inherits(parsed, \"try-error\")) {\n    return(alert_error(attr(parsed, \"condition\")$message))\n  }\n  funs <- unlist(c(extract_calls(parsed), lapply(parsed, extract_calls)), recursive = TRUE)\n  if (!are_allowed_operations(funs, allowed_operations)) {\n    return(alert_error(i18n(\"Some operations are not allowed\")))\n  }\n  if (!isTruthy(by)) {\n    result <- try(\n      eval_tidy(parse_expr(expression), data = rv$data),\n      silent = TRUE\n    )\n  } else {\n    result <- try(\n      {\n        dt <- as.data.table(rv$data)\n        new_col <- NULL\n        dt[, new_col := eval_tidy(parse_expr(expression), data = .SD), by = by]\n        dt$new_col\n      },\n      silent = TRUE\n    )\n  }\n  if (inherits(result, \"try-error\")) {\n    return(alert_error(attr(result, \"condition\")$message))\n  }\n  adding_col <- try(rv$data[[name]] <- result, silent = TRUE)\n  if (inherits(adding_col, \"try-error\")) {\n    return(alert_error(attr(adding_col, \"condition\")$message))\n  }\n  code <- if (!isTruthy(by)) {\n    call2(\"mutate\", !!!set_names(list(parse_expr(expression)), name))\n  } else {\n    call2(\n      \"mutate\",\n      !!!set_names(list(parse_expr(expression)), name),\n      !!!list(.by = expr(c(!!!syms(by))))\n    )\n  }\n  attr(rv$data, \"code\") <- Reduce(\n    f = function(x, y) expr(!!x %>% !!y),\n    x = c(attr(rv$data, \"code\"),  code)\n  )\n  alert(\n    status = \"success\",\n    ph(\"check\"), i18n(\"Column added!\")\n  )\n}\n\nare_allowed_operations <- function(x, allowed_operations) {\n  all(\n    x %in% allowed_operations\n  )\n}\n\n\nextract_calls <- function(exp) {\n  if (is.call(exp))\n    return(list(\n      as.character(exp[[1L]]),\n      lapply(exp[-1L], extract_calls)\n    ))\n}\n\nalert_error <- function(text) {\n  alert(\n    status = \"danger\",\n    ph(\"bug\"), text\n  )\n}\n\n\nbtn_column <- function(label, type, inputId) {\n  icon <- switch (\n    type,\n    discrete = \"text-aa\",\n    time = \"calendar\",\n    continuous = \"hash\",\n    NULL\n  )\n  tags$button(\n    type = \"button\",\n    class = paste0(\"btn btn-column-\", type),\n    style = css(\n      \"--bs-btn-padding-y\" = \".25rem\",\n      \"--bs-btn-padding-x\" = \".5rem\",\n      \"--bs-btn-font-size\" = \".75rem\",\n      \"margin-bottom\" = \"5px\"\n    ),\n    if (!is.null(icon)) ph(icon, weight = \"regular\"),\n    label,\n    onclick = sprintf(\n      \"Shiny.setInputValue('%s', '%s', {priority: 'event'})\",\n      inputId, label\n    )\n  )\n}\n\n\n#' @importFrom data.table uniqueN\n#' @importFrom htmltools doRenderTags\nmake_choices_with_infos <- function(data) {\n  lapply(\n    X = seq_along(data),\n    FUN = function(i) {\n      nm <- names(data)[i]\n      values <- data[[nm]]\n      icon <- if (inherits(values, \"character\")) {\n        phosphoricons::ph(\"text-aa\")\n      } else if (inherits(values, \"factor\")) {\n        phosphoricons::ph(\"list-bullets\")\n      } else if (inherits(values, c(\"numeric\", \"integer\"))) {\n        phosphoricons::ph(\"hash\")\n      } else if (inherits(values, c(\"Date\"))) {\n        phosphoricons::ph(\"calendar\")\n      } else if (inherits(values, c(\"POSIXt\"))) {\n        phosphoricons::ph(\"clock\")\n      } else {\n        NULL\n      }\n      description <- if (is.atomic(values)) {\n        paste(i18n(\"Unique values:\"), data.table::uniqueN(values))\n      } else {\n        \"\"\n      }\n      list(\n        label = htmltools::doRenderTags(tagList(\n          icon, nm\n        )),\n        value = nm,\n        description = description\n      )\n    }\n  )\n}\n\n"
  },
  {
    "path": "R/cut-variable.R",
    "content": "\n#' @title Module to Convert Numeric to Factor\n#'\n#' @description\n#' This module contain an interface to cut a numeric into several intervals.\n#'\n#'\n#' @param id Module ID.\n#'\n#' @return A [shiny::reactive()] function returning the data.\n#' @export\n#'\n#' @importFrom shiny NS fluidRow column numericInput checkboxInput checkboxInput plotOutput uiOutput\n#' @importFrom shinyWidgets virtualSelectInput\n#' @importFrom toastui datagridOutput2\n#'\n#' @name cut-variable\n#'\n#' @example examples/cut_variable.R\ncut_variable_ui <- function(id) {\n  ns <- NS(id)\n  tagList(\n    fluidRow(\n      column(\n        width = 3,\n        virtualSelectInput(\n          inputId = ns(\"variable\"),\n          label = i18n(\"Variable to cut:\"),\n          choices = NULL,\n          width = \"100%\"\n        )\n      ),\n      column(\n        width = 3,\n        virtualSelectInput(\n          inputId = ns(\"method\"),\n          label = i18n(\"Method:\"),\n          choices = c(\n            \"fixed\",\n            \"sd\",\n            \"equal\",\n            \"pretty\",\n            \"quantile\",\n            # \"kmeans\",\n            # \"hclust\",\n            # \"bclust\",\n            # \"fisher\",\n            # \"jenks\",\n            \"headtails\",\n            \"maximum\",\n            \"box\"\n          ),\n          selected = \"quantile\",\n          width = \"100%\"\n        )\n      ),\n      column(\n        width = 3,\n        numericInput(\n          inputId = ns(\"n_breaks\"),\n          label = i18n(\"Number of breaks:\"),\n          value = 5,\n          min = 2,\n          max = 12,\n          width = \"100%\"\n        )\n      ),\n      column(\n        width = 3,\n        checkboxInput(\n          inputId = ns(\"right\"),\n          label = i18n(\"Close intervals on the right\"),\n          value = TRUE\n        ),\n        checkboxInput(\n          inputId = ns(\"include_lowest\"),\n          label = i18n(\"Include lowest value\"),\n          value = FALSE\n        )\n      )\n    ),\n    conditionalPanel(\n      condition = \"input.method == 'fixed'\",\n      ns = ns,\n      uiOutput(outputId = ns(\"slider_fixed\"))\n    ),\n    plotOutput(outputId = ns(\"plot\"), width = \"100%\", height = \"270px\"),\n    datagridOutput2(outputId = ns(\"count\")),\n    actionButton(\n      inputId = ns(\"create\"),\n      label = tagList(ph(\"scissors\"), i18n(\"Create factor variable\")),\n      class = \"btn-outline-primary float-end\"\n    ),\n    tags$div(class = \"clearfix\")\n  )\n}\n\n#' @param data_r A [shiny::reactive()] function returning a `data.frame`.\n#'\n#' @export\n#'\n#' @importFrom shiny moduleServer observeEvent reactive req bindEvent renderPlot\n#' @importFrom shinyWidgets updateVirtualSelect noUiSliderInput\n#' @importFrom toastui renderDatagrid2 datagrid grid_colorbar\n#' @importFrom rlang %||% call2 set_names expr syms\n#' @importFrom classInt classIntervals\n#'\n#' @rdname cut-variable\ncut_variable_server <- function(id, data_r = reactive(NULL)) {\n  moduleServer(\n    id,\n    function(input, output, session) {\n\n      rv <- reactiveValues(data = NULL)\n\n      bindEvent(observe({\n        data <- data_r()\n        rv$data <- data\n        vars_num <- vapply(data, is.numeric, logical(1))\n        vars_num <- names(vars_num)[vars_num]\n        updateVirtualSelect(\n          inputId = \"variable\",\n          choices = vars_num,\n          selected = if (isTruthy(input$variable)) input$variable else vars_num[1]\n        )\n      }), data_r(), input$hidden)\n\n      output$slider_fixed <- renderUI({\n        data <- req(data_r())\n        variable <- req(input$variable)\n        req(hasName(data, variable))\n        noUiSliderInput(\n          inputId = session$ns(\"fixed_brks\"),\n          label = i18n(\"Fixed breaks:\"),\n          min = floor(min(data[[variable]], na.rm = TRUE)),\n          max = ceiling(max(data[[variable]], na.rm = TRUE)),\n          value = classInt::classIntervals(\n            var = data[[variable]],\n            n = input$n_breaks,\n            style = \"quantile\"\n          )$brks,\n          color = get_primary_color(),\n          width = \"100%\"\n        )\n      })\n\n      breaks_r <- reactive({\n        data <- req(data_r())\n        variable <- req(input$variable)\n        req(hasName(data, variable))\n        req(input$n_breaks, input$method)\n        if (input$method == \"fixed\") {\n          req(input$fixed_brks)\n          classInt::classIntervals(\n            var = data[[variable]],\n            n = input$n_breaks,\n            style = \"fixed\",\n            fixedBreaks = input$fixed_brks\n          )\n        } else {\n          classInt::classIntervals(\n            var = data[[variable]],\n            n = input$n_breaks,\n            style = input$method\n          )\n        }\n      })\n\n      output$plot <- renderPlot({\n        data <- req(data_r())\n        variable <- req(input$variable)\n        plot_histogram(data, variable, breaks = breaks_r()$brks, color = get_primary_color())\n      })\n\n\n      data_cutted_r <- reactive({\n        data <- req(data_r())\n        variable <- req(input$variable)\n        data[[paste0(variable, \"_cut\")]] <- cut(\n          x = data[[variable]],\n          breaks = breaks_r()$brks,\n          include.lowest = input$include_lowest,\n          right = input$right\n        )\n        code <- call2(\n          \"mutate\",\n          !!!set_names(\n            list(\n              expr(cut(\n                !!!syms(list(x = variable)),\n                !!!list(breaks = breaks_r()$brks, include.lowest = input$include_lowest, right = input$right)\n              ))\n            ),\n            paste0(variable, \"_cut\")\n          )\n        )\n        attr(data, \"code\") <- Reduce(\n          f = function(x, y) expr(!!x %>% !!y),\n          x = c(attr(data, \"code\"),  code)\n        )\n        data\n      })\n\n      output$count <- renderDatagrid2({\n        data <- req(data_cutted_r())\n        variable <- req(input$variable)\n        count_data <- as.data.frame(\n          table(\n            breaks = data[[paste0(variable, \"_cut\")]],\n            useNA = \"ifany\"\n          ),\n          responseName = \"count\"\n        )\n        gridTheme <- getOption(\"datagrid.theme\")\n        if (length(gridTheme) < 1) {\n          apply_grid_theme()\n        }\n        on.exit(toastui::reset_grid_theme())\n        grid <- datagrid(\n          data = count_data,\n          colwidths = \"guess\",\n          theme = \"default\",\n          bodyHeight = \"auto\"\n        )\n        grid <- toastui::grid_columns(grid, className = \"font-monospace\")\n        grid_colorbar(\n          grid,\n          column = \"count\",\n          label_outside = TRUE,\n          label_width = \"40px\",\n          bar_bg = get_primary_color(),\n          from = c(0, max(count_data$count) + 1)\n        )\n      })\n\n      data_returned_r <- observeEvent(input$create, {\n        rv$data <- data_cutted_r()\n      })\n      return(reactive(rv$data))\n    }\n  )\n}\n\n\n\n#' @inheritParams shiny::modalDialog\n#' @export\n#'\n#' @importFrom shiny showModal modalDialog textInput\n#' @importFrom htmltools tagList\n#'\n#' @rdname cut-variable\nmodal_cut_variable <- function(id,\n                               title = i18n(\"Convert Numeric to Factor\"),\n                               easyClose = TRUE,\n                               size = \"l\",\n                               footer = NULL) {\n  ns <- NS(id)\n  showModal(modalDialog(\n    title = tagList(title, button_close_modal()),\n    cut_variable_ui(id),\n    tags$div(\n      style = \"display: none;\",\n      textInput(inputId = ns(\"hidden\"), label = NULL, value = genId())\n    ),\n    easyClose = easyClose,\n    size = size,\n    footer = footer\n  ))\n}\n\n\n#' @inheritParams shinyWidgets::WinBox\n#' @export\n#'\n#' @importFrom shinyWidgets WinBox wbOptions wbControls\n#' @importFrom htmltools tagList\n#' @rdname cut-variable\nwinbox_cut_variable <- function(id,\n                                title = i18n(\"Convert Numeric to Factor\"),\n                                options = shinyWidgets::wbOptions(),\n                                controls = shinyWidgets::wbControls()) {\n  ns <- NS(id)\n  WinBox(\n    title = title,\n    ui = tagList(\n      cut_variable_ui(id),\n      tags$div(\n        style = \"display: none;\",\n        textInput(inputId = ns(\"hidden\"), label = NULL, value = genId())\n      )\n    ),\n    options = modifyList(\n      shinyWidgets::wbOptions(height = \"750px\", modal = TRUE),\n      options\n    ),\n    controls = controls,\n    auto_height = FALSE\n  )\n}\n\n\n#' @importFrom graphics abline axis hist par plot.new plot.window\nplot_histogram <- function(data, column, bins = 30, breaks = NULL, color = \"#112466\") {\n  x <- data[[column]]\n  op <- par(mar = rep(1.5, 4)); on.exit(par(op))\n  plot.new()\n  plot.window(xlim = range(pretty(x)), ylim =  range(pretty(hist(x, breaks = bins, plot = FALSE)$counts)))\n  abline(v = pretty(x), col = \"#D8D8D8\")\n  abline(h = pretty(hist(x, breaks = bins, plot = FALSE)$counts), col = \"#D8D8D8\")\n  hist(x, breaks = bins, xlim = range(pretty(x)), xaxs = \"i\", yaxs = \"i\", col = color, add = TRUE)\n  axis(side = 1, at = pretty(x), pos = 0)\n  axis(side = 2, at = pretty(hist(x, breaks = bins, plot = FALSE)$counts), pos = min(pretty(x)))\n  abline(v = breaks, col = \"#FFFFFF\", lty = 1, lwd = 1.5)\n  abline(v = breaks, col = \"#2E2E2E\", lty = 2, lwd = 1.5)\n}\n\n\n"
  },
  {
    "path": "R/data.R",
    "content": "#' Customer Credit Card Information\n#'\n#' A subset of fake customer credit card information inspired by the `{charlatan}` package.\n#'\n#' @format ## `demo_edit`\n#' A data frame with 20 rows and 6 columns:\n#' \\describe{\n#'   \\item{name}{Customer name}\n#'   \\item{job}{Customer job}\n#'   \\item{credit_card_provider}{Credit card provider}\n#'   \\item{credit_card_security_code}{Credit card security code}\n#'   \\item{date_obtained}{Date of obtaining the credit card}\n#'   \\item{contactless_card}{Contactless card}\n#' }\n#' @source <https://CRAN.R-project.org/package=charlatan>\n\"demo_edit\"\n"
  },
  {
    "path": "R/datagrid-infos.R",
    "content": "\n#' @importFrom htmltools tagList tags css\ndescribe_col_char <- function(x, with_summary = TRUE) {\n  tags$div(\n    style = css(padding = \"3px 0\", fontSize = \"x-small\"),\n    tags$div(\n      style = css(fontStyle = \"italic\"),\n      phosphoricons::ph(\"text-aa\"),\n      \"character\"\n    ),\n    if (with_summary) {\n      tagList(\n        tags$hr(style = css(margin = \"3px 0\")),\n        tags$div(\n          i18n(\"Unique:\"), length(unique(x))\n        ),\n        tags$div(\n          i18n(\"Missing:\"), sum(is.na(x))\n        ),\n        tags$div(\n          style = css(whiteSpace = \"normal\", wordBreak = \"break-all\"),\n          i18n(\"Most Common:\"), gsub(\n            pattern = \"'\",\n            replacement = \"\\u07F4\",\n            x = names(sort(table(x), decreasing = TRUE))[1]\n          )\n        ),\n        tags$div(\n          \"\\u00A0\"\n        )\n      )\n    }\n  )\n}\n\nfmt_p <- function(val, tot) {\n  paste0(round(val / tot * 100, 1), \"%\")\n}\n\ndescribe_col_factor <- function(x, with_summary = TRUE) {\n  count <- sort(table(x, useNA = \"always\"), decreasing = TRUE)\n  total <- sum(count)\n  one <- count[!is.na(names(count))][1]\n  two <- count[!is.na(names(count))][2]\n  missing <- count[is.na(names(count))]\n  tags$div(\n    style = css(padding = \"3px 0\", fontSize = \"x-small\"),\n    tags$div(\n      style = css(fontStyle = \"italic\"),\n      phosphoricons::ph(\"list-bullets\"),\n      \"factor\"\n    ),\n    if (with_summary) {\n      tagList(\n        tags$hr(style = css(margin = \"3px 0\")),\n        tags$div(\n          names(one), \":\", fmt_p(one, total)\n        ),\n        tags$div(\n          names(two), \":\", fmt_p(two, total)\n        ),\n        tags$div(\n          \"Missing\", \":\", fmt_p(missing, total)\n        ),\n        tags$div(\n          \"\\u00A0\"\n        )\n      )\n    }\n  )\n}\n\ndescribe_col_num <- function(x, with_summary = TRUE) {\n  tags$div(\n    style = css(padding = \"3px 0\", fontSize = \"x-small\"),\n    tags$div(\n      style = css(fontStyle = \"italic\"),\n      phosphoricons::ph(\"hash\"),\n      \"numeric\"\n    ),\n    if (with_summary) {\n      tagList(\n        tags$hr(style = css(margin = \"3px 0\")),\n        tags$div(\n          i18n(\"Min:\"), round(min(x, na.rm = TRUE), 2)\n        ),\n        tags$div(\n          i18n(\"Mean:\"), round(mean(x, na.rm = TRUE), 2)\n        ),\n        tags$div(\n          i18n(\"Max:\"), round(max(x, na.rm = TRUE), 2)\n        ),\n        tags$div(\n          i18n(\"Missing:\"), sum(is.na(x))\n        )\n      )\n    }\n  )\n}\n\n\ndescribe_col_date <- function(x, with_summary = TRUE) {\n  tags$div(\n    style = css(padding = \"3px 0\", fontSize = \"x-small\"),\n    tags$div(\n      style = css(fontStyle = \"italic\"),\n      phosphoricons::ph(\"calendar\"),\n      \"date\"\n    ),\n    if (with_summary) {\n      tagList(\n        tags$hr(style = css(margin = \"3px 0\")),\n        tags$div(\n          i18n(\"Min:\"), min(x, na.rm = TRUE)\n        ),\n        tags$div(\n          i18n(\"Max:\"), max(x, na.rm = TRUE)\n        ),\n        tags$div(\n          i18n(\"Missing:\"), sum(is.na(x))\n        ),\n        tags$div(\n          \"\\u00A0\"\n        )\n      )\n    }\n  )\n}\n\ndescribe_col_datetime <- function(x, with_summary = TRUE) {\n  tags$div(\n    style = css(padding = \"3px 0\", fontSize = \"x-small\"),\n    tags$div(\n      style = css(fontStyle = \"italic\"),\n      phosphoricons::ph(\"clock\"),\n      \"datetime\"\n    ),\n    if (with_summary) {\n      tagList(\n        tags$hr(style = css(margin = \"3px 0\")),\n        tags$div(\n          i18n(\"Min:\"), min(x, na.rm = TRUE)\n        ),\n        tags$div(\n          i18n(\"Max:\"), max(x, na.rm = TRUE)\n        ),\n        tags$div(\n          i18n(\"Missing:\"), sum(is.na(x))\n        ),\n        tags$div(\n          \"\\u00A0\"\n        )\n      )\n    }\n  )\n}\n\n\ndescribe_col_other <- function(x, with_summary = TRUE) {\n  tags$div(\n    style = css(padding = \"3px 0\", fontSize = \"x-small\"),\n    tags$div(\n      style = css(fontStyle = \"italic\"),\n      # phosphoricons::ph(\"clock\"),\n      paste(class(x), collapse = \", \")\n    ),\n    if (with_summary) {\n      tagList(\n        tags$hr(style = css(margin = \"3px 0\")),\n        tags$div(\n          i18n(\"Unique:\"), length(unique(x))\n        ),\n        tags$div(\n          i18n(\"Missing:\"), sum(is.na(x))\n        ),\n        tags$div(\n          \"\\u00A0\"\n        ),\n        tags$div(\n          \"\\u00A0\"\n        )\n      )\n    }\n  )\n}\n\n#' @importFrom htmltools doRenderTags\nconstruct_col_summary <- function(data) {\n  list(\n    position = \"top\",\n    height = 90,\n    columnContent = lapply(\n      X = setNames(names(data), names(data)),\n      FUN = function(col) {\n        values <- data[[col]]\n        content <- if (inherits(values, \"character\")) {\n          describe_col_char(values)\n        } else if (inherits(values, \"factor\")) {\n          describe_col_factor(values)\n        } else if (inherits(values, c(\"numeric\", \"integer\"))) {\n          describe_col_num(values)\n        } else if (inherits(values, c(\"Date\"))) {\n          describe_col_date(values)\n        } else if (inherits(values, c(\"POSIXt\"))) {\n          describe_col_datetime(values)\n        } else {\n          describe_col_other(values)\n        }\n        list(\n          template = toastui::JS(\n            \"function(value) {\",\n            sprintf(\n              \"return '%s';\",\n              gsub(replacement = \"\", pattern = \"\\n\", x = doRenderTags(content))\n            ),\n            \"}\"\n          )\n        )\n      }\n    )\n  )\n}\n"
  },
  {
    "path": "R/edit-data-utils.R",
    "content": "\n\n#' @title Edit modal\n#'\n#' @description The `edit_modal` function generates a modal window with the variables to edit\n#'\n#' @return a modal window with the variables to edit\n#'\n#' @param default row on which to operate a modification or a deletion, otherwise empty list for an addition\n#' @param id_validate inputId of the actionButton()\n#' @param title title of the modalDialog()\n#' @param data `data.frame` to use\n#' @param colnames `data.frame` column names\n#' @param var_edit vector of `character` which allows to choose the editable columns\n#' @param var_mandatory vector of `character` which allows to choose obligatory fields to fill\n#' @param modal_size `character` which allows to choose the size of the modalDialog. One of \"s\" for small, \"m\" (the default) for medium, \"l\" for large, or \"xl\" for extra large.\n#' @param modal_easy_close `boolean` If TRUE, modalDialog can be dismissed by clicking outside the dialog box, or be pressing the Escape key. If FALSE (the default), modalDialog can't be dismissed in those ways; instead it must be dismissed by clicking on a modalButton(), or from a call to removeModal() on the server.\n#' @param session The `session` object passed to function given to shinyServer\n#'\n#' @importFrom shiny showModal modalDialog actionButton\n#' @importFrom phosphoricons ph\n#' @importFrom htmltools tagList tags css\n#'\n#' @noRd\n#'\nedit_modal <- function(default = list(),\n                       id_validate = \"add_row\",\n                       title = i18n(\"Add a row\"),\n                       data,\n                       var_edit = NULL,\n                       var_mandatory = NULL,\n                       var_labels = colnames(data),\n                       modal_size = \"m\",\n                       modal_easy_close = FALSE,\n                       n_column = 1,\n                       session = getDefaultReactiveDomain()) {\n  ns <- session$ns\n\n  if (length(var_edit) > 0) {\n    data <- data[, ..var_edit]\n  }\n\n  showModal(modalDialog(\n    title = tagList(\n      title,\n      tags$button(\n        phosphoricons::ph(\"x\", title = i18n(\"Close\"), height = \"2em\"),\n        class = \"btn btn-link\",\n        style = css(border = \"0 none\", position = \"absolute\", top = \"5px\", right = \"5px\"),\n        `data-bs-dismiss` = \"modal\",\n        `data-dismiss` = \"modal\",\n        `aria-label` = \"Close\"\n      )\n    ),\n    footer = NULL,\n    size = modal_size,\n    easyClose = modal_easy_close,\n    edit_input_form(\n      default = default,\n      data = data,\n      var_mandatory = var_mandatory,\n      var_labels = var_labels,\n      n_column = n_column,\n      session = session\n    ),\n    actionButton(\n      inputId = ns(id_validate),\n      label = tagList(\n        ph(\"floppy-disk\"), i18n(\"Save\")\n      ),\n      class = \"btn-outline-primary float-end\"\n    )\n  ))\n}\n\n\n#' @title Edit input form\n#'\n#' @description The `edit_input_form` function allows to correctly generate the variables to be edited in the modal window according to their respective class\n#'\n#' @param default default row on which to operate a modification or a deletion, otherwise empty list for an addition\n#' @param data `data.frame` to use\n#' @param colnames `data.frame` column names\n#' @param var_mandatory vector of `character` which allows to choose obligatory fields to fill\n#' @param position_var_edit position of editable columns in order to retrieve their name\n#' @param session The `session` object passed to function given to shinyServer\n#'\n#' @importFrom shiny numericInput textInput\n#' @importFrom shinyWidgets virtualSelectInput prettyCheckbox airDatepickerInput\n#' @importFrom htmltools tagList tags\n#' @importFrom rlang is_vector is_named\n#'\n#' @return different shiny widgets with edited columns according to their respective class\n#' @noRd\n#'\nedit_input_form <- function(default = list(),\n                            data,\n                            var_mandatory = NULL,\n                            var_labels = colnames(data),\n                            n_column = 1,\n                            session = getDefaultReactiveDomain()) {\n\n  ns <- session$ns\n\n  if (is_vector(var_labels) & !is_named(var_labels)) {\n    var_labels <- setNames(var_labels, unlist(var_labels))\n  }\n\n  widgets <- lapply(\n    X = seq_len(ncol(data)),\n    FUN = function(i) {\n      variable_id <- colnames(data)[i]\n      variable_label <- var_labels[which(names(var_labels) == variable_id)]\n      if (length(variable_label) < 1)\n        variable_label <- variable_id\n      variable <- data[[i]]\n\n      suffix <- if (isTRUE((inherits(variable, \"logical\")))) \"\" else \" : \"\n      if (variable_id %in% var_mandatory) {\n        label <- tagList(\n          variable_label,\n          tags$span(HTML(\"&#42;\"), class = \"asterisk\", style = \"color: red;\"), suffix\n        )\n      } else {\n        label <- paste0(variable_label, suffix)\n      }\n\n      if (isTRUE(inherits(variable, c(\"numeric\", \"integer\")))) {\n        opts <- getOption(\"datamods.edit.input.numeric\", list())\n        opts <- modifyList(\n          x = opts,\n          val = list(\n            inputId = ns(variable_id),\n            label = label,\n            value = default[[variable_id]] %||% NA_real_,\n            width = \"100%\"\n          )\n        )\n        do.call(numericInput, opts)\n      } else if (inherits(variable, \"factor\")) {\n        opts <- getOption(\"datamods.edit.input.factor\", list())\n        opts <- modifyList(\n          x = opts,\n          val = list(\n            inputId = ns(variable_id),\n            label = label,\n            choices = sort(unique(c(as.character(variable), levels(variable)))),\n            selected = default[[variable_id]] %||% \"\",\n            width = \"100%\",\n            allowNewOption = TRUE,\n            autoSelectFirstOption = FALSE,\n            placeholder = i18n(\"Select\"),\n            zIndex = 999\n          )\n        )\n        do.call(virtualSelectInput, opts)\n      } else if (inherits(variable, \"character\")) {\n        opts <- getOption(\"datamods.edit.input.character\", list())\n        opts <- modifyList(\n          x = opts,\n          val = list(\n            inputId = ns(variable_id),\n            label = label,\n            value = default[[variable_id]] %||% \"\",\n            width = \"100%\"\n          )\n        )\n        do.call(textInput, opts)\n      } else if (inherits(variable, \"logical\")) {\n        opts <- getOption(\"datamods.edit.input.logical\", list())\n        opts <- modifyList(\n          x = opts,\n          val = list(\n            inputId = ns(variable_id),\n            label = label,\n            value = default[[variable_id]] %||% FALSE,\n            icon = icon(\"check\"),\n            status = \"primary\",\n            width = \"100%\"\n          )\n        )\n        do.call(prettyCheckbox, opts)\n      } else if (inherits(variable, \"Date\")) {\n        opts <- getOption(\"datamods.edit.input.Date\", list())\n        opts <- modifyList(\n          x = opts,\n          val = list(\n            inputId = ns(variable_id),\n            label = label,\n            value = default[[variable_id]] %||% Sys.Date(),\n            width = \"100%\"\n          )\n        )\n        do.call(airDatepickerInput, opts)\n      } else if (inherits(variable, c(\"POSIXct\", \"POSIXt\"))) {\n        opts <- getOption(\"datamods.edit.input.POSIXt\", list())\n        opts <- modifyList(\n          x = opts,\n          val = list(\n            inputId = ns(variable_id),\n            label = label,\n            value = default[[variable_id]] %||% Sys.time(),\n            timepicker = TRUE,\n            width = \"100%\"\n          )\n        )\n        do.call(airDatepickerInput, opts)\n      } else {\n        return(NULL)\n      }\n    }\n  )\n  fluidRow(\n    lapply(\n      X = split(\n        x = seq_along(widgets),\n        f = rep(seq_len(n_column), each = ceiling(length(widgets)/n_column))[seq_along(widgets)]\n      ),\n      FUN = function(i) {\n        column(\n          width = 12 / n_column,\n          widgets[i]\n        )\n      }\n    )\n  )\n}\n\n\n#' @title Table display\n#'\n#' @description The `table_display` function allows you to display the table in reactable format with columns to edit and delete rows\n#'\n#' @param data `data.frame` to use\n#' @param colnames `data.frame` column names\n#' @param reactable_options `list` allowing you to add reactable options\n#'\n#' @return the `data.frame` in reactable format\n#' @noRd\n#'\n#' @importFrom reactable reactable colDef\n#' @importFrom data.table copy setnames\ntable_display <- function(data, colnames = NULL, reactable_options = NULL) {\n\n  data <- copy(data)\n  if (!is.null(colnames)) {\n    setnames(data, old = seq_along(colnames), new = colnames)\n  }\n\n  cols <- reactable_options$columns %||% list()\n  if (all(is.na(data$.datamods_edit_update))) {\n    cols$.datamods_edit_update <- colDef(show = FALSE)\n  } else {\n    cols$.datamods_edit_update <- col_def_update()\n  }\n\n  if (all(is.na(data$.datamods_edit_delete))) {\n    cols$.datamods_edit_delete <- colDef(show = FALSE)\n  } else {\n    cols$.datamods_edit_delete <- col_def_delete()\n  }\n\n  cols$.datamods_id <- colDef(show = FALSE)\n\n  if (is.null(reactable_options))\n    reactable_options <- list()\n  reactable_options <- reactable_options\n  reactable_options$data <- data\n  reactable_options$columns <- cols\n\n  rlang::exec(reactable::reactable, !!!reactable_options)\n}\n\n#' @importFrom reactable updateReactable getReactableState\n#' @importFrom data.table copy setnames\nupdate_table <- function(data, colnames) {\n  data <- copy(data)\n  setnames(data, old = seq_along(colnames), new = colnames)\n  page <- getReactableState(outputId = \"table\", name = \"page\")\n  updateReactable(\"table\", data = data, page = page)\n  return(data)\n}\n\nformat_edit_data <- function(data, colnames, internal_colnames = NULL) {\n  data <- as.data.table(data)\n  vars_datamods_edit <- intersect(c(\".datamods_id\", \".datamods_edit_update\", \".datamods_edit_delete\"), names(data))\n  data <- data[, -..vars_datamods_edit]\n  if (is.null(internal_colnames))\n    internal_colnames <- seq_along(colnames)\n  setnames(data, old = internal_colnames, new = colnames, skip_absent = TRUE)\n  data[]\n}\n\nrename_edit <- function(data, var_labels) {\n  for(i in seq_along(names(var_labels))) {\n    names(data)[names(data) == names(var_labels)[i]] <- var_labels[[i]]\n  }\n  data\n}\n\n\n#' @importFrom rlang set_names is_null is_list is_named\nget_variables_labels <- function(labels, column_names, internal_names) {\n  if (is_null(labels)) {\n    labels <- column_names\n  } else {\n    if (!is_list(labels)) {\n      stopifnot(\n        \"If `var_labels` is an unnamed vector, it must have same length as `colnames(data)`\" = length(labels) == length(column_names)\n      )\n      labels <- set_names(as.list(labels), column_names)\n    }\n    stopifnot(\n      \"`var_labels` must be a named list\" = is_named(labels)\n    )\n    names(labels) <- internal_names[match(names(labels), column_names)]\n    labels <- modifyList(\n      x = set_names(as.list(column_names), internal_names),\n      val = labels\n    )\n  }\n  return(labels)\n}\n\nget_variables_default <- function(default, column_names, internal_names) {\n  default <- default[column_names]\n  idx <- match(names(default), column_names, nomatch = 0L)\n  names(default)[idx > 0] <- internal_names[idx]\n  default\n}\n\n\n#' @title The update column definition\n#'\n#' @return A column definition object that can be used to customize the update column in reactable().\n#' @noRd\n#'\n#' @importFrom reactable colDef\n#'\ncol_def_update <- function() {\n  colDef(\n    name = i18n(\"Update\"),\n    width = 82,\n    sortable = FALSE,\n    html = TRUE,\n    filterable = FALSE\n  )\n}\n\n#' The update button\n#'\n#' @param inputId ID\n#'\n#' @return the update button\n#' @noRd\n#'\n#' @importFrom htmltools tags css doRenderTags\n#' @importFrom phosphoricons ph\n#'\nbtn_update <- function(inputId) {\n  function(value) {\n    htmltools::doRenderTags(\n      tags$button(\n        class = \"btn btn-outline-primary rounded-circle\",\n        style = htmltools::css(\n          height = \"40px\",\n          width = \"40px\",\n          padding = 0\n        ),\n        onClick = sprintf(\n          \"Shiny.setInputValue(\\'%s\\', %s,  {priority: \\'event\\'})\",\n          inputId,\n          value\n        ),\n        title = i18n(\"Click to edit\"),\n        ph(\"pencil-simple-line\", height = \"1.2em\")\n      )\n    )\n\n  }\n}\n\n\n#' @title The delete column definition\n#'\n#' @return A column definition object that can be used to customize the delete column in reactable().\n#' @noRd\n#' @importFrom reactable colDef\n#'\ncol_def_delete <- function() {\n  reactable::colDef(\n    name = i18n(\"Delete\"),\n    width = 96,\n    sortable = FALSE,\n    html = TRUE,\n    filterable = FALSE\n  )\n}\n\n#' The delete button\n#'\n#' @param inputId ID\n#'\n#' @return the delete button\n#' @noRd\n#'\n#' @importFrom htmltools tags css doRenderTags\n#' @importFrom phosphoricons ph\n#'\nbtn_delete <- function(inputId) {\n  function(value) {\n    htmltools::doRenderTags(\n      tags$button(\n        class = \"btn btn-outline-danger rounded-circle\",\n        style = htmltools::css(\n          height = \"40px\",\n          width = \"40px\",\n          padding = 0\n        ),\n        onClick = sprintf(\n          \"Shiny.setInputValue(\\'%s\\', %s,  {priority: \\'event\\'})\",\n          inputId,\n          value\n        ),\n        title = i18n(\"Click to delete\"),\n        ph(\"x\", height = \"1.2em\")\n      )\n    )\n  }\n}\n\n\n#' Confirmation window\n#'\n#' @param inputId ID\n#' @param ... optional additional elements to add in the ui\n#' @param title title of the confirmation window\n#'\n#' @return a confirmation window\n#' @noRd\n#'\n#' @importFrom shiny modalDialog actionButton\n#' @importFrom htmltools tagList tags css\n#' @importFrom phosphoricons ph\n#'\nconfirmation_window <- function(inputId, ..., title = NULL) {\n  modalDialog(\n    title = tagList(\n      tags$button(\n        phosphoricons::ph(\"x\", title = i18n(\"Close\"), height = \"2em\"),\n        class = \"btn btn-link\",\n        style = css(border = \"0 none\", position = \"absolute\", top = \"5px\", right = \"5px\"),\n        `data-bs-dismiss` = \"modal\",\n        `aria-label` = \"Fermer\"\n      ),\n      title\n    ),\n    ...,\n    size = \"m\",\n    footer = tagList(\n      tags$button(\n        i18n(\"Cancel\"),\n        class = \"btn btn-outline-secondary\",\n        `data-bs-dismiss` = \"modal\"\n      ),\n      actionButton(\n        inputId = paste0(inputId, \"_no\"),\n        label = i18n(\"No\"),\n        class = \"btn-outline-danger\",\n        `data-bs-dismiss` = \"modal\"\n      ),\n      actionButton(\n        inputId = paste0(inputId, \"_yes\"),\n        label = i18n(\"Yes\"),\n        class = \"btn-outline-primary\"\n      )\n    )\n  )\n}\n\n\n#' @importFrom shinybusy notify_failure notify_success notify_info notify_warning\nnotification_failure <- function(title, text, use_notify = TRUE) {\n  if (isTRUE(use_notify)) {\n    shinybusy::notify_failure(\n      title = title,\n      text = text,\n      position = \"center-top\",\n      clickToClose = TRUE\n    )\n  }\n}\nnotification_warning <- function(title, text, use_notify = TRUE) {\n  if (isTRUE(use_notify)) {\n    shinybusy::notify_warning(\n      title = title,\n      text = text,\n      position = \"center-top\",\n      clickToClose = TRUE\n    )\n  }\n}\nnotification_success <- function(title, text, use_notify = TRUE) {\n  if (isTRUE(use_notify)) {\n    shinybusy::notify_success(\n      title = title,\n      text = text,\n      position = \"center-top\",\n      clickToClose = TRUE\n    )\n  }\n}\nnotification_info <- function(title, text, use_notify = TRUE) {\n  if (isTRUE(use_notify)) {\n    shinybusy::notify_info(\n      title = title,\n      text = text,\n      position = \"center-top\",\n      clickToClose = TRUE\n    )\n  }\n}\n\n"
  },
  {
    "path": "R/edit-data.R",
    "content": "\n\n#' @title Shiny module to interactively edit a `data.frame`\n#'\n#' @description The module generates different options to edit a `data.frame`: adding, deleting and modifying rows, exporting data (csv and excel), choosing editable columns, choosing mandatory columns.\n#' This module returns the edited table with the user modifications.\n#'\n#' @param id Module ID\n#'\n#' @importFrom shiny uiOutput\n#' @importFrom htmltools tagList tags\n#' @importFrom reactable reactableOutput\n#' @importFrom utils getFromNamespace\n#'\n#' @export\n#'\n#' @name edit-data\n#'\n#' @example examples/edit_data.R\nedit_data_ui <- function(id) {\n  ns <- NS(id)\n\n  notify_dep <- getFromNamespace(\"html_dependency_notify\", \"shinybusy\")\n\n  tagList(\n\n    notify_dep(),\n\n    # Download data in Excel format --\n    uiOutput(outputId = ns(\"download_excel\"), style = \"display: inline;\"),\n\n    # Download data in csv format --\n    uiOutput(outputId = ns(\"download_csv\"), style = \"display: inline;\"),\n\n    # Add a row --\n    uiOutput(outputId = ns(\"add_button\"), style = \"display: inline;\"),\n\n    tags$div(class = \"clearfix mb-2\"),\n\n    # Table --\n    reactableOutput(outputId = ns(\"table\"))\n  )\n}\n\n#' @title Shiny module to interactively edit a `data.frame`\n#'\n#' @param id Module ID\n#' @param data_r data_r `reactive` function containing a `data.frame` to use in the module.\n#' @param add `boolean`, if `TRUE`, allows you to add a row in the table via a button at the top right.\n#' @param update `boolean`, if `TRUE`, allows you to modify a row of the table via a button located in the table on the row you want to edit.\n#' @param delete `boolean`, if `TRUE`, allows a row to be deleted from the table via a button in the table.\n#' @param download_csv if `TRUE`, allows to export the table in csv format via a download button.\n#' @param download_excel if `TRUE`, allows to export the table in excel format via a download button.\n#' @param file_name_export `character` that allows you to choose the export name of the downloaded file.\n#' @param var_edit vector of `character` which allows to choose the names of the editable columns.\n#' @param var_mandatory vector of `character` which allows to choose obligatory fields to fill.\n#' @param var_labels named list, where names are colnames and values are labels to be used in edit modal.\n#' @param add_default_values Default values to use for input control when adding new data, e.g. `list(my_var_text = \"Default text to display\")`.\n#' @param n_column Number of column in the edit modal window, must be a number that divide 12 since it use Bootstrap grid system with [shiny::column()].\n#' @param return_class Class of returned data: `data.frame`, `data.table`, `tbl_df` (tibble) or `raw`.\n#' @param reactable_options Options passed to [reactable::reactable()].\n#' @param modal_size `character` which allows to choose the size of the modalDialog. One of \"s\" for small, \"m\" (the default) for medium, \"l\" for large, or \"xl\" for extra large.\n#' @param modal_easy_close `boolean` If TRUE, modalDialog can be dismissed by clicking outside the dialog box, or be pressing the Escape key. If FALSE (the default), modalDialog can't be dismissed in those ways; instead it must be dismissed by clicking on a modalButton(), or from a call to removeModal() on the server.\n#' @param callback_add,callback_update,callback_delete Functions to be executed just before an action (add, update or delete) is performed on the data.\n#'  Functions used must be like `function(data, row) {...}` where :\n#'    * `data` will be the data in the table at the moment the function is called\n#'    * `row` will contain either a new row of data (add), an updated row (update) or the row that will be deleted (delete).\n#'\n#'  If the return value of a callback function is not truthy (see [shiny::isTruthy()]) then the action is cancelled.\n#' @param only_callback Only use callbacks, don't alter data within the module.\n#' @param use_notify Display information or not to user through [shinybusy::notify()].\n#'\n#'\n#'\n#' @return the edited `data.frame` in reactable format with the user modifications\n#'\n#' @name edit-data\n#'\n#' @importFrom shiny moduleServer eventReactive reactiveValues is.reactive reactive renderUI actionButton observeEvent isTruthy showModal removeModal downloadButton downloadHandler\n#' @importFrom data.table copy as.data.table := copy setnames as.data.table setattr\n#' @importFrom reactable renderReactable reactableOutput getReactableState\n#' @importFrom phosphoricons ph\n#' @importFrom writexl write_xlsx\n#' @importFrom utils write.csv\n#' @importFrom htmltools tagList\n#' @importFrom rlang is_function is_list\n#'\n#' @export\n#'\nedit_data_server <- function(id,\n                             data_r = reactive(NULL),\n                             add = TRUE,\n                             update = TRUE,\n                             delete = TRUE,\n                             download_csv = TRUE,\n                             download_excel = TRUE,\n                             file_name_export = \"data\",\n                             var_edit = NULL,\n                             var_mandatory = NULL,\n                             var_labels = NULL,\n                             add_default_values = list(),\n                             n_column = 1,\n                             return_class = c(\"data.frame\", \"data.table\", \"tbl_df\", \"raw\"),\n                             reactable_options = NULL,\n                             modal_size = c(\"m\", \"s\", \"l\", \"xl\"),\n                             modal_easy_close = TRUE,\n                             callback_add = NULL,\n                             callback_update = NULL,\n                             callback_delete = NULL,\n                             only_callback = FALSE,\n                             use_notify = TRUE) {\n  return_class <- match.arg(return_class)\n  modal_size <- match.arg(modal_size)\n  callback_default <- function(...) return(TRUE)\n  if (!is_function(callback_add))\n    callback_add <- callback_default\n  if (!is_function(callback_update))\n    callback_update <- callback_default\n  if (!is_function(callback_delete))\n    callback_delete <- callback_default\n  moduleServer(\n    id,\n    function(input, output, session) {\n\n      ns <- session$ns\n\n      data_rv <- reactiveValues(data = NULL, colnames = NULL, mandatory = NULL, edit = NULL)\n\n      # Data data_r() with added columns \".datamods_edit_update\" et \".datamods_edit_delete\" ---\n      data_init_r <- eventReactive(data_r(), {\n        req(data_r())\n        data <- data_r()\n        if (is.reactive(var_mandatory))\n          var_mandatory <- var_mandatory()\n        if (is.reactive(var_labels))\n          var_labels <- var_labels()\n        if (is.null(var_labels))\n          var_labels <- setNames(as.list(names(data)), names(data))\n        if (is.reactive(var_edit))\n          var_edit <- var_edit()\n        if (is.null(var_edit))\n          var_edit <- names(data)\n        data <- as.data.table(data)\n        data_rv$colnames <- copy(colnames(data))\n        if (ncol(data) > 0) {\n          setnames(data, paste0(\"col_\", seq_along(data)))\n          data_rv$internal_colnames <- copy(colnames(data))\n        }\n        data_rv$mandatory <- data_rv$internal_colnames[data_rv$colnames %in% var_mandatory]\n        data_rv$edit <- data_rv$internal_colnames[data_rv$colnames %in% var_edit]\n        data_rv$labels <- get_variables_labels(var_labels, data_rv$colnames, data_rv$internal_colnames)\n\n        data[, .datamods_id := seq_len(.N)]\n\n        if (is.reactive(update)) {\n          update <- update()\n        }\n\n        if (isTRUE(update)) {\n          data[, .datamods_edit_update := as.character(seq_len(.N))]\n          data[, .datamods_edit_update := list(\n            lapply(.datamods_edit_update, btn_update(ns(\"update\")))\n          )]\n        } else {\n          data[, .datamods_edit_update := NA]\n        }\n\n        if (is.reactive(delete)) {\n          delete <- delete()\n        }\n\n        if (isTRUE(delete)) {\n        data[, .datamods_edit_delete := as.character(seq_len(.N))]\n        data[, .datamods_edit_delete := list(\n          lapply(.datamods_edit_delete, btn_delete(ns(\"delete\")))\n        )]\n        } else {\n          data[, .datamods_edit_delete := NA]\n        }\n\n        data_rv$data <- data\n        return(data)\n      })\n\n\n      # Table ---\n      output$table <- renderReactable({\n        data <- req(data_init_r())\n        if (is.reactive(reactable_options))\n          reactable_options <- reactable_options()\n        table_display(\n          data = data,\n          colnames = data_rv$colnames,\n          reactable_options = reactable_options\n        )\n      })\n\n      # Retrieve selected row(s)\n      selected_r <- reactive({\n        getReactableState(\"table\", \"selected\")\n      })\n\n\n      # Add a row ---\n      output$add_button <- renderUI({\n        if (is.reactive(add)) {\n          add <- add()\n        }\n        if (isTRUE(add)) {\n          actionButton(\n            inputId = ns(\"add\"),\n            label = tagList(ph(\"plus\"), i18n(\"Add a row\")),\n            class = \"btn-outline-primary float-end\"\n          )\n        }\n      })\n\n      observeEvent(input$add, {\n        req(data_r())\n        edit_modal(\n          default = get_variables_default(\n            add_default_values,\n            data_rv$colnames,\n            data_rv$internal_colnames\n          ),\n          id_validate = \"add_row\",\n          data = data_rv$data,\n          var_edit = data_rv$edit,\n          var_mandatory = data_rv$mandatory,\n          var_labels = data_rv$labels,\n          modal_size = modal_size,\n          modal_easy_close = modal_easy_close,\n          n_column = n_column\n        )\n      })\n\n      observeEvent(input$add_row, {\n        req(data_r())\n        data <- copy(data_rv$data)\n        data <- as.data.table(data)\n\n        for (var in data_rv$mandatory) {\n          if (!isTruthy(input[[var]])) {\n            notification_warning(\n              title = i18n(\"Required field\"),\n              text = i18n(\"Please fill in the required fields\"),\n              use_notify = use_notify\n            )\n            return(NULL)\n          }\n        }\n\n        results_add <- try({\n          results_inputs <- lapply(\n            X = setNames(data_rv$edit, data_rv$edit),\n            FUN = function(x) {\n              input[[x]] %||% NA\n            }\n          )\n          id <- max(data$.datamods_id) + 1\n          results_inputs[[\".datamods_id\"]] <- id\n          results_inputs[[\".datamods_edit_update\"]] <- if (update) list(btn_update(ns(\"update\"))(id)) else NA\n          results_inputs[[\".datamods_edit_delete\"]] <- if (delete) list(btn_delete(ns(\"delete\"))(id)) else NA\n\n          new <- as.data.table(results_inputs)\n\n          res_callback <- callback_add(\n            format_edit_data(data, data_rv$colnames),\n            format_edit_data(new, data_rv$colnames, data_rv$internal_colnames)\n          )\n\n          if (isTruthy(res_callback) & !isTRUE(only_callback)) {\n            data <- rbind(data, new[, .SD, .SDcols = !anyNA], use.names = TRUE, fill = TRUE)\n            data_rv$data <- data\n            removeModal()\n            update_table(data, data_rv$colnames)\n          } else {\n            NULL\n          }\n        })\n\n        if (is.null(results_add)) {\n          notification_warning(\n            title = i18n(\"Warning\"),\n            text = i18n(\"The row wasn't added to the data\"),\n            use_notify = use_notify\n          )\n        } else if (inherits(results_add, \"try-error\")) {\n          notification_failure(\n            title = i18n(\"Error\"),\n            text = i18n(\"Unable to add the row, contact the platform administrator\"),\n            use_notify = use_notify\n          )\n        } else {\n          notification_success(\n            title = i18n(\"Registered\"),\n            text = i18n(\"Row has been saved\"),\n            use_notify = use_notify\n          )\n        }\n      })\n\n\n      # Update a row ---\n      observeEvent(input$update, {\n        data <- copy(data_rv$data)\n        data <- as.data.table(data)\n        row <- data[.datamods_id == input$update]\n        edit_modal(\n          default = row,\n          title = i18n(\"Update row\"),\n          id_validate = \"update_row\",\n          data = data,\n          var_edit = data_rv$edit,\n          var_mandatory = data_rv$mandatory,\n          var_labels = data_rv$labels,\n          modal_size = modal_size,\n          modal_easy_close = modal_easy_close,\n          n_column = n_column\n        )\n      })\n\n      observeEvent(input$update_row, {\n        req(data_r())\n        data <- copy(data_rv$data)\n        data <- as.data.table(data)\n\n        for (var in data_rv$mandatory) {\n          if (!isTruthy(input[[var]])) {\n            notification_failure(\n              title = i18n(\"Required field\"),\n              text = i18n(\"Please fill in the required fields\"),\n              use_notify = use_notify\n            )\n            return(NULL)\n          }\n        }\n\n        results_update <- try({\n          id <- input$update\n\n          data_updated <- copy(data)\n          data_updated[.datamods_id == id, (data_rv$edit) := lapply(data_rv$edit, function(x) {\n            input[[x]] %||% NA\n          })]\n\n          res_callback <- callback_update(\n            format_edit_data(data, data_rv$colnames),\n            format_edit_data(\n              data_updated[.datamods_id == id],\n              data_rv$colnames,\n              data_rv$internal_colnames\n            )\n          )\n          if (isTruthy(res_callback) & !isTRUE(only_callback)) {\n            data_updated <- data_updated[order(.datamods_id)]\n            data_rv$data <- copy(data_updated)\n            removeModal()\n            update_table(data_updated, data_rv$colnames)\n          } else {\n            NULL\n          }\n        })\n        if (is.null(results_update)) {\n          notification_warning(\n            title = i18n(\"Warning\"),\n            text = i18n(\"Data wasn't updated\"),\n            use_notify = use_notify\n          )\n        } else if (inherits(results_update, \"try-error\")) {\n          notification_failure(\n            title = i18n(\"Error\"),\n            text = i18n(\"Unable to modify the item, contact the platform administrator\"),\n            use_notify = use_notify\n          )\n        } else {\n          notification_success(\n            title = i18n(\"Registered\"),\n            text = i18n(\"Item has been modified\"),\n            use_notify = use_notify\n          )\n        }\n      })\n\n\n      # Delete a row ---\n      observeEvent(input$delete, {\n        req(data_r())\n        data <- copy(data_rv$data)\n        data <- as.data.table(data)\n        row <- data[.datamods_id == input$delete]\n        removeModal()\n        showModal(confirmation_window(\n          inputId = ns(\"confirmation_delete_row\"),\n          title = i18n(\"Delete\"),\n          i18n(\"Do you want to delete the selected row ?\")\n        ))\n      })\n      observeEvent(input$confirmation_delete_row_yes, {\n        req(data_r())\n        data <- copy(data_rv$data)\n        data <- as.data.table(data)\n\n        results_delete <- try({\n\n          res_callback <- callback_delete(\n            format_edit_data(data, data_rv$colnames),\n            format_edit_data(\n              data[.datamods_id == input$delete],\n              data_rv$colnames,\n              data_rv$internal_colnames\n            )\n          )\n\n          if (isTruthy(res_callback) & !isTRUE(only_callback)) {\n            data <- data[.datamods_id != input$delete]\n            data <- data[order(.datamods_id)]\n            data_rv$data <- data\n            removeModal()\n            update_table(data, data_rv$colnames)\n          } else {\n            NULL\n          }\n        })\n        if (is.null(results_delete)) {\n          notification_warning(\n            title = i18n(\"Warning\"),\n            text = i18n(\"Data wasn't deleted\"),\n            use_notify = use_notify\n          )\n        } else if (inherits(results_delete, \"try-error\")) {\n          notification_failure(\n            title = i18n(\"Error\"),\n            text = i18n(\"Unable to delete the row, contact platform administrator\"),\n            use_notify = use_notify\n          )\n        } else {\n          notification_success(\n            title = i18n(\"Registered\"),\n            text = i18n(\"The row has been deleted\"),\n            use_notify = use_notify\n          )\n        }\n      })\n      observeEvent(input$confirmation_delete_row_no, {\n        notification_info(\n          title = i18n(\"Information\"),\n          text = i18n(\"Row was not deleted\"),\n          use_notify = use_notify\n        )\n        removeModal()\n      })\n\n\n      # Download data in Excel format ---\n      output$download_excel <- renderUI({\n        if (is.reactive(download_excel)) {\n          download_excel <- download_excel()\n        }\n        if (isTRUE(download_excel)) {\n          downloadButton(\n            outputId = ns(\"export_excel\"),\n            label = tagList(ph(\"download\"), \"Excel\"),\n            icon = NULL,\n            class = \"btn-datamods-export\"\n          )\n        }\n      })\n\n      output$export_excel <- downloadHandler(\n        filename = function() {\n          file_name <- file_name_export\n          paste0(file_name, \".xlsx\")\n        },\n        content = function(file) {\n          data <- format_edit_data(data_rv$data, data_rv$colnames)\n          write_xlsx(\n            x = list(data = data),\n            path = file\n          )\n        }\n      )\n\n      # Download data in csv format ---\n      output$download_csv <- renderUI({\n        if (is.reactive(download_csv)) {\n          download_csv <- download_csv()\n        }\n        if (isTRUE(download_csv)) {\n          downloadButton(\n            outputId = ns(\"export_csv\"),\n            label = tagList(ph(\"download\"), \"CSV\"),\n            icon = NULL,\n            class = \"btn-datamods-export\"\n          )\n        }\n      })\n      output$export_csv <- downloadHandler(\n        filename = function() {\n          file_name <- file_name_export\n          paste0(file_name, \".csv\")\n        },\n        content = function(file) {\n          data <- format_edit_data(data_rv$data, data_rv$colnames)\n          write.csv(\n            x = data,\n            file = file\n          )\n        }\n      )\n\n\n      return(\n        reactive({\n          req(data_rv$data)\n          data <- format_edit_data(data_rv$data, data_rv$colnames)\n          setattr(data, \"selected\", selected_r())\n          as_out(data, return_class)\n        })\n      )\n\n    }\n  )\n}\n\n"
  },
  {
    "path": "R/filter-data.R",
    "content": "\n#' @title Shiny module to interactively filter a `data.frame`\n#'\n#' @description Module generate inputs to filter `data.frame` according column's type.\n#'  Code to reproduce the filter is returned as an expression with filtered data.\n#'\n#' @param id Module id. See [shiny::moduleServer()].\n#' @param show_nrow Show number of filtered rows and total.\n#' @param max_height Maximum height for filters panel, useful\n#'  if you have many variables to filter and limited space.\n#'\n#' @return\n#' * UI: HTML tags that can be included in shiny's UI\n#' * Server: a `list` with four slots:\n#'   + **filtered**: a `reactive` function returning the data filtered.\n#'   + **code**: a `reactive` function returning the dplyr pipeline to filter data.\n#'   + **expr**: a `reactive` function returning an expression to filter data.\n#'   + **values**: a `reactive` function returning a named list of variables and filter values.\n#'\n#' @export\n#'\n#' @name filter-data\n#'\n#' @importFrom htmltools tagList singleton tags validateCssUnit\n#' @importFrom shiny NS uiOutput\n#'\n#' @example examples/filter_data.R\nfilter_data_ui <- function(id,\n                           show_nrow = TRUE,\n                           max_height = NULL) {\n  ns <- NS(id)\n  max_height <- if (!is.null(max_height)) {\n    paste0(\"overflow-y: auto; overflow-x: hidden; max-height:\", validateCssUnit(max_height), \";\")\n  }\n  tagList(\n    singleton(\n      tags$style(\n        \".selectize-big .selectize-input {height: 72px; overflow-y: scroll;}\"\n      )\n    ),\n    if (isTRUE(show_nrow)) {\n      tags$span(i18n(\"Number of rows:\"), uiOutput(outputId = ns(\"nrow\"), inline = TRUE))\n    },\n    uiOutput(outputId = ns(\"placeholder_filters\"), style = max_height)\n  )\n}\n\n#' @param data [shiny::reactive()] function returning a\n#'  \\code{data.frame} to filter.\n#' @param vars [shiny::reactive()] function returning a\n#'  `character` vector of variables for which to add a filter.\n#'  If a named `list`, names are used as labels.\n#' @param name [shiny::reactive()] function returning a\n#'  `character` string representing `data` name, only used for code generated.\n#' @param defaults [shiny::reactive()] function returning a\n#'  named `list` of variable:value pairs which will be used to set the filters.\n#' @param drop_ids Drop columns containing more than 90% of unique values, or than 50 distinct values.\n#' Use `FALSE` to disable or use `list(p = 0.9, n = 50)` to customize threshold values.\n#' @param widget_char Widget to use for `character` variables: [shinyWidgets::pickerInput()]\n#'  or [shiny::selectInput()] (default).\n#' @param widget_num Widget to use for `numeric` variables: [shinyWidgets::numericRangeInput()]\n#'  or [shiny::sliderInput()] (default).\n#' @param widget_date Widget to use for `date/time` variables: [shiny::dateRangeInput()]\n#'  or [shiny::sliderInput()] (default).\n#' @param label_na Label for missing value widget.\n#' @param value_na Default value for all NA's filters.\n#'\n#'\n#' @rdname filter-data\n#' @export\n#'\n#' @importFrom rlang eval_tidy %||%\n#' @importFrom shiny observeEvent reactiveValues removeUI\n#'  insertUI reactive req isolate reactive renderUI tags outputOptions\nfilter_data_server <- function(id,\n                               data = reactive(NULL),\n                               vars = reactive(NULL),\n                               name = reactive(\"data\"),\n                               defaults = reactive(NULL),\n                               drop_ids = getOption(\"datamods.filter.drop_ids\", default = TRUE),\n                               widget_char = c(\"virtualSelect\", \"select\", \"picker\"),\n                               widget_num = c(\"slider\", \"range\"),\n                               widget_date = c(\"slider\", \"range\"),\n                               label_na = \"NA\",\n                               value_na = TRUE) {\n  widget_char <- match.arg(widget_char)\n  widget_num <- match.arg(widget_num)\n  widget_date <- match.arg(widget_date)\n  moduleServer(\n    id,\n    function(input, output, session) {\n      ns <- session$ns\n      jns <- function(x) paste0(\"#\", ns(x))\n\n      output$nrow <- renderUI({\n        tags$b(nrow(data_filtered()) , \"/\", nrow(data()))\n      })\n\n      rv_filters <- reactiveValues(mapping = NULL, mapping_na = NULL)\n      rv_code <- reactiveValues(expr = NULL, dplyr = NULL)\n\n      output$placeholder_filters <- renderUI({\n        data <- data()\n        req(data)\n        vars <- vars()\n        defaults <- defaults()\n        filters <- create_filters(\n          data = data,\n          vars = vars,\n          defaults = defaults,\n          drop_ids = drop_ids,\n          widget_char = widget_char,\n          widget_num = widget_num,\n          widget_date = widget_date,\n          label_na = label_na,\n          value_na = value_na\n        )\n        rv_filters$mapping <- filters$filters_id\n        rv_filters$mapping_na <- filters$filters_na_id\n        return(filters$ui)\n      })\n\n      filter_values <- reactive({\n        data <- data()\n        req(data)\n        req(all(names(rv_filters$mapping) %in% names(data)))\n        filter_inputs <- lapply(\n          X = rv_filters$mapping,\n          FUN = function(x) {\n            input[[x]]\n          }\n        )\n        filter_inputs\n      })\n\n      data_filtered <- reactive({\n        data <- data()\n        req(data)\n        req(all(names(rv_filters$mapping) %in% names(data)))\n        filter_inputs <- lapply(\n          X = rv_filters$mapping,\n          FUN = function(x) {\n            # req(input[[x]])\n            input[[x]]\n          }\n        )\n        filter_nas <- lapply(\n          X = rv_filters$mapping_na,\n          FUN = function(x) {\n            input[[x]]\n          }\n        )\n        filters <- make_expr_filter(\n          filters = filter_inputs,\n          filters_na = filter_nas,\n          data = data,\n          data_name = isolate(name()) %||% \"data\"\n        )\n        rv_code$expr <- filters$expr\n        rv_code$dplyr <- filters$expr_dplyr\n        if (length(rv_code$expr) > 0) {\n          result <- eval_tidy(expr = rv_code$expr, data = data)\n          data[result, , drop = FALSE]\n        } else {\n          data\n        }\n      })\n      outputOptions(x = output, name = \"placeholder_filters\", suspendWhenHidden = FALSE)\n\n      return(list(\n        filtered = data_filtered,\n        values = filter_values,\n        code = reactive(rv_code$dplyr),\n        expr = reactive(rv_code$expr)\n      ))\n    }\n  )\n}\n\n\n\n# Utils -------------------------------------------------------------------\n\n\n\n\n#' @importFrom htmltools HTML tagList tags\n#' @importFrom shiny selectizeInput sliderInput dateRangeInput\n#' @importFrom stats setNames\n#' @importFrom shinyWidgets pickerInput pickerOptions numericRangeInput virtualSelectInput\n#' @importFrom rlang is_list\ncreate_filters <- function(data,\n                           vars = NULL,\n                           defaults = NULL,\n                           drop_ids = TRUE,\n                           widget_char = c(\"virtualSelect\", \"select\", \"picker\"),\n                           widget_num = c(\"slider\", \"range\"),\n                           widget_date = c(\"slider\", \"range\"),\n                           label_na = \"NA\",\n                           value_na = TRUE,\n                           width = \"100%\",\n                           session = getDefaultReactiveDomain()) {\n  data <- as.data.frame(data)\n  if (ncol(data) < 1)\n    return(NULL)\n  widget_char <- match.arg(widget_char)\n  widget_num <- match.arg(widget_num)\n  widget_date <- match.arg(widget_date)\n  ns <- session$ns\n  data <- drop_na(data)\n  if (isTRUE(drop_ids)) {\n    data <- drop_id(data)\n  }\n  if (is_list(drop_ids)) {\n    data <- drop_id(data, n = drop_ids$n, p = drop_ids$p)\n  }\n  data <- dropListColumns(data)\n  if (is.null(vars)) {\n    vars <- names(data)\n    labels <- vars\n  } else {\n    if (rlang::is_named(vars)) {\n      labels <- names(vars)\n      vars <- unname(unlist(vars))\n    } else {\n      labels <- vars\n    }\n    vars_display <- intersect(vars, names(data))\n    labels <- labels[vars %in% vars_display]\n    vars <- vars_display\n  }\n  # filters_id <- paste0(\"filter_\", sample.int(1e9, length(vars)))\n  filters_id <- paste0(\"filter_\", makeId(vars))\n  filters_id <- setNames(as.list(filters_id), vars)\n  filters_na_id <- setNames(as.list(paste0(\"na_\", filters_id)), vars)\n  ui <- lapply(\n    X = vars,\n    FUN = function(variable) {\n      var <- data[[variable]]\n      any_na <- anyNA(var)\n      var <- var[!is.na(var)]\n      id <- filters_id[[variable]]\n      label <- labels[variable == vars]\n\n      tag_label <- tags$span(\n        tags$label(\n          label,\n          class = \"control-label\",\n          `for` = id\n        ),\n        HTML(\"&nbsp;&nbsp;\"),\n        if (any_na) na_filter(id = ns(paste0(\"na_\", id)), label = label_na, value = value_na)\n      )\n\n      if (inherits(x = var, what = c(\"numeric\", \"integer\"))) {\n        params <- find_range_step(var)\n        if(!is.null(defaults) && label %in% names(defaults)){\n          params$range = defaults[[label]]\n        }\n        if (identical(widget_num, \"slider\")) {\n          tags$div(\n            style = \"position: relative;\",\n            tag_label,\n            set_slider_attr(sliderInput(\n              inputId = ns(id),\n              min = params$min,\n              max = params$max,\n              value = params$range,\n              step = params$step,\n              label = NULL,\n              width = width\n            ))\n          )\n        } else {\n          tags$div(\n            style = \"position: relative;\",\n            tag_label,\n            numericRangeInput(\n              inputId = ns(id),\n              value = params$range,\n              label = NULL,\n              width = width\n            )\n          )\n        }\n      } else if (inherits(x = var, what = c(\"Date\", \"POSIXct\"))) {\n        # browser()\n        var <- pretty(var)\n        range_var <- range(var)\n        if(!is.null(defaults) && label %in% names(defaults)) {\n          range_var <- defaults[[label]]\n        }\n        if (identical(widget_date, \"slider\")) {\n          tags$div(\n            style = \"position: relative;\",\n            tag_label,\n            set_slider_attr(sliderInput(\n              inputId = ns(id),\n              min = range_var[1],\n              max = range_var[2],\n              value = range_var,\n              label = NULL,\n              width = width,\n              timezone = if (inherits(var, \"POSIXct\")) format(var[1], format = \"%z\")\n            ))\n          )\n        } else {\n          range_var <- format(range_var, format = \"%Y-%m-%d\")\n          tags$div(\n            style = \"position: relative;\",\n            tag_label,\n            dateRangeInput(\n              inputId = ns(id),\n              min = range_var[1],\n              max = range_var[2],\n              start = range_var[1],\n              end = range_var[2],\n              label = NULL,\n              width = width\n            )\n          )\n        }\n      } else {\n        choices <- unique(as.character(sort(var)))\n        if (\"\" %in% choices)\n          choices <- append(choices, .empty_field_char)\n        choices <- tryCatch(choices[trimws(choices) != \"\"], error = function(e) {\n          Encoding(choices[!validEnc(choices)]) <- \"unknown\"\n          choices\n        })\n        selected <- choices\n        if(!is.null(defaults) && label %in% names(defaults)){\n          selected = defaults[[label]]\n        }\n        if (identical(widget_char, \"picker\")) {\n          tags$div(\n            style = \"position: relative;\",\n            tag_label,\n            pickerInput(\n              inputId = ns(id),\n              choices = choices,\n              selected = selected,\n              label = NULL,\n              multiple = TRUE,\n              width = width,\n              options = pickerOptions(\n                container = \"body\",\n                actionsBox = TRUE,\n                selectedTextFormat = \"count\",\n                liveSearch = TRUE\n              )\n            )\n          )\n        } else if (identical(widget_char, \"virtualSelect\")) {\n          tags$div(\n            style = \"position: relative;\",\n            tag_label,\n            virtualSelectInput(\n              inputId = ns(id),\n              choices = choices,\n              selected = selected,\n              label = NULL,\n              multiple = TRUE,\n              width = width,\n              showValueAsTags = TRUE,\n              zIndex = 9999,\n              dropboxWrapper = paste0(\"#\", ns(\"placeholder_filters\"), \" .datamods-filters-container\"),\n              html = TRUE\n            )\n          )\n        } else {\n          tags$div(\n            style = \"position: relative;\",\n            class = if (length(choices) > 15) \"selectize-big\",\n            tag_label,\n            selectizeInput(\n              inputId = ns(id),\n              choices = choices,\n              selected = selected,\n              label = NULL,\n              multiple = TRUE,\n              width = width,\n              options = list(plugins = list(\"remove_button\"))\n            )\n          )\n        }\n      }\n    }\n  )\n  list(\n    ui = tags$div(\n      class = \"datamods-filters-container\",\n      ui\n    ),\n    filters_id = filters_id,\n    filters_na_id = filters_na_id\n  )\n}\n\ntagSetAttributes <- function(tag, ...) {\n  tag$attribs[names(list(...))] <- NULL\n  tag$attribs <- c(tag$attribs, list(...))\n  tag\n}\n\nset_slider_attr <- function(slider) {\n  slider$children[[2]] <- tagSetAttributes(\n    tag = slider$children[[2]],\n    `data-force-edges` = \"true\",\n    `data-grid-num` = \"4\"\n  )\n  slider\n}\n\n#' @importFrom htmltools tags\n#' @importFrom shinyWidgets prettySwitch\nna_filter <- function(id, label = \"NA\", value = TRUE) {\n  tags$span(\n    style = \"position: absolute; right: 0px; margin-right: -20px;\",\n    prettySwitch(\n      inputId = id,\n      label = label,\n      value = value,\n      slim = TRUE,\n      status = \"primary\",\n      inline = TRUE\n    )\n  )\n}\n\n\n#' @importFrom rlang expr sym\nmake_expr_filter <- function(filters, filters_na, data, data_name) {\n  expressions <- lapply(\n    X = names(filters),\n    FUN = function(var) {\n      values <- filters[[var]]\n      nas <- filters_na[[var]]\n      data_values <- data[[var]]\n      if (!is.null(values) & !match_class(values, data_values))\n        return(NULL)\n      values_expr <- NULL\n      if (inherits(x = values, what = c(\"numeric\", \"integer\"))) {\n        data_range <- find_range_step(data_values)$range\n        if (!isTRUE(all.equal(values, data_range))) {\n          if (isTRUE(nas)) {\n            if (anyNA(data_values)) {\n              values_expr <- expr(!!sym(var) >= !!values[1] & !!sym(var) <= !!values[2] | is.na(!!sym(var)))\n            } else {\n              values_expr <- expr(!!sym(var) >= !!values[1] & !!sym(var) <= !!values[2])\n            }\n          } else {\n            if (anyNA(data_values)) {\n              values_expr <- expr(!!sym(var) >= !!values[1] & !!sym(var) <= !!values[2] & !is.na(!!sym(var)))\n            } else {\n              values_expr <- expr(!!sym(var) >= !!values[1] & !!sym(var) <= !!values[2])\n            }\n          }\n        }\n      } else if (inherits(x = values, what = c(\"Date\", \"POSIXct\"))) {\n        date_fmt <- if (inherits(values, \"Date\")) {\n          \"%Y-%m-%d\"\n        } else {\n          \"%Y-%m-%d %H:%M:%S\"\n        }\n        data_values <- pretty(data_values)\n        data_range <- range(data_values, na.rm = TRUE)\n        data_range <- format(data_range, format = date_fmt, tz = \"UTC\")\n        if (!identical(format(values, format = date_fmt, tz = \"UTC\"), data_range)) {\n          values <- format(values, format = date_fmt)\n          if (isTRUE(nas)) {\n            if (anyNA(data_values)) {\n              values_expr <- expr(!!sym(var) >= !!values[1] & !!sym(var) <= !!values[2] | is.na(!!sym(var)))\n            } else {\n              values_expr <- expr(!!sym(var) >= !!values[1] & !!sym(var) <= !!values[2])\n            }\n          } else {\n            if (anyNA(data_values)) {\n              values_expr <- expr(!!sym(var) >= !!values[1] & !!sym(var) <= !!values[2] & !is.na(!!sym(var)))\n            } else {\n              values_expr <- expr(!!sym(var) >= !!values[1] & !!sym(var) <= !!values[2])\n            }\n          }\n        }\n      } else {\n        data_values <- unique(as.character(data_values))\n        if (.empty_field_char %in% values)\n          values[which(values == .empty_field_char)] <- \"\"\n        if (!identical(sort(values), sort(data_values))) {\n          if (length(values) == 0) {\n            if (isTRUE(nas)) {\n              values_expr <- expr(is.na(!!sym(var)))\n            } else {\n              values_expr <- expr(!(!!sym(var) %in% !!data_values[!is.na(data_values)]) & !is.na(!!sym(var)))\n            }\n          } else {\n            if (length(values) <= length(data_values)/2) {\n              if (isTRUE(nas)) {\n                if (anyNA(data_values)) {\n                  values_expr <- expr(!!sym(var) %in% !!values | is.na(!!sym(var)))\n                } else {\n                  values_expr <- expr(!!sym(var) %in% !!values)\n                }\n              } else {\n                values_expr <- expr(!!sym(var) %in% !!values)\n              }\n            } else {\n              if (isTRUE(nas)) {\n                if (anyNA(data_values)) {\n                  values_expr <- expr(!(!!sym(var) %in% !!setdiff(data_values[!is.na(data_values)], values)) | is.na(!!sym(var)))\n                } else {\n                  values_expr <- expr(!(!!sym(var) %in% !!setdiff(data_values[!is.na(data_values)], values)))\n                }\n              } else {\n                if (anyNA(data_values)) {\n                  values_expr <- expr(!(!!sym(var) %in% !!setdiff(data_values[!is.na(data_values)], values)) & !is.na(!!sym(var)))\n                } else {\n                  values_expr <- expr(!(!!sym(var) %in% !!setdiff(data_values[!is.na(data_values)], values)))\n                }\n              }\n            }\n          }\n        }\n      }\n      if (is.null(values_expr) & !isTRUE(nas) & anyNA(data_values)) {\n        expr(!is.na(!!sym(var)))\n      } else {\n        values_expr\n      }\n    }\n  )\n  expressions <- lapply(\n    X = expressions,\n    FUN = function(expr) {\n      res_expr <- try(eval_tidy(expr = expr, data = data), silent = TRUE)\n      if (inherits(res_expr, \"try-error\"))\n        return(expr)\n      if (isTRUE(all(res_expr)))\n        return(NULL)\n      expr\n    }\n  )\n  expressions <- dropNullsOrEmpty(expressions)\n  data_name <- as.character(data_name)\n  if (grepl(\"::\", data_name)) {\n    data_name <- str2lang(data_name)\n  } else {\n    data_name <- sym(data_name)\n  }\n  expr_dplyr <- Reduce(\n    f = function(x, y) expr(!!x %>% filter(!!y)),\n    x = expressions,\n    init = expr(!!data_name)\n  )\n  expression <- Reduce(\n    f = function(x, y) expr(!!x & !!y),\n    x = expressions\n  )\n  return(list(\n    expr_dplyr = expr_dplyr,\n    expr = expression\n  ))\n}\n\n#' @importFrom rlang is_double\ndrop_id <- function(data, p = 0.9, n = 50) {\n  p <- as.numeric(p)\n  if (!is_double(p, n = 1))\n    p <- 0.9\n  n <- as.numeric(n)\n  if (!is_double(n, n = 1))\n    n <- 50\n  data[] <- lapply(\n    X = data,\n    FUN = function(x) {\n      if (inherits(x, c(\"factor\", \"character\"))) {\n        values <- unique(as.character(x))\n        values <- tryCatch(\n          values[trimws(values) != \"\"],\n          error = function(e) {\n            Encoding(values[!validEnc(values)]) <- \"unknown\"\n            values\n          }\n        )\n        if (length(values) <= 1)\n          return(NULL)\n        if (isTRUE(length(values) >= (length(x) * p)))\n          return(NULL)\n        if (isTRUE(length(values) >= n))\n          return(NULL)\n      }\n      x\n    }\n  )\n  data\n}\n\ndrop_na <- function(data) {\n  data[] <- lapply(\n    X = data,\n    FUN = function(x) {\n      if (all(is.na(x)))\n        return(NULL)\n      x\n    }\n  )\n  data\n}\n\n\n# borrowed from shiny\nhasDecimals <- function (value) {\n  truncatedValue <- round(value)\n  return(!identical(value, truncatedValue))\n}\n\nfind_range_step <- function(x) {\n  max <- max(x, na.rm = TRUE)\n  min <- min(x, na.rm = TRUE)\n  range <- max - min\n  if (range < 2 || hasDecimals(min) || hasDecimals(max)) {\n    pretty_steps <- pretty(c(min, max), n = 100, high.u.bias = 1)\n    n_steps <- length(pretty_steps) - 1\n    list(\n      range = range(pretty_steps),\n      min = min(pretty_steps),\n      max = max(pretty_steps),\n      step = signif(digits = 10, (max(pretty_steps) - min(pretty_steps))/n_steps)\n    )\n  }\n  else {\n    list(\n      range = range(x, na.rm = TRUE),\n      min = min,\n      max = max,\n      step = 1\n    )\n  }\n}\n\nmatch_class <- function(x, y) {\n  char <- c(\"character\", \"factor\")\n  num <- c(\"numeric\", \"integer\")\n  date <- c(\"Date\", \"POSIXt\")\n  if (inherits(x, num) & inherits(y, num))\n    return(TRUE)\n  if (inherits(x, char) & inherits(y, char))\n    return(TRUE)\n  if (inherits(x, date) & inherits(y, date))\n    return(TRUE)\n  return(FALSE)\n}\n\n\n.empty_field_char <- \"\\u3008 \\U0001d626\\U0001d62e\\U0001d631\\U0001d635\\U0001d63a \\U0001d627\\U0001d62a\\U0001d626\\U0001d62d\\U0001d625 \\u3009\"\n"
  },
  {
    "path": "R/i18n.R",
    "content": "\n#' @title Internationalization\n#'\n#' @description Simple mechanism to translate labels in a Shiny application.\n#'\n#' @param x Label to translate.\n#' @param translations Either a `list` or a `data.frame` with translations.\n#'\n#' @return `i18n()` returns a `character`, `i18n_translations()` returns a `list` or a `data.frame`.\n#' @export\n#'\n#' @name i18n\n#'\n#' @importFrom data.table as.data.table :=\n#'\n#' @example examples/i18n.R\ni18n <- function(x, translations = i18n_translations()) {\n  if (is.null(translations))\n    return(x)\n  if (is.list(translations) & !is.data.frame(translations)) {\n    if (!x %in% names(translations)) {\n      warning(\"i18n: translation for '\", x, \"' not found!\", call. = FALSE)\n      return(x)\n    }\n    return(translations[[x]])\n  }\n  if (is.data.frame(translations)) {\n    translations <- as.data.table(translations)\n    translations[, label := as.character(label)]\n    translations <- unique(translations, by = \"label\")\n    translations[, translation := as.character(translation)]\n    if (!x %in% translations$label) {\n      warning(\"i18n: translation for '\", x, \"' not found!\", call. = FALSE)\n      return(x)\n    }\n    return(translations[label == x, c(translation)])\n  }\n  stop(\"i18n option must be either: a list, a data.frame, or a path to a valid file.\", call. = FALSE)\n}\n\n#' @param package Name of the package where the function is called, use `NULL` outside a package.\n#'  It will retrieve option `\"i18n.<PACKAGE>\"` (or `\"i18n\"` if no package) to returns appropriate labels.\n#'\n#' @export\n#'\n#' @rdname i18n\n#'\n#' @importFrom utils packageName\n#' @importFrom data.table fread\ni18n_translations <- function(package = packageName(parent.frame(2))) {\n  if (is.null(package)) {\n    opts <- \"i18n\"\n  } else {\n    opts <- paste(package, \"i18n\", sep = \".\")\n  }\n  language <- getOption(x = opts)\n  if (is.null(language))\n    return(NULL)\n  if (is.character(language) && i18n_exist(language, package = package)) {\n    language <- fread(file = i18n_file(language, package = package), encoding = \"UTF-8\", fill = TRUE)\n  } else if (is.character(language) && file.exists(language)) {\n    language <- fread(file = language, encoding = \"UTF-8\", fill = TRUE)\n  } else if (is.character(language)) {\n    warning(\n      \"i18n translations not found for : \", language,\n      call. = FALSE\n    )\n    language <- NULL\n  }\n  return(language)\n}\n\n#' @param value Value to set for translation. Can be:\n#'   * single `character` to use a supported language (`\"fr\"`, `\"mk\"`, `\"al\"`, `\"pt\"` for esquisse and datamods packages).\n#'   * a `list` with labels as names and translations as values.\n#'   * a `data.frame` with 2 column: `label` & `translation`.\n#'   * path to a CSV file with same structure as for `data.frame` above.\n#' @param packages Name of packages for which to set i18n, default to esquisse and datamods\n#'\n#' @export\n#'\n#' @rdname i18n\n#'\n#' @importFrom stats setNames\nset_i18n <- function(value, packages = c(\"datamods\", \"esquisse\")) {\n  if (is.null(packages)) {\n    options(\"i18n\" = value)\n  } else {\n    i18n.opts <- setNames(\n      lapply(seq_along(packages), function(...) value),\n      paste(packages, \"i18n\", sep = \".\")\n    )\n    options(i18n.opts)\n  }\n}\n\n\ni18n_file <- function(x, package) {\n  if (is.null(package))\n    return(character(0))\n  system.file(\"i18n\", paste0(x, \".csv\"), package = package)\n}\ni18n_exist <- function(x, package) {\n  isTRUE(file.exists(i18n_file(x, package)))\n}\n\ni18n_test <- function(x) {\n  i18n(x)\n}\n"
  },
  {
    "path": "R/import-copypaste.R",
    "content": "\n#' @title Import data with copy & paste\n#'\n#' @description Let the user copy data from Excel or text file then paste it into a text area to import it.\n#'\n#' @inheritParams import-globalenv\n#' @param name_field Show or not a field to add a name to data (that is returned server-side).\n#'\n#' @template module-import\n#'\n#' @export\n#'\n#' @name import-copypaste\n#'\n#' @importFrom shiny NS icon textAreaInput actionButton textInput\n#' @importFrom htmltools tags tagAppendAttributes\n#'\n#' @example examples/from-copypaste.R\nimport_copypaste_ui <- function(id, title = TRUE, name_field = TRUE) {\n\n  ns <- NS(id)\n\n  if (isTRUE(title)) {\n    title <- tags$h4(\n      i18n(\"Copy & paste data\"),\n      class = \"datamods-title\"\n    )\n  }\n\n  tags$div(\n    class = \"datamods-import\",\n    html_dependency_datamods(),\n    title,\n    tagAppendAttributes(\n      textAreaInput(\n        inputId = ns(\"data_pasted\"),\n        label = i18n(\"Paste data here:\"),\n        height = \"300px\",\n        width = \"100%\",\n        resize = \"none\"\n      ),\n      class = \"shiny-input-container-inline\"\n    ),\n   if (isTRUE(name_field)) {\n     textInput(\n       inputId = ns(\"name\"),\n       label = NULL,\n       placeholder = i18n(\"Add a label to data\"),\n       width = \"100%\"\n     )\n   },\n    tags$div(\n      id = ns(\"import-placeholder\"),\n      alert(\n        id = ns(\"import-result\"),\n        status = \"info\",\n        tags$b(i18n(\"Nothing pasted yet!\")),\n        i18n(\"Please copy and paste some data in the dialog box above.\"),\n        dismissible = TRUE\n      )\n    ),\n    uiOutput(\n      outputId = ns(\"container_valid_btn\"),\n      style = \"margin-top: 20px;\"\n    )\n  )\n}\n\n\n#' @inheritParams import_globalenv_server\n#' @param fread_args `list` of additional arguments to pass to [data.table::fread()] when reading data.\n#'\n#' @export\n#'\n#' @importFrom shiny moduleServer\n#' @importFrom data.table fread\n#' @importFrom shiny reactiveValues observeEvent removeUI reactive\n#' @importFrom htmltools tags tagList\n#' @importFrom rlang %||%\n#'\n#' @rdname import-copypaste\nimport_copypaste_server <- function(id,\n                                    btn_show_data = TRUE,\n                                    show_data_in = c(\"popup\", \"modal\"),\n                                    trigger_return = c(\"button\", \"change\"),\n                                    return_class = c(\"data.frame\", \"data.table\", \"tbl_df\", \"raw\"),\n                                    reset = reactive(NULL),\n                                    fread_args = list()) {\n\n  trigger_return <- match.arg(trigger_return)\n  return_class <- match.arg(return_class)\n\n  module <- function(input, output, session) {\n\n    ns <- session$ns\n    imported_rv <- reactiveValues(data = NULL, name = NULL)\n    temporary_rv <- reactiveValues(data = NULL, name = NULL, status = NULL)\n\n    observeEvent(reset(), {\n      temporary_rv$data <- NULL\n      temporary_rv$name <- NULL\n      temporary_rv$status <- NULL\n    })\n\n    output$container_valid_btn <- renderUI({\n      if (identical(trigger_return, \"button\")) {\n        button_import()\n      }\n    })\n\n    observeEvent(input$data_pasted, {\n      req(input$data_pasted)\n      fread_args$tex <- input$data_pasted\n      imported <- try(rlang::exec(data.table::fread, !!!fread_args), silent = TRUE)\n\n      if (inherits(imported, \"try-error\") || NROW(imported) < 1) {\n        toggle_widget(inputId = \"confirm\", enable = FALSE)\n        insert_error(mssg = i18n(attr(imported, \"condition\")$message))\n        temporary_rv$status <- \"error\"\n        temporary_rv$data <- NULL\n        temporary_rv$name <- NULL\n      } else {\n        toggle_widget(inputId = \"confirm\", enable = TRUE)\n        insert_alert(\n          selector = ns(\"import\"),\n          status = \"success\",\n          make_success_alert(\n            imported,\n            trigger_return = trigger_return,\n            btn_show_data = btn_show_data\n          )\n        )\n        temporary_rv$status <- \"success\"\n        temporary_rv$data <- imported\n      }\n    }, ignoreInit = TRUE)\n\n    observeEvent(input$name, {\n      temporary_rv$name <- if (isTruthy(input$name)) {\n        input$name\n      } else {\n        \"clipboard_data\"\n      }\n    })\n\n    observeEvent(input$see_data, {\n      show_data(temporary_rv$data, title = i18n(\"Imported data\"), type = show_data_in)\n    })\n\n    observeEvent(input$confirm, {\n      imported_rv$data <- temporary_rv$data\n      imported_rv$name <- temporary_rv$name\n    })\n\n\n    if (identical(trigger_return, \"button\")) {\n      return(list(\n        status = reactive(temporary_rv$status),\n        name = reactive(imported_rv$name),\n        data = reactive(as_out(imported_rv$data, return_class))\n      ))\n    } else {\n      return(list(\n        status = reactive(temporary_rv$status),\n        name = reactive(temporary_rv$name),\n        data = reactive(as_out(temporary_rv$data, return_class))\n      ))\n    }\n  }\n\n  moduleServer(\n    id = id,\n    module = module\n  )\n}\n\n\n\n"
  },
  {
    "path": "R/import-file.R",
    "content": "\n#' @title Import data from a file\n#'\n#' @description Let user upload a file and import data\n#'\n#' @inheritParams import-globalenv\n#' @param preview_data Show or not a preview of the data under the file input.\n#' @param file_extensions File extensions accepted by [shiny::fileInput()], can also be MIME type.\n#' @param layout_params How to display import parameters : in a dropdown button or inline below file input.\n#'\n#' @template module-import\n#'\n#' @export\n#'\n#' @name import-file\n#'\n#' @importFrom shiny NS fileInput actionButton icon\n#' @importFrom htmltools tags tagAppendAttributes css tagAppendChild\n#' @importFrom shinyWidgets pickerInput numericInputIcon textInputIcon dropMenu\n#' @importFrom phosphoricons ph\n#' @importFrom toastui datagridOutput2\n#'\n#' @example examples/from-file.R\nimport_file_ui <- function(id,\n                           title = TRUE,\n                           preview_data = TRUE,\n                           file_extensions = c(\".csv\", \".txt\", \".xls\", \".xlsx\", \".rds\", \".fst\", \".sas7bdat\", \".sav\"),\n                           layout_params = c(\"dropdown\", \"inline\")) {\n\n  ns <- NS(id)\n\n  if (!is.null(layout_params)) {\n    layout_params <- match.arg(layout_params)\n  }\n\n  if (isTRUE(title)) {\n    title <- tags$h4(\n      i18n(\"Import a file\"),\n      class = \"datamods-title\"\n    )\n  }\n\n\n  params_ui <- fluidRow(\n    column(\n      width = 6,\n      numericInputIcon(\n        inputId = ns(\"skip_rows\"),\n        label = i18n(\"Rows to skip before reading data:\"),\n        value = 0,\n        min = 0,\n        icon = list(\"n =\"),\n        size = \"sm\",\n        width = \"100%\"\n      ),\n      tagAppendChild(\n        textInputIcon(\n          inputId = ns(\"na_label\"),\n          label = i18n(\"Missing values character(s):\"),\n          value = \",NA\",\n          icon = list(\"NA\"),\n          size = \"sm\",\n          width = \"100%\"\n        ),\n        shiny::helpText(ph(\"info\"), i18n(\"if several use a comma (',') to separate them\"))\n      )\n    ),\n    column(\n      width = 6,\n      textInputIcon(\n        inputId = ns(\"dec\"),\n        label = i18n(\"Decimal separator:\"),\n        value = \".\",\n        icon = list(\"0.00\"),\n        size = \"sm\",\n        width = \"100%\"\n      ),\n      textInputIcon(\n        inputId = ns(\"encoding\"),\n        label = i18n(\"Encoding:\"),\n        value = \"UTF-8\",\n        icon = phosphoricons::ph(\"text-aa\"),\n        size = \"sm\",\n        width = \"100%\"\n      )\n    )\n  )\n\n  file_ui <- tagAppendAttributes(\n    fileInput(\n      inputId = ns(\"file\"),\n      label = i18n(\"Upload a file:\"),\n      buttonLabel = i18n(\"Browse...\"),\n      placeholder = i18n(\"No file selected\"),\n      accept = file_extensions,\n      width = \"100%\"\n    ),\n    class = \"mb-0\"\n  )\n  if (identical(layout_params, \"dropdown\")) {\n    file_ui <- tags$div(\n      style = css(\n        display = \"grid\",\n        gridTemplateColumns = \"1fr 50px\",\n        gridColumnGap = \"10px\"\n      ),\n      file_ui,\n      tags$div(\n        class = \"shiny-input-container\",\n        tags$label(\n          class = \"control-label\",\n          `for` = ns(\"dropdown_params\"),\n          \"...\",\n          style = css(visibility = \"hidden\")\n        ),\n        shinyWidgets::dropMenu(\n          actionButton(\n            inputId = ns(\"dropdown_params\"),\n            label = ph(\"gear\", title = \"Parameters\"),\n            width = \"50px\",\n            class = \"px-1\"\n          ),\n          params_ui\n        )\n      )\n    )\n  }\n  tags$div(\n    class = \"datamods-import\",\n    html_dependency_datamods(),\n    shinyWidgets::html_dependency_winbox(),\n    title,\n    file_ui,\n    if (identical(layout_params, \"inline\")) params_ui,\n    tags$div(\n      class = \"hidden\",\n      id = ns(\"sheet-container\"),\n      pickerInput(\n        inputId = ns(\"sheet\"),\n        label = i18n(\"Select sheet to import:\"),\n        choices = NULL,\n        width = \"100%\"\n      )\n    ),\n    tags$div(\n      id = ns(\"import-placeholder\"),\n      alert(\n        id = ns(\"import-result\"),\n        status = \"info\",\n        tags$b(i18n(\"No file selected:\")),\n        sprintf(i18n(\"You can import %s files\"), paste(file_extensions, collapse = \", \")),\n        dismissible = TRUE\n      )\n    ),\n    if (isTRUE(preview_data)) {\n      datagridOutput2(outputId = ns(\"table\"))\n    },\n    uiOutput(\n      outputId = ns(\"container_confirm_btn\"),\n      style = \"margin-top: 20px;\"\n    ),\n    tags$div(\n      style = css(display = \"none\"),\n      checkboxInput(\n        inputId = ns(\"preview_data\"),\n        label = NULL,\n        value = isTRUE(preview_data)\n      )\n    )\n  )\n}\n\n\n#' @inheritParams import_globalenv_server\n#' @param read_fns Named list with custom function(s) to read data:\n#'  * the name must be the extension of the files to which the function will be applied\n#'  * the value must be a function that can have 5 arguments (you can ignore some of them, but you have to use the same names),\n#'    passed by user through the interface:\n#'    + `file`: path to the file\n#'    + `sheet`: for Excel files, sheet to read\n#'    + `skip`: number of row to skip\n#'    + `dec`: decimal separator\n#'    + `encoding`: file encoding\n#'    + `na.strings`: character(s) to interpret as missing values.\n#'\n#' @export\n#'\n#' @importFrom shiny moduleServer\n#' @importFrom htmltools tags tagList\n#' @importFrom shiny reactiveValues reactive observeEvent removeUI req\n#' @importFrom shinyWidgets updatePickerInput\n#' @importFrom readxl excel_sheets\n#' @importFrom rio import\n#' @importFrom rlang exec fn_fmls_names is_named is_function\n#' @importFrom tools file_ext\n#' @importFrom utils head\n#' @importFrom toastui renderDatagrid2 datagrid\n#'\n#' @rdname import-file\nimport_file_server <- function(id,\n                               btn_show_data = TRUE,\n                               show_data_in = \"winbox\",\n                               trigger_return = c(\"button\", \"change\"),\n                               return_class = c(\"data.frame\", \"data.table\", \"tbl_df\", \"raw\"),\n                               reset = reactive(NULL),\n                               read_fns = list()) {\n\n  if (length(read_fns) > 0) {\n    if (!is_named(read_fns))\n      stop(\"import_file_server: `read_fns` must be a named list.\", call. = FALSE)\n    if (!all(vapply(read_fns, is_function, logical(1))))\n      stop(\"import_file_server: `read_fns` must be list of function(s).\", call. = FALSE)\n  }\n\n  trigger_return <- match.arg(trigger_return)\n  return_class <- match.arg(return_class)\n\n  module <- function(input, output, session) {\n\n    ns <- session$ns\n    imported_rv <- reactiveValues(data = NULL, name = NULL)\n    temporary_rv <- reactiveValues(data = NULL, name = NULL, status = NULL)\n\n    observeEvent(reset(), {\n      temporary_rv$data <- NULL\n      temporary_rv$name <- NULL\n      temporary_rv$status <- NULL\n    })\n\n    output$container_confirm_btn <- renderUI({\n      if (identical(trigger_return, \"button\")) {\n        button_import()\n      }\n    })\n\n    observeEvent(input$file, {\n      if (isTRUE(is_excel(input$file$datapath))) {\n        updatePickerInput(\n          session = session,\n          inputId = \"sheet\",\n          choices = readxl::excel_sheets(input$file$datapath)\n        )\n        showUI(paste0(\"#\", ns(\"sheet-container\")))\n      } else {\n        hideUI(paste0(\"#\", ns(\"sheet-container\")))\n      }\n    })\n\n    observeEvent(list(\n      input$file,\n      input$sheet,\n      input$skip_rows,\n      input$dec,\n      input$encoding,\n      input$na_label\n    ), {\n      req(input$file)\n      # req(input$skip_rows)\n      extension <- tools::file_ext(input$file$datapath)\n      if (isTRUE(extension %in% names(read_fns))) {\n        parameters <- list(\n          file = input$file$datapath,\n          sheet = input$sheet,\n          skip = input$skip_rows,\n          dec = input$dec,\n          encoding = input$encoding,\n          na.strings = split_char(input$na_label)\n        )\n        parameters <- parameters[which(names(parameters) %in% fn_fmls_names(read_fns[[extension]]))]\n        imported <- try(rlang::exec(read_fns[[extension]], !!!parameters), silent = TRUE)\n        code <- call2(read_fns[[extension]], !!!modifyList(parameters, list(file = input$file$name)))\n      } else {\n        if (is_excel(input$file$datapath)) {\n          req(input$sheet)\n          parameters <- list(\n            file = input$file$datapath,\n            which = input$sheet,\n            skip = input$skip_rows,\n            na = split_char(input$na_label)\n          )\n        } else if (is_sas(input$file$datapath)) {\n          parameters <- list(\n            file = input$file$datapath,\n            skip = input$skip_rows,\n            encoding = input$encoding\n          )\n        } else {\n          parameters <- list(\n            file = input$file$datapath,\n            skip = input$skip_rows,\n            dec = input$dec,\n            encoding = input$encoding,\n            na.strings = split_char(input$na_label)\n          )\n        }\n        imported <- try(rlang::exec(rio::import, !!!parameters), silent = TRUE)\n        code <- call2(\"import\", !!!modifyList(parameters, list(file = input$file$name)), .ns = \"rio\")\n      }\n\n      if (inherits(imported, \"try-error\")) {\n        imported <- try(rlang::exec(rio::import, !!!parameters[1]), silent = TRUE)\n        code <- call2(\"import\", !!!list(file = input$file$name), .ns = \"rio\")\n      }\n\n      if (inherits(imported, \"try-error\") || NROW(imported) < 1) {\n\n        toggle_widget(inputId = \"confirm\", enable = FALSE)\n        insert_error(mssg = i18n(attr(imported, \"condition\")$message))\n        temporary_rv$status <- \"error\"\n        temporary_rv$data <- NULL\n        temporary_rv$name <- NULL\n        temporary_rv$code <- NULL\n\n      } else {\n\n        toggle_widget(inputId = \"confirm\", enable = TRUE)\n\n        insert_alert(\n          selector = ns(\"import\"),\n          status = \"success\",\n          make_success_alert(\n            imported,\n            trigger_return = trigger_return,\n            btn_show_data = btn_show_data,\n            extra = if (isTRUE(input$preview_data)) i18n(\"First five rows are shown below:\")\n          )\n        )\n        temporary_rv$status <- \"success\"\n        temporary_rv$data <- imported\n        temporary_rv$name <- input$file$name\n        temporary_rv$code <- code\n      }\n    }, ignoreInit = TRUE)\n\n    observeEvent(input$see_data, {\n      show_data(temporary_rv$data, title = i18n(\"Imported data\"), type = show_data_in)\n    })\n\n    output$table <- renderDatagrid2({\n      req(temporary_rv$data)\n      datagrid(\n        data = head(temporary_rv$data, 5),\n        theme = \"striped\",\n        colwidths = \"guess\",\n        minBodyHeight = 250\n      )\n    })\n\n    observeEvent(input$confirm, {\n      imported_rv$data <- temporary_rv$data\n      imported_rv$name <- temporary_rv$name\n      imported_rv$code <- temporary_rv$code\n    })\n\n    if (identical(trigger_return, \"button\")) {\n      return(list(\n        status = reactive(temporary_rv$status),\n        name = reactive(imported_rv$name),\n        code = reactive(imported_rv$code),\n        data = reactive(as_out(imported_rv$data, return_class))\n      ))\n    } else {\n      return(list(\n        status = reactive(temporary_rv$status),\n        name = reactive(temporary_rv$name),\n        code = reactive(temporary_rv$code),\n        data = reactive(as_out(temporary_rv$data, return_class))\n      ))\n    }\n  }\n\n  moduleServer(\n    id = id,\n    module = module\n  )\n}\n\n# utils -------------------------------------------------------------------\n\nis_excel <- function(path) {\n  isTRUE(tools::file_ext(path) %in% c(\"xls\", \"xlsx\"))\n}\n\nis_sas <- function(path) {\n  isTRUE(tools::file_ext(path) %in% c(\"sas7bdat\"))\n}\n\n"
  },
  {
    "path": "R/import-globalenv.R",
    "content": "\n#' @title Import data from an Environment\n#'\n#' @description Let the user select a dataset from its own environment or from a package's environment.\n#'\n#' @param id Module's ID.\n#' @param globalenv Search for data in Global environment.\n#' @param packages Name of packages in which to search data.\n#' @param title Module's title, if `TRUE` use the default title,\n#'  use `NULL` for no title or a `shiny.tag` for a custom one.\n#'\n#' @template module-import\n#'\n#' @export\n#'\n#' @name import-globalenv\n#'\n#' @importFrom htmltools tags\n#' @importFrom shiny NS actionButton icon textInput\n#' @importFrom shinyWidgets pickerInput alert\n#'\n#' @example examples/from-globalenv.R\nimport_globalenv_ui <- function(id,\n                                globalenv = TRUE,\n                                packages = get_data_packages(),\n                                title = TRUE) {\n\n  ns <- NS(id)\n\n  choices <- list()\n  if (isTRUE(globalenv)) {\n    choices <- append(choices, \"Global Environment\")\n  }\n  if (!is.null(packages)) {\n    choices <- append(choices, list(Packages = as.character(packages)))\n  }\n\n  if (isTRUE(globalenv)) {\n    selected <- \"Global Environment\"\n  } else {\n    selected <- packages[1]\n  }\n\n  if (isTRUE(title)) {\n    title <- tags$h4(\n      i18n(\"Import a dataset from an environment\"),\n      class = \"datamods-title\"\n    )\n  }\n\n  tags$div(\n    class = \"datamods-import\",\n    html_dependency_datamods(),\n    title,\n    pickerInput(\n      inputId = ns(\"data\"),\n      label = i18n(\"Select a data.frame:\"),\n      choices = NULL,\n      options = list(title = i18n(\"List of data.frame...\")),\n      width = \"100%\"\n    ),\n    pickerInput(\n      inputId = ns(\"env\"),\n      label = i18n(\"Select an environment in which to search:\"),\n      choices = choices,\n      selected = selected,\n      width = \"100%\",\n      options = list(\n        \"title\" = i18n(\"Select environment\"),\n        \"live-search\" = TRUE,\n        \"size\" = 10\n      )\n    ),\n\n    tags$div(\n      id = ns(\"import-placeholder\"),\n      alert(\n        id = ns(\"import-result\"),\n        status = \"info\",\n        tags$b(i18n(\"No data selected!\")),\n        i18n(\"Use a data.frame from your environment or from the environment of a package.\"),\n        dismissible = TRUE\n      )\n    ),\n    uiOutput(\n      outputId = ns(\"container_valid_btn\"),\n      style = \"margin-top: 20px;\"\n    )\n  )\n}\n\n\n\n#' @param btn_show_data Display or not a button to display data in a modal window if import is successful.\n#' @param show_data_in Where to display data: in a `\"popup\"` or in a `\"modal\"` window.\n#' @param trigger_return When to update selected data:\n#'  `\"button\"` (when user click on button) or\n#'  `\"change\"` (each time user select a dataset in the list).\n#' @param return_class Class of returned data: `data.frame`, `data.table`, `tbl_df` (tibble) or `raw`.\n#' @param reset A `reactive` function that when triggered resets the data.\n#'\n#' @export\n#'\n#' @importFrom shiny moduleServer reactiveValues observeEvent reactive removeUI is.reactive icon actionLink isTruthy\n#' @importFrom htmltools tags tagList\n#' @importFrom shinyWidgets updatePickerInput\n#'\n#' @rdname import-globalenv\nimport_globalenv_server <- function(id,\n                                    btn_show_data = TRUE,\n                                    show_data_in = c(\"popup\", \"modal\"),\n                                    trigger_return = c(\"button\", \"change\"),\n                                    return_class = c(\"data.frame\", \"data.table\", \"tbl_df\", \"raw\"),\n                                    reset = reactive(NULL)) {\n\n  trigger_return <- match.arg(trigger_return)\n  return_class <- match.arg(return_class)\n\n  module <- function(input, output, session) {\n\n    ns <- session$ns\n    imported_rv <- reactiveValues(data = NULL, name = NULL)\n    temporary_rv <- reactiveValues(data = NULL, name = NULL, status = NULL)\n\n    observeEvent(reset(), {\n      temporary_rv$data <- NULL\n      temporary_rv$name <- NULL\n      temporary_rv$status <- NULL\n    })\n\n    output$container_valid_btn <- renderUI({\n      if (identical(trigger_return, \"button\")) {\n        button_import()\n      }\n    })\n\n    observeEvent(input$env, {\n      if (identical(input$env, \"Global Environment\")) {\n        choices <- search_obj(\"data.frame\")\n      } else {\n        choices <- list_pkg_data(input$env)\n      }\n      if (is.null(choices)) {\n        choices <- i18n(\"No data.frame here...\")\n        choicesOpt <- list(disabled = TRUE)\n      } else {\n        choicesOpt <- list(\n          subtext = get_dimensions(choices)\n        )\n      }\n      temporary_rv$package <- attr(choices, \"package\")\n      updatePickerInput(\n        session = session,\n        inputId = \"data\",\n        choices = choices,\n        choicesOpt = choicesOpt\n      )\n    })\n\n\n    observeEvent(input$trigger, {\n      if (identical(trigger_return, \"change\")) {\n        hideUI(selector = paste0(\"#\", ns(\"container_valid_btn\")))\n      }\n    })\n\n\n    observeEvent(input$data, {\n      if (!isTruthy(input$data)) {\n        toggle_widget(inputId = \"confirm\", enable = FALSE)\n        insert_alert(\n          selector = ns(\"import\"),\n          status = \"info\",\n          tags$b(i18n(\"No data selected!\")),\n          i18n(\"Use a data.frame from your environment or from the environment of a package.\")\n        )\n      } else {\n        name_df <- input$data\n\n        if (!is.null(temporary_rv$package)) {\n          attr(name_df, \"package\") <- temporary_rv$package\n        }\n\n        imported <- try(get_env_data(name_df), silent = TRUE)\n\n        if (inherits(imported, \"try-error\") || NROW(imported) < 1) {\n          toggle_widget(inputId = \"confirm\", enable = FALSE)\n          insert_error(mssg = i18n(attr(imported, \"condition\")$message))\n          temporary_rv$status <- \"error\"\n          temporary_rv$data <- NULL\n          temporary_rv$name <- NULL\n        } else {\n          toggle_widget(inputId = \"confirm\", enable = TRUE)\n          insert_alert(\n            selector = ns(\"import\"),\n            status = \"success\",\n            make_success_alert(\n              imported,\n              trigger_return = trigger_return,\n              btn_show_data = btn_show_data\n            )\n          )\n          pkg <- attr(name_df, \"package\")\n          if (!is.null(pkg)) {\n            name <- paste(pkg, input$data, sep = \"::\")\n          } else {\n            name <- input$data\n          }\n          name <- trimws(sub(\"\\\\(([^\\\\)]+)\\\\)\", \"\", name))\n          temporary_rv$status <- \"success\"\n          temporary_rv$data <- imported\n          temporary_rv$name <- name\n        }\n      }\n    }, ignoreInit = TRUE, ignoreNULL = FALSE)\n\n\n    observeEvent(input$see_data, {\n      show_data(temporary_rv$data, title = i18n(\"Imported data\"), type = show_data_in)\n    })\n\n    observeEvent(input$confirm, {\n      imported_rv$data <- temporary_rv$data\n      imported_rv$name <- temporary_rv$name\n    })\n\n\n    if (identical(trigger_return, \"button\")) {\n      return(list(\n        status = reactive(temporary_rv$status),\n        name = reactive(imported_rv$name),\n        data = reactive(as_out(imported_rv$data, return_class))\n      ))\n    } else {\n      return(list(\n        status = reactive(temporary_rv$status),\n        name = reactive(temporary_rv$name),\n        data = reactive(as_out(temporary_rv$data, return_class))\n      ))\n    }\n  }\n\n  moduleServer(\n    id = id,\n    module = module\n  )\n}\n\n\n\n\n\n\n\n# utils -------------------------------------------------------------------\n\n\n#' Get packages containing datasets\n#'\n#' @return a character vector of packages names\n#' @export\n#'\n#' @importFrom utils data\n#'\n#' @examples\n#' if (interactive()) {\n#'\n#'   get_data_packages()\n#'\n#' }\nget_data_packages <- function() {\n  suppressWarnings({\n    pkgs <- data(package = .packages(all.available = TRUE))\n  })\n  unique(pkgs$results[, 1])\n}\n\n\n#' List dataset contained in a package\n#'\n#' @param pkg Name of the package, must be installed.\n#'\n#' @return a \\code{character} vector or \\code{NULL}.\n#' @export\n#'\n#' @importFrom utils data\n#'\n#' @examples\n#'\n#' list_pkg_data(\"ggplot2\")\nlist_pkg_data <- function(pkg) {\n  if (isTRUE(requireNamespace(pkg, quietly = TRUE))) {\n    list_data <- data(package = pkg, envir = environment())$results[, \"Item\"]\n    list_data <- sort(list_data)\n    attr(list_data, \"package\") <- pkg\n    if (length(list_data) < 1) {\n      NULL\n    } else {\n      unname(list_data)\n    }\n  } else {\n    NULL\n  }\n}\n\n#' @importFrom utils data\nget_env_data <- function(obj, env = globalenv()) {\n  pkg <- attr(obj, \"package\")\n  re <- regexpr(pattern = \"\\\\(([^\\\\)]+)\\\\)\", text = obj)\n  obj_ <- substr(x = obj, start = re + 1, stop = re + attr(re, \"match.length\") - 2)\n  obj <- gsub(pattern = \"\\\\s.*\", replacement = \"\", x = obj)\n  if (obj %in% ls(name = env)) {\n    get(x = obj, envir = env)\n  } else if (!is.null(pkg) && !identical(pkg, \"\")) {\n    res <- suppressWarnings(try(\n      get(utils::data(list = obj, package = pkg, envir = environment())), silent = TRUE\n    ))\n    if (!inherits(res, \"try-error\"))\n      return(res)\n    data(list = obj_, package = pkg, envir = environment())\n    get(obj, envir = environment())\n  } else {\n    NULL\n  }\n}\n\n\nget_dimensions <- function(objs) {\n  if (is.null(objs))\n    return(NULL)\n  dataframes_dims <- Map(\n    f = function(name, pkg) {\n      attr(name, \"package\") <- pkg\n      tmp <- suppressWarnings(get_env_data(name))\n      if (is.data.frame(tmp)) {\n        sprintf(\"%d obs. of  %d variables\", nrow(tmp), ncol(tmp))\n      } else {\n        i18n(\"Not a data.frame\")\n      }\n    },\n    name = objs,\n    pkg = if (!is.null(attr(objs, \"package\"))) {\n      attr(objs, \"package\")\n    } else {\n      character(1)\n    }\n  )\n  unlist(dataframes_dims)\n}\n"
  },
  {
    "path": "R/import-googlesheets.R",
    "content": "\n#' @title Import data from Googlesheet\n#'\n#' @description Let user paste link to a Google sheet then import the data.\n#'\n#' @inheritParams import-globalenv\n#'\n#' @template module-import\n#'\n#' @export\n#' @name import-googlesheets\n#'\n#' @importFrom shiny NS actionLink\n#' @importFrom shinyWidgets textInputIcon\n#' @importFrom htmltools tags tagList\n#'\n#' @example examples/from-googlesheets.R\nimport_googlesheets_ui <- function(id, title = TRUE) {\n\n  ns <- NS(id)\n\n  if (isTRUE(title)) {\n    title <- tags$h4(\n      i18n(\"Import Google Spreadsheet\"),\n      class = \"datamods-title\"\n    )\n  }\n\n  tags$div(\n    class = \"datamods-import\",\n    html_dependency_datamods(),\n    title,\n    tags$div(\n      class = \"pull-right float-right\",\n      help_popup(tagList(\n        i18n(\"You can either use:\"),\n        tags$ul(\n          tags$li(\n            i18n(\"A shareable link, in that case first sheet will be read\")\n          ),\n          tags$li(\n            i18n(\"The URL that appear in your browser, in that case the current sheet will be read\")\n          )\n        )\n      ))\n    ),\n    textInputIcon(\n      inputId = ns(\"link\"),\n      label = i18n(\"Enter a shareable link to a GoogleSheet:\"),\n      icon = phosphoricons::ph(\"link\"),\n      width = \"100%\"\n    ),\n    tags$div(\n      id = ns(\"import-placeholder\"),\n      alert(\n        id = ns(\"import-result\"),\n        status = \"info\",\n        tags$b(i18n(\"Nothing pasted yet!\")),\n        i18n(\"Please paste a valid GoogleSheet link in the dialog box above.\"),\n        dismissible = TRUE\n      )\n    ),\n    uiOutput(\n      outputId = ns(\"container_confirm_btn\"),\n      style = \"margin-top: 20px;\"\n    )\n  )\n}\n\n\n#' @inheritParams import_globalenv_server\n#'\n#' @export\n#'\n#' @importFrom shiny moduleServer\n#' @importFrom shiny reactiveValues observeEvent removeUI reactive req\n#' @importFrom htmltools tags tagList\n#'\n#' @rdname import-googlesheets\nimport_googlesheets_server <- function(id,\n                                       btn_show_data = TRUE,\n                                       show_data_in = c(\"popup\", \"modal\"),\n                                       trigger_return = c(\"button\", \"change\"),\n                                       return_class = c(\"data.frame\", \"data.table\", \"tbl_df\", \"raw\"),\n                                       reset = reactive(NULL)) {\n\n  trigger_return <- match.arg(trigger_return)\n  return_class <- match.arg(return_class)\n\n  module <- function(input, output, session) {\n\n    ns <- session$ns\n    imported_rv <- reactiveValues(data = NULL, name = NULL)\n    temporary_rv <- reactiveValues(data = NULL, name = NULL, status = NULL)\n\n    observeEvent(reset(), {\n      temporary_rv$data <- NULL\n      temporary_rv$name <- NULL\n      temporary_rv$status <- NULL\n    })\n\n    output$container_confirm_btn <- renderUI({\n      if (identical(trigger_return, \"button\")) {\n        button_import()\n      }\n    })\n\n    observeEvent(input$trigger, {\n      if (identical(trigger_return, \"change\")) {\n        hideUI(selector = paste0(\"#\", ns(\"confirm-button\")))\n      }\n    })\n\n    observeEvent(input$link, {\n      req(input$link)\n      imported <- try(read_gsheet(input$link), silent = TRUE)\n      if (inherits(imported, \"try-error\") || NROW(imported) < 1) {\n        toggle_widget(inputId = \"confirm\", enable = FALSE)\n        insert_error(mssg = i18n(attr(imported, \"condition\")$message))\n        temporary_rv$status <- \"error\"\n        temporary_rv$data <- NULL\n      } else {\n        toggle_widget(inputId = \"confirm\", enable = TRUE)\n        insert_alert(\n          selector = ns(\"import\"),\n          status = \"success\",\n          make_success_alert(\n            imported,\n            trigger_return = trigger_return,\n            btn_show_data = btn_show_data\n          )\n        )\n        temporary_rv$status <- \"success\"\n        temporary_rv$data <- imported\n      }\n    }, ignoreInit = TRUE)\n\n    observeEvent(input$see_data, {\n      show_data(temporary_rv$data, title = i18n(\"Imported data\"), type = show_data_in)\n    })\n\n    observeEvent(input$confirm, {\n      imported_rv$data <- temporary_rv$data\n    })\n\n    if (identical(trigger_return, \"button\")) {\n      return(list(\n        status = reactive(temporary_rv$status),\n        name = reactive(imported_rv$name),\n        data = reactive(as_out(imported_rv$data, return_class))\n      ))\n    } else {\n      return(list(\n        status = reactive(temporary_rv$status),\n        name = reactive(temporary_rv$name),\n        data = reactive(as_out(temporary_rv$data, return_class))\n      ))\n    }\n  }\n\n  moduleServer(\n    id = id,\n    module = module\n  )\n}\n\n\n\n# Utils -------------------------------------------------------------------\n\nget_id <- function(x) {\n  if (grepl(\"/d/\", x)) {\n    x <- strsplit(x = x, split = \"/\")\n    x <- unlist(x)\n    x[which(x == \"d\") + 1]\n  } else if (grepl(\"id=\", x)) {\n    x <- regmatches(x, gregexpr(\"id=[[:alnum:]_-]+\", x))\n    gsub(\"^id=\", \"\", x[[1]])\n  } else {\n    stop(\"Failed to retrieve Googlesheet ID\")\n  }\n}\n\n#' @importFrom data.table fread .SD\n#' @importFrom utils type.convert\nread_gsheet <- function(url, dec = NULL) {\n  url_ <- sprintf(\n    \"https://docs.google.com/spreadsheets/export?id=%s&format=csv\",\n    get_id(url)\n  )\n  if (grepl(\"gid=\", url)) {\n    gid <- regmatches(url, gregexpr(\"gid=[0-9]+\", url))\n    url_ <- paste0(url_, \"&\", gid[[1]])\n  }\n  dt <- fread(input = url_)\n  if (!is.null(dec)) {\n    dt <- dt[, lapply(.SD, type.convert, dec = dec)]\n  }\n  return(dt)\n}\n\n"
  },
  {
    "path": "R/import-modal.R",
    "content": "\n#' @title Import from all sources\n#'\n#' @description Wrap all import modules into one, can be displayed inline or in a modal window..\n#'\n#' @param id Module's id\n#' @param from The import_ui & server to use, i.e. the method.\n#'   There are 5 options to choose from. (\"env\", \"file\", \"copypaste\", \"googlesheets\", \"url\")\n#' @inheritParams import-file\n#'\n#' @template module-import\n#'\n#' @export\n#' @name import-modal\n#'\n#' @importFrom shiny NS tabsetPanel tabPanel tabPanelBody icon fluidRow column\n#' @importFrom htmltools tags HTML\n#' @importFrom shinyWidgets radioGroupButtons\n#'\n#' @example examples/modal.R\n#'\nimport_ui <- function(id,\n                      from = c(\"env\", \"file\", \"copypaste\", \"googlesheets\", \"url\"),\n                      file_extensions = c(\".csv\", \".txt\", \".xls\", \".xlsx\", \".rds\", \".fst\", \".sas7bdat\", \".sav\")) {\n  ns <- NS(id)\n  from <- match.arg(from, several.ok = TRUE)\n\n  env <- if (\"env\" %in% from) {\n    tabPanelBody(\n      value = \"env\",\n      tags$br(),\n      import_globalenv_ui(id = ns(\"env\"), title = NULL)\n    )\n  }\n\n  file <- if (\"file\" %in% from) {\n    tabPanelBody(\n      value = \"file\",\n      tags$br(),\n      import_file_ui(id = ns(\"file\"), title = NULL, file_extensions = file_extensions)\n    )\n  }\n\n  copypaste <- if (\"copypaste\" %in% from) {\n    tabPanelBody(\n      value = \"copypaste\",\n      tags$br(),\n      import_copypaste_ui(id = ns(\"copypaste\"), title = NULL)\n    )\n  }\n\n  googlesheets <- if (\"googlesheets\" %in% from) {\n    tabPanelBody(\n      value = \"googlesheets\",\n      tags$br(),\n      import_googlesheets_ui(id = ns(\"googlesheets\"), title = NULL)\n    )\n  }\n\n  url <- if (\"url\" %in% from) {\n    tabPanelBody(\n      value = \"url\",\n      tags$br(),\n      import_url_ui(id = ns(\"url\"), title = NULL)\n    )\n  }\n\n  #database <- if(\"database\" %in% from) tabPanel(\"Database\", import_database_ui(ns(\"database\")))\n\n  labsImport <- list(\n    \"env\" = i18n(\"Environment\"),\n    \"file\" = i18n(\"External file\"),\n    \"copypaste\" = i18n(\"Copy / Paste\"),\n    \"googlesheets\" = i18n(\"Googlesheets\"),\n    \"url\" = i18n(\"URL\")\n  )\n  iconsImport <- list(\n    \"env\" = phosphoricons::ph(\"code\", title = labsImport$env),\n    \"file\" = phosphoricons::ph(\"file-arrow-down\", title = labsImport$file),\n    \"copypaste\" = phosphoricons::ph(\"clipboard-text\", title = labsImport$copypaste),\n    \"googlesheets\" = phosphoricons::ph(\"cloud-arrow-down\", title = labsImport$googlesheets),\n    \"url\" = phosphoricons::ph(\"link\", title = labsImport$url)\n  )\n\n\n  if (identical(length(from), 1L)) {\n    importTab <- switch(\n      from,\n      \"env\" = import_globalenv_ui(id = ns(\"env\")),\n      \"file\" = import_file_ui(id = ns(\"file\"), file_extensions = file_extensions),\n      \"copypaste\" = import_copypaste_ui(id = ns(\"copypaste\")),\n      \"googlesheets\" = import_googlesheets_ui(id = ns(\"googlesheets\")),\n      \"url\" = import_url_ui(id = ns(\"url\")),\n    )\n  } else {\n    tabsetPanelArgs <- dropNulls(list(\n      env, file, copypaste, googlesheets, url,\n      id = ns(\"tabs-import\"),\n      type = \"hidden\"\n    ))\n    importTab <- do.call(\n      what = tabsetPanel,\n      args = tabsetPanelArgs\n    )\n    importTab <- fluidRow(\n      column(\n        width = 3,\n        tags$br(),\n        tags$style(\n          HTML(sprintf(\"#%s>.btn-group-vertical {width: 100%%;}\", ns(\"from\"))),\n          HTML(sprintf(\".btn-group-vertical>.btn-group>.btn {text-align: left;}\"))\n        ),\n        radioGroupButtons(\n          inputId = ns(\"from\"),\n          label = i18n(\"How to import data?\"),\n          choiceValues = from,\n          choiceNames = lapply(\n            X = from,\n            FUN = function(x) {\n              tagList(iconsImport[[x]], labsImport[[x]])\n            }\n          ),\n          direction = \"vertical\",\n          width = \"100%\"\n        )\n      ),\n      column(\n        width = 9, importTab\n      )\n    )\n  }\n\n  tags$div(\n    class = \"datamods-imports\",\n    html_dependency_datamods(),\n    tags$style(\".tui-grid-cell-summary {vertical-align: baseline;}\"),\n    bslib::navset_underline(\n      id = ns(\"tabs-mode\"),\n      bslib::nav_panel(\n        title = tagList(\n          phosphoricons::ph(\"download-simple\", title = i18n(\"Import\")),\n          i18n(\"Import\")\n        ),\n        value = \"import\",\n        importTab\n      ),\n      bslib::nav_panel(\n        title = tagList(\n          phosphoricons::ph(\"table\", title = i18n(\"View\")),\n          i18n(\"View\")\n        ),\n        value = \"view\",\n        tags$br(),\n        tags$div(\n          style = css(minHeight = \"600px\"),\n          toastui::datagridOutput(outputId = ns(\"view\"), height = \"auto\")\n        )\n      ),\n      bslib::nav_panel(\n        title = tagList(\n          phosphoricons::ph(\"gear-six\", title = i18n(\"Update\")),\n          i18n(\"Update\")\n        ),\n        value = \"update\",\n        tags$br(),\n        update_variables_ui(id = ns(\"update\"), title = NULL)\n      ),\n      bslib::nav_panel(\n        title = tagList(\n          phosphoricons::ph(\"shield-check\", title = i18n(\"Validate\")),\n          i18n(\"Validate\")\n        ),\n        value = \"validate\",\n        tags$br(),\n        validation_ui(\n          id = ns(\"validation\"),\n          display = \"inline\",\n          max_height = \"400px\"\n        )\n      )\n    ),\n    tags$div(\n      id = ns(\"confirm-button\"),\n      style = \"margin-top: 20px;\",\n      button_import(list(ns = ns))\n    ),\n    tags$div(\n      style = \"display: none;\",\n      textInput(inputId = ns(\"hidden\"), label = NULL, value = genId())\n    ),\n    tags$script(\n      sprintf(\"$('#%s').addClass('nav-justified');\", ns(\"tabs-mode\")),\n      sprintf(\"fadeTab({id: '%s'});\", ns(\"tabs-mode\")),\n      sprintf(\"disableTab({id: '%s', value: '%s'});\", ns(\"tabs-mode\"), \"view\"),\n      sprintf(\"disableTab({id: '%s', value: '%s'});\", ns(\"tabs-mode\"), \"update\"),\n      sprintf(\"disableTab({id: '%s', value: '%s'});\", ns(\"tabs-mode\"), \"validate\")\n    )\n  )\n}\n\n\n#' @param validation_opts `list` of arguments passed to [validation_server().\n#' @param allowed_status Vector of statuses allowed to confirm dataset imported,\n#'  if you want that all validation rules are successful before importing data use `allowed_status = \"OK\"`.\n#' @param return_class Class of returned data: `data.frame`, `data.table`, `tbl_df` (tibble) or `raw`.\n#'\n#' @export\n#' @rdname import-modal\n#' @importFrom shiny moduleServer reactiveValues observeEvent\n#'  reactive removeModal updateTabsetPanel hideTab observe\n#' @importFrom rlang %||%\nimport_server <- function(id,\n                          validation_opts = NULL,\n                          allowed_status = c(\"OK\", \"Failed\", \"Error\"),\n                          return_class = c(\"data.frame\", \"data.table\", \"tbl_df\", \"raw\"),\n                          read_fns = list()) {\n  allowed_status <- match.arg(allowed_status, several.ok = TRUE)\n  return_class <- match.arg(return_class)\n  if (length(read_fns) > 0) {\n    if (!is_named(read_fns))\n      stop(\"import_file_server: `read_fns` must be a named list.\", call. = FALSE)\n    if (!all(vapply(read_fns, is_function, logical(1))))\n      stop(\"import_file_server: `read_fns` must be list of function(s).\", call. = FALSE)\n  }\n\n  moduleServer(\n    id,\n    function(input, output, session) {\n\n      ns <- session$ns\n\n      data_rv <- reactiveValues(data = NULL)\n      imported_rv <- reactiveValues(data = NULL)\n\n      observeEvent(input$hidden, {\n        data_rv$data <- NULL\n        data_rv$name <- NULL\n        if (length(validation_opts) < 1) {\n          hideTab(inputId = \"tabs-mode\", target = \"validate\")\n        }\n      })\n\n      observeEvent(input$from, {\n        updateTabsetPanel(\n          session = session,\n          inputId = \"tabs-import\",\n          selected = input$from\n        )\n      })\n\n      from_env <- import_globalenv_server(\n        id = \"env\",\n        trigger_return = \"change\",\n        btn_show_data = FALSE,\n        reset = reactive(input$hidden)\n      )\n      from_file <- import_file_server(\n        id = \"file\",\n        trigger_return = \"change\",\n        btn_show_data = FALSE,\n        reset = reactive(input$hidden),\n        read_fns = read_fns\n      )\n      from_copypaste <- import_copypaste_server(\n        id = \"copypaste\",\n        trigger_return = \"change\",\n        btn_show_data = FALSE,\n        reset = reactive(input$hidden)\n      )\n      from_googlesheets <- import_googlesheets_server(\n        id = \"googlesheets\",\n        trigger_return = \"change\",\n        btn_show_data = FALSE,\n        reset = reactive(input$hidden)\n      )\n      from_url <- import_url_server(\n        id = \"url\",\n        trigger_return = \"change\",\n        btn_show_data = FALSE,\n        reset = reactive(input$hidden)\n      )\n      #from_database <- import_database_server(\"database\")\n\n      observeEvent(from_env$data(), {\n        data_rv$data <- from_env$data()\n        data_rv$name <- from_env$name()\n      })\n      observeEvent(from_file$data(), {\n        data_rv$data <- from_file$data()\n        data_rv$name <- from_file$name()\n      })\n      observeEvent(from_copypaste$data(), {\n        data_rv$data <- from_copypaste$data()\n        data_rv$name <- from_copypaste$name()\n      })\n      observeEvent(from_googlesheets$data(), {\n        data_rv$data <- from_googlesheets$data()\n        data_rv$name <- from_googlesheets$name()\n      })\n      observeEvent(from_url$data(), {\n        data_rv$data <- from_url$data()\n        data_rv$name <- from_url$name()\n      })\n      # observeEvent(from_database$data(), {\n      #   data_rv$data <- from_database$data()\n      # })\n\n      observeEvent(data_rv$data, {\n        req(data_rv$data)\n        if (is.data.frame(data_rv$data)) {\n          if (length(validation_opts) < 1) {\n            toggle_widget(inputId = \"confirm\", enable = TRUE)\n          } else {\n            status <- validation_results$status()\n            if (isTRUE(status %in% allowed_status)) {\n              toggle_widget(inputId = \"confirm\", enable = TRUE)\n            } else {\n              toggle_widget(inputId = \"confirm\", enable = FALSE)\n            }\n          }\n          enable_tab(\"tabs-mode\", \"view\")\n          enable_tab(\"tabs-mode\", \"update\")\n          enable_tab(\"tabs-mode\", \"validate\")\n        } else {\n          toggle_widget(inputId = \"confirm\", enable = FALSE)\n        }\n      })\n\n      output$view <- toastui::renderDatagrid({\n        data <- req(data_rv$data)\n        session <- shiny::getDefaultReactiveDomain()\n        gridTheme <- getOption(\"datagrid.theme\")\n        if (length(gridTheme) < 1) {\n          apply_grid_theme()\n        }\n        on.exit(toastui::reset_grid_theme())\n        grid <- toastui::datagrid(\n          data = data,\n          summary = construct_col_summary(data),\n          colwidths = \"guess\",\n          minBodyHeight = 500\n        )\n        toastui::grid_columns(grid, className = \"font-monospace\")\n      })\n\n      updated_data <- update_variables_server(\n        id = \"update\",\n        data = reactive(data_rv$data),\n        height = \"300px\"\n      )\n\n      validation_results <- validation_server(\n        id = \"validation\",\n        data = reactive({\n          data_rv$data\n        }),\n        n_row = validation_opts$n_row,\n        n_col = validation_opts$n_col,\n        n_row_label = validation_opts$n_row_label %||% \"Valid number of rows\",\n        n_col_label = validation_opts$n_col_label %||% \"Valid number of columns\",\n        btn_label = validation_opts$btn_label,\n        rules = validation_opts$rules\n      )\n\n      observeEvent(validation_results$status(), {\n        status <- validation_results$status()\n        req(status)\n        if (status %in% c(\"Error\", \"Failed\")) {\n          update_tab_label(\"tabs-mode\", \"validate\", tagList(\n            phosphoricons::ph(\"warning-circle\", weight = \"fill\", fill = \"firebrick\"), i18n(\"Validate\")\n          ))\n        } else {\n          update_tab_label(\"tabs-mode\", \"validate\", i18n(\"Validate\"))\n        }\n        if (status %in% allowed_status) {\n          toggle_widget(inputId = \"confirm\", enable = TRUE)\n        } else {\n          toggle_widget(inputId = \"confirm\", enable = FALSE)\n        }\n      })\n\n      observeEvent(updated_data(), {\n        data_rv$data <- updated_data()\n      })\n\n      observeEvent(input$confirm, {\n        removeModal()\n        imported_rv$data <- data_rv$data\n        imported_rv$name <- data_rv$name %||% \"imported_data\"\n      })\n\n      return(list(\n        data = reactive(as_out(imported_rv$data, return_class)),\n        name = reactive(imported_rv$name)\n      ))\n    }\n  )\n}\n\n\n#' @param title Modal window title.\n#' @param size Modal window size, default to \\code{\"l\"} (large).\n#'\n#' @export\n#' @rdname import-modal\n#' @importFrom shiny modalDialog showModal\n#' @importFrom htmltools tags css\nimport_modal <- function(id,\n                         from,\n                         title = i18n(\"Import data\"),\n                         size = \"l\",\n                         file_extensions = c(\".csv\", \".txt\", \".xls\", \".xlsx\", \".rds\", \".fst\", \".sas7bdat\", \".sav\")) {\n  showModal(modalDialog(\n    title = tagList(\n      button_close_modal(),\n      title\n    ),\n    import_ui(id, from, file_extensions = file_extensions),\n    size = size,\n    footer = NULL\n  ))\n}\n\n\n"
  },
  {
    "path": "R/import-url.R",
    "content": "#' @title Import data from a URL\n#'\n#' @description Let user paste link to a JSON then import the data.\n#'\n#' @inheritParams import-globalenv\n#'\n#' @template module-import\n#'\n#' @export\n#' @name import-url\n#'\n#' @importFrom htmltools tags\n#'\n#' @example examples/from-url.R\nimport_url_ui <- function(id, title = TRUE) {\n\n  ns <- shiny::NS(id)\n\n  if (isTRUE(title)) {\n    title <- tags$h4(\n      i18n(\"Import Url\"),\n      class = \"datamods-title\"\n    )\n  }\n\n  tags$div(\n    class = \"datamods-import\",\n    html_dependency_datamods(),\n    title,\n    shinyWidgets::textInputIcon(\n      inputId = ns(\"link\"),\n      label = i18n(\"Enter URL to data:\"),\n      icon = phosphoricons::ph(\"link\"),\n      width = \"100%\"\n    ),\n    tags$div(\n      id = ns(\"import-placeholder\"),\n      alert(\n        id = ns(\"import-result\"),\n        status = \"info\",\n        tags$b(i18n(\"Nothing pasted yet!\")),\n        i18n(\"Please paste a valid link in the dialog box above.\"),\n        i18n(\"You can import from flat table format supported by\"),\n        tags$a(\n          href = \"https://CRAN.R-project.org/package=rio/vignettes/rio.html#Supported_file_formats\",\n          \"package rio\"\n        ),\n        dismissible = TRUE\n      )\n    ),\n    shiny::uiOutput(\n      outputId = ns(\"container_confirm_btn\"),\n      style = \"margin-top: 20px;\"\n    )\n  )\n}\n\n#' @inheritParams import_globalenv_server\n#'\n#' @export\n#'\n#' @importFrom shiny moduleServer\n#' @importFrom shiny reactiveValues observeEvent removeUI reactive req\n#' @importFrom htmltools tags tagList\n#'\n#' @rdname import-url\nimport_url_server <- function(id,\n                              btn_show_data = TRUE,\n                              show_data_in = c(\"popup\", \"modal\"),\n                              trigger_return = c(\"button\", \"change\"),\n                              return_class = c(\"data.frame\", \"data.table\", \"tbl_df\", \"raw\"),\n                              reset = reactive(NULL)) {\n\n  trigger_return <- match.arg(trigger_return)\n  return_class <- match.arg(return_class)\n\n  module <- function(input, output, session) {\n\n    ns <- session$ns\n    imported_rv <- reactiveValues(data = NULL, name = NULL)\n    temporary_rv <- reactiveValues(data = NULL, name = NULL, status = NULL)\n\n    observeEvent(reset(), {\n      temporary_rv$data <- NULL\n      temporary_rv$name <- NULL\n      temporary_rv$status <- NULL\n    })\n\n    output$container_confirm_btn <- renderUI({\n      if (identical(trigger_return, \"button\")) {\n        button_import()\n      }\n    })\n\n    observeEvent(input$trigger, {\n      if (identical(trigger_return, \"change\")) {\n        hideUI(selector = paste0(\"#\", ns(\"confirm-button\")))\n      }\n    })\n\n    observeEvent(input$link, {\n      req(input$link)\n\n      imported <- try(rio::import(input$link), silent = TRUE)\n      if (inherits(imported, \"try-error\")) # retry with explicit json format\n        imported <- try(rio::import(input$link, format = \"json\"), silent = TRUE)\n\n      if (inherits(imported, \"try-error\") || NROW(imported) < 1) {\n        toggle_widget(inputId = \"confirm\", enable = FALSE)\n        # pass error message to UI\n        insert_error(mssg = i18n(attr(imported, \"condition\")$message))\n        temporary_rv$status <- \"error\"\n        temporary_rv$data <- NULL\n        temporary_rv$name <- NULL\n      } else {\n        toggle_widget(inputId = \"confirm\", enable = TRUE)\n        insert_alert(\n          selector = ns(\"import\"),\n          status = \"success\",\n          make_success_alert(\n            imported,\n            trigger_return = trigger_return,\n            btn_show_data = btn_show_data\n          )\n        )\n        temporary_rv$status <- \"success\"\n        temporary_rv$data <- imported\n        temporary_rv$name <- basename(input$link)\n      }\n    }, ignoreInit = TRUE)\n\n    observeEvent(input$see_data, {\n      show_data(temporary_rv$data, title = i18n(\"Imported data\"), type = show_data_in)\n    })\n\n    observeEvent(input$confirm, {\n      imported_rv$data <- temporary_rv$data\n      imported_rv$name <- temporary_rv$name\n    })\n\n    if (identical(trigger_return, \"button\")) {\n      return(list(\n        status = reactive(temporary_rv$status),\n        name = reactive(imported_rv$name),\n        data = reactive(as_out(imported_rv$data, return_class))\n      ))\n    } else {\n      return(list(\n        status = reactive(temporary_rv$status),\n        name = reactive(temporary_rv$name),\n        data = reactive(as_out(temporary_rv$data, return_class))\n      ))\n    }\n  }\n\n  moduleServer(\n    id = id,\n    module = module\n  )\n}\n\n"
  },
  {
    "path": "R/onLoad.R",
    "content": "#' Shiny resource\n#'\n#' @importFrom shiny addResourcePath\n#'\n#' @noRd\n.onLoad <- function(...) {\n  shiny::addResourcePath(\"datamods\", system.file(\"assets\", package = \"datamods\"))\n}\n"
  },
  {
    "path": "R/sample-data.R",
    "content": "## Function sample_n()\n\n#' @title Sample rows\n#'\n#' @description The `sample_n` function returns the sample of a dataset from a number of rows chosen by the user.\n#'\n#' @param data `data.frame`\n#' @param n vector of type `numeric`\n#'\n#' @return the sample of a dataset in the form of `data.table`\n#'\n#' @noRd\n#'\n#' @importFrom data.table as.data.table .N\n#'\n#' @examples\n#' sample_n(iris, 25)\nsample_n <- function(data, n) {\n  as.data.table(data)[sample(x = .N, size = n)]\n}\n\n\n## Function sample_prop()\n\n#' @title Sample percentage\n#'\n#' @description The `sample_prop` function returns the sample of a dataset from a percentage chosen by the user.\n#'\n#' @param data `data.frame`\n#' @param percentage vector of type `numeric`\n#'\n#' @return the sample of a dataset in the form of `data.table`\n#'\n#' @noRd\n#'\n#' @importFrom data.table as.data.table .N\n#'\nsample_prop <- function(data, prop) {\n  as.data.table(data)[sample(x = .N, size = nrow(data) * (prop/100))]\n}\n\n\n## Function sample_ui()\n\n#' @title Shiny module to interactively sample a `data.frame`\n#'\n#' @description Allow to take a sample of `data.frame` for a given number or proportion of rows to keep.\n#'\n#' @param id Module id. See [shiny::moduleServer()].\n#'\n#' @return\n#' * UI: HTML tags that can be included in shiny's UI\n#' * Server: a `reactive` fgunction with the sampled data.\n#'\n#' @export\n#'\n#' @name module-sample\n#'\n#' @importFrom htmltools tagList\n#' @importFrom shinyWidgets radioGroupButtons\n#' @importFrom shiny NS conditionalPanel sliderInput uiOutput\n#'\n#' @example examples/sample.R\nsample_ui <- function(id) {\n  ns <- NS(id)\n\n  tagList(\n    radioGroupButtons(\n      inputId = ns(\"choice\"),\n      label = i18n(\"Sample data by :\"),\n      choiceNames = c(i18n(\"number of rows\"), i18n(\"proportion of rows\")),\n      choiceValues = c(\"number of rows\", \"proportion of rows\"),\n      justified = TRUE,\n      size = \"xs\",\n      width = \"100%\"\n    ),\n\n    conditionalPanel(\n      condition = \"input.choice == `proportion of rows`\",\n      ns = ns,\n      sliderInput(\n        inputId = ns(\"proportion_rows\"),\n        label = i18n(\"Choose a percentage :\"),\n        min = 0,\n        max = 100,\n        value = 100,\n        post = \" %\",\n        width = \"100%\"\n      ),\n      uiOutput(outputId = ns(\"feedback_proportion_rows\"))\n    ),\n\n    conditionalPanel(\n      condition = \"input.choice == `number of rows`\",\n      ns = ns,\n      sliderInput(\n        inputId = ns(\"number_rows\"),\n        label = i18n(\"Choose a number of rows :\"),\n        min = 0,\n        max = 10,\n        value = 10,\n        width = \"100%\"\n      ),\n      uiOutput(outputId = ns(\"feedback_number_rows\"))\n    )\n  )\n}\n\n\n## Function sample_server()\n\n#' @param data_r `reactive` containing a `data.frame` to use in the module.\n#'\n#' @export\n#'\n#' @rdname module-sample\n#'\n#' @importFrom shiny moduleServer observeEvent updateSliderInput renderUI reactive\n#' @importFrom htmltools tags div\n#'\nsample_server <- function(id, data_r = reactive(NULL)) {\n  moduleServer(\n    id,\n    function(input, output, session) {\n\n      observeEvent(data_r(), {\n        req(data_r())\n        updateSliderInput(\n          session,\n          inputId = \"number_rows\",\n          min = 0,\n          max = nrow(data_r()),\n          value = nrow(data_r())\n        )\n      })\n\n      output$feedback_proportion_rows <- renderUI({\n        sample <- req(sample_r())\n        tags$div(\n          paste(input$proportion_rows, i18n(\"% of the total, i.e.\"), nrow(sample), i18n(\"rows\"))\n        )\n      })\n\n      output$feedback_number_rows <- renderUI({\n        data <- req(data_r())\n        tags$div(\n          paste(input$number_rows, i18n(\"lines, i.e.\"), round(input$number_rows / nrow(data) * 100, 1), i18n(\"% of the total\"))\n        )\n      })\n\n      sample_r <- reactive({\n        req(data_r())\n        if (input$choice == \"proportion of rows\") {\n          table_sample <- sample_prop(data = data_r(), prop = input$proportion_rows)\n        } else {\n          table_sample <- sample_n(data = data_r(), n = input$number_rows)\n        }\n        return(table_sample)\n      })\n\n      return(sample_r)\n    }\n  )\n}\n\n\n"
  },
  {
    "path": "R/select-group.R",
    "content": "#' @title Select Group Input Module\n#'\n#' @description Group of mutually dependent select menus for filtering `data.frame`'s columns (like in Excel).\n#'\n#' @param id Module's id.\n#' @param params A list of parameters passed to each [shinyWidgets::virtualSelectInput()],\n#'  you can use :\n#'   * `inputId`: mandatory, must correspond to variable name.\n#'   * `label`: Display label for the control.\n#'   * `placeholder`: Text to show when no options selected.\n#' @param label Character, global label on top of all labels.\n#' @param btn_reset_label Character, reset button label. If `NULL` no button is added.\n#' @param inline If `TRUE` (the default),\n#'  select menus are horizontally positioned, otherwise vertically.\n#' @param vs_args Arguments passed to all [shinyWidgets::virtualSelectInput()] created.\n#'\n#' @return A [shiny::reactive()] function containing data filtered with an attribute `inputs` containing a named list of selected inputs.\n#' @export\n#'\n#' @name select-group\n#'\n#' @importFrom utils modifyList\n#' @importFrom htmltools tagList tags css\n#' @importFrom shiny NS actionLink icon singleton\n#' @importFrom shinyWidgets virtualSelectInput\n#'\n#' @example examples/select-group-default.R\n#' @example examples/select-group-selected.R\nselect_group_ui <- function(\n  id,\n  params,\n  label = NULL,\n  btn_reset_label = \"Reset filters\",\n  inline = TRUE,\n  vs_args = list()\n) {\n  ns <- NS(id)\n\n  button_reset <- if (!is.null(btn_reset_label)) {\n    actionLink(\n      inputId = ns(\"reset_all\"),\n      label = tagList(\n        phosphoricons::ph(\"x\", title = btn_reset_label),\n        btn_reset_label\n      ),\n      icon = NULL,\n      style = \"text-align: right;\"\n    )\n  }\n  label_tag <- if (!is.null(label)) tags$b(label, class = \"select-group-label\")\n\n  sel_tag <- lapply(\n    X = seq_along(params),\n    FUN = function(x) {\n      input <- params[[x]]\n      vs_args <- modifyList(\n        x = vs_args,\n        val = list(\n          inputId = ns(input$inputId),\n          label = input$label,\n          placeholder = input$placeholder,\n          choices = input$selected,\n          selected = input$selected,\n          multiple = ifelse(is.null(input$multiple), TRUE, input$multiple),\n          width = \"100%\"\n        ),\n        keep.null = TRUE\n      )\n      if (is.null(vs_args$showValueAsTags)) vs_args$showValueAsTags <- TRUE\n      if (is.null(vs_args$zIndex)) vs_args$zIndex <- 10\n      if (is.null(vs_args$disableSelectAll)) vs_args$disableSelectAll <- TRUE\n      tags$div(\n        class = \"select-group-item\",\n        id = ns(paste0(\"container-\", input$inputId)),\n        do.call(shinyWidgets::virtualSelectInput, vs_args)\n      )\n    }\n  )\n\n  if (isTRUE(inline)) {\n    sel_tag <- tags$div(\n      class = \"select-group-container\",\n      style = htmltools::css(\n        display = \"grid\",\n        gridTemplateColumns = sprintf(\"repeat(%s, 1fr)\", length(params)),\n        gridColumnGap = \"5px\"\n      ),\n      sel_tag\n    )\n  }\n\n  tags$div(\n    class = \"select-group\",\n    label_tag,\n    sel_tag,\n    button_reset,\n    html_dependency_datamods()\n  )\n}\n\n\n#' @param data_r Either a [data.frame()] or a [shiny::reactive()]\n#'  function returning a `data.frame` (do not use parentheses).\n#' @param vars_r character, columns to use to create filters,\n#'  must correspond to variables listed in `params`. Can be a\n#'  [shiny::reactive()] function, but values must be included in the initial ones (in `params`).\n#' @param selected_r [shiny::reactive()] function returning a named list with selected values to set.\n#'\n#' @export\n#'\n#' @rdname select-group\n#' @importFrom shiny observeEvent observe reactiveValues reactive is.reactive isolate isTruthy\n#' @importFrom shinyWidgets updateVirtualSelect\n#' @importFrom rlang %||%\nselect_group_server <- function(id, data_r, vars_r, selected_r = reactive(list())) {\n  moduleServer(\n    id = id,\n    module = function(input, output, session) {\n      # Namespace\n      ns <- session$ns\n      hideUI(selector = paste0(\"#\", ns(\"reset_all\")))\n\n      # data <- as.data.frame(data)\n      rv <- reactiveValues(data = NULL, vars = NULL)\n      observe({\n        if (is.reactive(data_r)) {\n          rv$data <- data_r()\n        } else {\n          rv$data <- as.data.frame(data_r)\n        }\n        if (is.reactive(vars_r)) {\n          rv$vars <- vars_r()\n        } else {\n          rv$vars <- vars_r\n        }\n        for (var in names(rv$data)) {\n          if (var %in% rv$vars) {\n            showUI(id = paste0(\"container-\", var))\n          } else {\n            hideUI(id = paste0(\"container-\", var))\n          }\n        }\n      })\n\n      observe({\n        selected <- selected_r()\n        if (!is.list(selected)) selected <- list()\n        lapply(\n          X = rv$vars,\n          FUN = function(x) {\n            vals <- sort(unique(rv$data[[x]]))\n            shinyWidgets::updateVirtualSelect(\n              session = session,\n              inputId = x,\n              choices = vals,\n              selected = selected[[x]] %||% isolate(input[[x]])\n            )\n          }\n        )\n      })\n\n      observeEvent(input$reset_all, {\n        lapply(\n          X = rv$vars,\n          FUN = function(x) {\n            vals <- sort(unique(rv$data[[x]]))\n            shinyWidgets::updateVirtualSelect(\n              session = session,\n              inputId = x,\n              choices = vals\n            )\n          }\n        )\n      })\n\n      observe({\n        vars <- rv$vars\n        lapply(\n          X = vars,\n          FUN = function(x) {\n            ovars <- vars[vars != x]\n\n            observeEvent(\n              input[[x]],\n              {\n                data <- rv$data\n\n                indicator <- lapply(\n                  X = vars,\n                  FUN = function(x) {\n                    data[[x]] %inT% input[[x]]\n                  }\n                )\n                indicator <- Reduce(f = `&`, x = indicator)\n                data <- data[indicator, ]\n\n                if (all(indicator)) {\n                  hideUI(selector = paste0(\"#\", ns(\"reset_all\")))\n                } else {\n                  showUI(selector = paste0(\"#\", ns(\"reset_all\")))\n                }\n\n                for (i in ovars) {\n                  if (!isTruthy(input[[i]])) {\n                    shinyWidgets::updateVirtualSelect(\n                      session = session,\n                      inputId = i,\n                      choices = sort(unique(data[[i]]))\n                    )\n                  }\n                }\n\n                if (!isTruthy(input[[x]])) {\n                  shinyWidgets::updateVirtualSelect(\n                    session = session,\n                    inputId = x,\n                    choices = sort(unique(data[[x]]))\n                  )\n                }\n              },\n              ignoreNULL = FALSE,\n              ignoreInit = TRUE\n            )\n          }\n        )\n      })\n\n      return(reactive({\n        data <- rv$data\n        vars <- rv$vars\n        indicator <- lapply(\n          X = vars,\n          FUN = function(x) {\n            data[[x]] %inT% input[[x]]\n          }\n        )\n        indicator <- Reduce(f = `&`, x = indicator)\n        data <- data[indicator, ]\n        attr(data, \"inputs\") <- lapply(\n          X = setNames(vars, vars),\n          FUN = function(x) input[[x]]\n        )\n        return(data)\n      }))\n    }\n  )\n}\n"
  },
  {
    "path": "R/show_data.R",
    "content": "\n#' Display a table in a window\n#'\n#' @param data a data object (either a `matrix` or a `data.frame`).\n#' @param title Title to be displayed in window.\n#' @param show_classes Show variables classes under variables names in table header.\n#' @param type Display table in a pop-up with [shinyWidgets::show_alert()],\n#'  in modal window with [shiny::showModal()] or in a WinBox window with [shinyWidgets::WinBox()].\n#' @param options Arguments passed to [toastui::datagrid()].\n#' @param width Width of the window, only used if `type = \"popup\"` or `type = \"winbox\"`.\n#' @param ... Additional options, such as `wbOptions = wbOptions()` or `wbControls = wbControls()`.\n#' @inheritParams shiny::showModal\n#'\n#' @note\n#' If you use `type = \"winbox\"`, you'll need to use `shinyWidgets::html_dependency_winbox()` somewhere in your UI.\n#'\n#' @return No value.\n#' @export\n#'\n#' @importFrom shinyWidgets show_alert\n#' @importFrom htmltools tags tagList css\n#' @importFrom shiny showModal modalDialog\n#' @importFrom utils modifyList packageVersion\n#'\n#' @example examples/show_data.R\nshow_data <- function(data,\n                      title = NULL,\n                      options = NULL,\n                      show_classes = TRUE,\n                      type = c(\"popup\", \"modal\", \"winbox\"),\n                      width = \"65%\",\n                      ...,\n                      session = shiny::getDefaultReactiveDomain()) { # nocov start\n  type <- match.arg(type)\n  data <- as.data.frame(data)\n  args <- list(...)\n  gridTheme <- getOption(\"datagrid.theme\")\n  if (length(gridTheme) < 1) {\n    apply_grid_theme()\n  }\n  on.exit(toastui::reset_grid_theme())\n\n  if (is.null(options))\n    options <- list()\n\n  options$height <- 550\n  options$minBodyHeight <- 400\n  options$data <- data\n  options$theme <- \"default\"\n  options$colwidths <- \"guess\"\n  options$guess_colwidths_opts <- list(min_width = 90, max_width = 400, mul = 1, add = 10)\n  if (isTRUE(show_classes))\n    options$summary <- construct_col_summary(data)\n  datatable <- rlang::exec(toastui::datagrid, !!!options)\n  datatable <- toastui::grid_columns(datatable, className = \"font-monospace\")\n  if (is.null(session))\n    return(datatable)\n  if (identical(type, \"winbox\")) {\n    wb_options <- if (is.null(args$wbOptions)) {\n      shinyWidgets::wbOptions(\n        height = \"600px\",\n        width = width,\n        modal = TRUE\n      )\n    } else {\n      modifyList(\n        shinyWidgets::wbOptions(\n          height = \"600px\",\n          width = width,\n          modal = TRUE\n        ),\n        args$wbOptions\n      )\n    }\n    wb_controls <- if (is.null(args$wbControls)) {\n      shinyWidgets::wbControls()\n    } else {\n      args$wbControls\n    }\n    shinyWidgets::WinBox(\n      title = title,\n      ui = datatable,\n      options = wb_options,\n      controls = wb_controls,\n      padding = \"0 5px\",\n      session = session\n    )\n  } else if (identical(type, \"popup\")) {\n    show_alert(\n      title = NULL,\n      text = tags$div(\n        if (!is.null(title)) {\n          tagList(\n            tags$h3(title),\n            tags$hr()\n          )\n        },\n        style = \"color: #000 !important;\",\n        datatable\n      ),\n      closeOnClickOutside = TRUE,\n      showCloseButton = TRUE,\n      btn_labels = NA,\n      html = TRUE,\n      width = width,\n      session = session\n    )\n  } else {\n    showModal(modalDialog(\n      title = tagList(\n        button_close_modal(),\n        title\n      ),\n      tags$div(\n        style = css(minHeight = validateCssUnit(options$height)),\n        toastui::renderDatagrid2(datatable)\n      ),\n      size = \"xl\",\n      footer = NULL,\n      easyClose = TRUE\n    ), session = session)\n  }\n} # nocov end\n\n"
  },
  {
    "path": "R/update-factor.R",
    "content": "\n#' @title Module to Reorder the Levels of a Factor Variable\n#'\n#' @description\n#' This module contain an interface to reorder the levels of a factor variable.\n#'\n#'\n#' @param id Module ID.\n#'\n#' @return A [shiny::reactive()] function returning the data.\n#' @export\n#'\n#' @importFrom shiny NS fluidRow tagList column actionButton\n#' @importFrom shinyWidgets virtualSelectInput prettyCheckbox\n#' @importFrom toastui datagridOutput\n#' @importFrom htmltools tags\n#'\n#' @name update-factor\n#'\n#' @example examples/update_factor.R\nupdate_factor_ui <- function(id) {\n  ns <- NS(id)\n  tagList(\n    tags$style(\n      \".tui-grid-row-header-draggable span {width: 3px !important; height: 3px !important;}\"\n    ),\n    fluidRow(\n      column(\n        width = 6,\n        virtualSelectInput(\n          inputId = ns(\"variable\"),\n          label = i18n(\"Factor variable to reorder:\"),\n          choices = NULL,\n          width = \"100%\",\n          zIndex = 50\n        )\n      ),\n      column(\n        width = 3,\n        class = \"d-flex align-items-end\",\n        actionButton(\n          inputId = ns(\"sort_levels\"),\n          label = tagList(\n            ph(\"sort-ascending\"),\n            i18n(\"Sort by levels\")\n          ),\n          class = \"btn-outline-primary mb-3\",\n          width = \"100%\"\n        )\n      ),\n      column(\n        width = 3,\n        class = \"d-flex align-items-end\",\n        actionButton(\n          inputId = ns(\"sort_occurrences\"),\n          label = tagList(\n            ph(\"sort-ascending\"),\n            i18n(\"Sort by count\")\n          ),\n          class = \"btn-outline-primary mb-3\",\n          width = \"100%\"\n        )\n      )\n    ),\n    datagridOutput(ns(\"grid\")),\n    tags$div(\n      class = \"float-end\",\n      prettyCheckbox(\n        inputId = ns(\"new_var\"),\n        label = i18n(\"Create a new variable (otherwise replaces the one selected)\"),\n        value = FALSE,\n        status = \"primary\",\n        outline = TRUE,\n        inline = TRUE\n      ),\n      actionButton(\n        inputId = ns(\"create\"),\n        label = tagList(ph(\"arrow-clockwise\"), i18n(\"Update factor variable\")),\n        class = \"btn-outline-primary\"\n      )\n    ),\n    tags$div(class = \"clearfix\")\n  )\n}\n\n\n#' @param data_r A [shiny::reactive()] function returning a `data.frame`.\n#'\n#' @export\n#'\n#' @importFrom shiny moduleServer observeEvent reactive reactiveValues req bindEvent isTruthy updateActionButton\n#' @importFrom shinyWidgets updateVirtualSelect\n#' @importFrom toastui renderDatagrid datagrid grid_columns grid_colorbar\n#'\n#' @rdname update-factor\nupdate_factor_server <- function(id, data_r = reactive(NULL)) {\n  moduleServer(\n    id,\n    function(input, output, session) {\n\n      rv <- reactiveValues(data = NULL, data_grid = NULL)\n\n      bindEvent(observe({\n        data <- data_r()\n        rv$data <- data\n        vars_factor <- vapply(data, is.factor, logical(1))\n        vars_factor <- names(vars_factor)[vars_factor]\n        updateVirtualSelect(\n          inputId = \"variable\",\n          choices = vars_factor,\n          selected = if (isTruthy(input$variable)) input$variable else vars_factor[1]\n        )\n      }), data_r(), input$hidden)\n\n      observeEvent(input$variable, {\n        data <- req(data_r())\n        variable <- req(input$variable)\n        grid <- as.data.frame(table(data[[variable]]))\n        rv$data_grid <- grid\n      })\n\n      observeEvent(input$sort_levels, {\n        if (input$sort_levels %% 2 == 1) {\n          decreasing <- FALSE\n          label <- tagList(\n            ph(\"sort-descending\"),\n            \"Sort Levels\"\n          )\n        } else {\n          decreasing <- TRUE\n          label <- tagList(\n            ph(\"sort-ascending\"),\n            \"Sort Levels\"\n          )\n        }\n        updateActionButton(inputId = \"sort_levels\", label = as.character(label))\n        rv$data_grid <- rv$data_grid[order(rv$data_grid[[1]], decreasing = decreasing), ]\n      })\n\n      observeEvent(input$sort_occurrences, {\n        if (input$sort_occurrences %% 2 == 1) {\n          decreasing <- FALSE\n          label <- tagList(\n            ph(\"sort-descending\"),\n            i18n(\"Sort count\")\n          )\n        } else {\n          decreasing <- TRUE\n          label <- tagList(\n            ph(\"sort-ascending\"),\n            i18n(\"Sort count\")\n          )\n        }\n        updateActionButton(inputId = \"sort_occurrences\", label = as.character(label))\n        rv$data_grid <- rv$data_grid[order(rv$data_grid[[2]], decreasing = decreasing), ]\n      })\n\n\n      output$grid <- renderDatagrid({\n        req(rv$data_grid)\n        gridTheme <- getOption(\"datagrid.theme\")\n        if (length(gridTheme) < 1) {\n          apply_grid_theme()\n        }\n        on.exit(toastui::reset_grid_theme())\n        grid <- datagrid(\n          data = rv$data_grid,\n          draggable = TRUE,\n          sortable = FALSE,\n          data_as_input = TRUE\n        )\n        grid <- grid_columns(\n          grid,\n          columns = c(\"Var1\", \"Freq\"),\n          header = c(i18n(\"Levels\"), i18n(\"Count\"))\n        )\n        grid <- grid_colorbar(\n          grid,\n          column = \"Freq\",\n          label_outside = TRUE,\n          label_width = \"30px\",\n          background = \"#D8DEE9\",\n          bar_bg = get_primary_color(),\n          from = c(0, max(rv$data_grid$Freq) + 1)\n        )\n        grid\n      })\n\n      data_updated_r <- reactive({\n        data <- req(data_r())\n        variable <- req(input$variable)\n        grid <- req(input$grid_data)\n        name_var <- if (isTRUE(input$new_var)) {\n          paste0(variable, \"_updated\")\n        } else {\n          variable\n        }\n        data[[name_var]] <- factor(\n          as.character(data[[variable]]),\n          levels = grid[[\"Var1\"]]\n        )\n        data\n      })\n\n      data_returned_r <- observeEvent(input$create, {\n        rv$data <- data_updated_r()\n      })\n      return(reactive(rv$data))\n    }\n  )\n}\n\n\n\n#' @inheritParams shiny::modalDialog\n#' @export\n#'\n#' @importFrom shiny showModal modalDialog textInput\n#' @importFrom htmltools tagList\n#'\n#' @rdname update-factor\nmodal_update_factor <- function(id,\n                                title = i18n(\"Update levels of a factor\"),\n                                easyClose = TRUE,\n                                size = \"l\",\n                                footer = NULL) {\n  ns <- NS(id)\n  showModal(modalDialog(\n    title = tagList(title, button_close_modal()),\n    update_factor_ui(id),\n    tags$div(\n      style = \"display: none;\",\n      textInput(inputId = ns(\"hidden\"), label = NULL, value = genId())\n    ),\n    easyClose = easyClose,\n    size = size,\n    footer = footer\n  ))\n}\n\n\n#' @inheritParams shinyWidgets::WinBox\n#' @export\n#'\n#' @importFrom shinyWidgets WinBox wbOptions wbControls\n#' @importFrom htmltools tagList\n#' @rdname create-column\nwinbox_update_factor <- function(id,\n                                 title = i18n(\"Update levels of a factor\"),\n                                 options = shinyWidgets::wbOptions(),\n                                 controls = shinyWidgets::wbControls()) {\n  ns <- NS(id)\n  WinBox(\n    title = title,\n    ui = tagList(\n      update_factor_ui(id),\n      tags$div(\n        style = \"display: none;\",\n        textInput(inputId = ns(\"hidden\"), label = NULL, value = genId())\n      )\n    ),\n    options = modifyList(\n      shinyWidgets::wbOptions(height = \"615px\", modal = TRUE),\n      options\n    ),\n    controls = controls,\n    auto_height = FALSE\n  )\n}\n\n\n"
  },
  {
    "path": "R/update-variables.R",
    "content": "\n#' Select, rename and convert variables\n#'\n#' @param id Module id. See [shiny::moduleServer()].\n#' @param title Module's title, if `TRUE` use the default title,\n#'  use \\code{NULL} for no title or a `shiny.tag` for a custom one.\n#'\n#' @return A [shiny::reactive()] function returning the updated data.\n#' @export\n#'\n#' @name update-variables\n#'\n#' @importFrom shiny uiOutput actionButton icon\n#' @importFrom htmltools tagList tags\n#' @importFrom shinyWidgets html_dependency_pretty textInputIcon dropMenu\n#'\n#' @example examples/variables.R\nupdate_variables_ui <- function(id, title = TRUE) {\n  ns <- NS(id)\n  if (isTRUE(title)) {\n    title <- tags$h4(\n      i18n(\"Update & select variables\"),\n      class = \"datamods-title\"\n    )\n  }\n  tags$div(\n    class = \"datamods-update\",\n    html_dependency_pretty(),\n    title,\n    tags$div(\n      style = \"min-height: 25px;\",\n      tags$div(\n        uiOutput(outputId = ns(\"data_info\"), inline = TRUE),\n        tagAppendAttributes(\n          dropMenu(\n            placement = \"bottom-end\",\n            actionButton(\n              inputId = ns(\"settings\"),\n              label = phosphoricons::ph(\"gear\"),\n              class = \"pull-right float-right\"\n            ),\n            textInputIcon(\n              inputId = ns(\"format\"),\n              label = i18n(\"Date format:\"),\n              value = \"%Y-%m-%d\",\n              icon = list(phosphoricons::ph(\"clock\"))\n            ),\n            textInputIcon(\n              inputId = ns(\"origin\"),\n              label = i18n(\"Date to use as origin to convert date/datetime:\"),\n              value = \"1970-01-01\",\n              icon = list(phosphoricons::ph(\"calendar\"))\n            ),\n            textInputIcon(\n              inputId = ns(\"dec\"),\n              label = i18n(\"Decimal separator:\"),\n              value = \".\",\n              icon = list(\"0.00\")\n            )\n          ),\n          style = \"display: inline;\"\n        )\n      ),\n      tags$br(),\n      toastui::datagridOutput(outputId = ns(\"table\"))\n    ),\n    tags$br(),\n    tags$div(\n      id = ns(\"update-placeholder\"),\n      alert(\n        id = ns(\"update-result\"),\n        status = \"info\",\n        phosphoricons::ph(\"info\"),\n        i18n(paste(\n          \"Select, rename and convert variables in table above,\",\n          \"then apply changes by clicking button below.\"\n        ))\n      )\n    ),\n    actionButton(\n      inputId = ns(\"validate\"),\n      label = tagList(\n        phosphoricons::ph(\"arrow-circle-right\", title = i18n(\"Apply changes\")),\n        i18n(\"Apply changes\")\n      ),\n      width = \"100%\"\n    )\n  )\n}\n\n#' @export\n#'\n#' @param id Module's ID\n#' @param data a \\code{data.frame} or a \\code{reactive} function returning a \\code{data.frame}.\n#' @param height Height for the table.\n#' @param return_data_on_init Return initial data when module is called.\n#' @param try_silent logical: should the report of error messages be suppressed?\n#'\n#' @rdname update-variables\n#'\n#' @importFrom shiny moduleServer reactiveValues reactive renderUI reactiveValuesToList validate need reactiveVal\n#' @importFrom rlang call2 expr\n#' @importFrom data.table setorderv\nupdate_variables_server <- function(id,\n                                    data,\n                                    height = NULL,\n                                    return_data_on_init = FALSE,\n                                    try_silent = FALSE) {\n  moduleServer(\n    id = id,\n    module = function(input, output, session) {\n\n      ns <- session$ns\n      updated_data <- reactiveValues(x = NULL)\n\n      data_r <- reactive({\n        if (is.reactive(data)) {\n          data()\n        } else {\n          data\n        }\n      })\n\n      output$data_info <- renderUI({\n        shiny::req(data_r())\n        data <- data_r()\n        sprintf(i18n(\"Data has %s observations and %s variables.\"), nrow(data), ncol(data))\n      })\n\n      variables_r <- reactive({\n        shiny::validate(\n          shiny::need(data(), i18n(\"No data to display.\"))\n        )\n        data <- data_r()\n        if (isTRUE(return_data_on_init)) {\n          updated_data$x <- data\n        } else {\n          updated_data$x <- NULL\n        }\n        summary_vars(data)\n      })\n\n      output$table <- toastui::renderDatagrid({\n        req(variables_r())\n        variables <- variables_r()\n        update_variables_datagrid(\n          variables,\n          height = height,\n          selectionId = ns(\"row_selected\"),\n          buttonId = \"validate\"\n        )\n      })\n\n      observeEvent(input$validate, {\n        updated_data$list_rename <- NULL\n        updated_data$list_select <- NULL\n        updated_data$list_mutate <- NULL\n        data <- data_r()\n        new_selections <- input$row_selected\n        if (length(new_selections) < 1)\n          new_selections <- seq_along(data)\n\n        data_inputs <- as.data.table(input$table_data)\n        setorderv(data_inputs, \"rowKey\")\n\n        old_names <- data_inputs$name\n        new_names <- data_inputs$name_toset\n        new_names[new_names == \"Enter new name\"] <- NA\n        new_names[is.na(new_names)] <- old_names[is.na(new_names)]\n        new_names[new_names == \"\"] <- old_names[new_names == \"\"]\n\n\n        new_classes <- data_inputs$class_toset\n        new_classes[new_classes == \"Select new class\"] <- NA\n\n        data_sv <- variables_r()\n        vars_to_change <- get_vars_to_convert(data_sv, setNames(as.list(new_classes), old_names))\n\n        res_update <- try({\n          # convert\n          if (nrow(vars_to_change) > 0) {\n            data <- convert_to(\n              data = data,\n              variable = vars_to_change$name,\n              new_class = vars_to_change$class_to_set,\n              origin = input$origin,\n              format = input$format,\n              dec = input$dec\n            )\n          }\n          list_mutate <- attr(data, \"code_03_convert\")\n\n          # rename\n          list_rename <- setNames(\n            as.list(old_names),\n            unlist(new_names, use.names = FALSE)\n          )\n          list_rename <- list_rename[names(list_rename) != unlist(list_rename, use.names = FALSE)]\n          names(data) <- unlist(new_names, use.names = FALSE)\n\n          # select\n          list_select <- setdiff(names(data), names(data)[new_selections])\n          data <- data[, new_selections, drop = FALSE]\n\n        }, silent = try_silent)\n\n        if (inherits(res_update, \"try-error\")) {\n          insert_error(selector = \"update\")\n        } else {\n          insert_alert(\n            selector = ns(\"update\"),\n            status = \"success\",\n            tags$b(phosphoricons::ph(\"check\"), i18n(\"Data successfully updated!\"))\n          )\n          updated_data$x <- data\n          updated_data$list_rename <- list_rename\n          updated_data$list_select <- list_select\n          updated_data$list_mutate <- list_mutate\n        }\n      }, ignoreNULL = TRUE, ignoreInit = TRUE)\n\n      return(reactive({\n        data <- updated_data$x\n        code <- list()\n        if (!is.null(data) && isTruthy(updated_data$list_mutate) && length(updated_data$list_mutate) > 0) {\n          code <- c(code, list(call2(\"mutate\", !!!updated_data$list_mutate)))\n        }\n        if (!is.null(data) && isTruthy(updated_data$list_rename) && length(updated_data$list_rename) > 0) {\n          code <- c(code, list(call2(\"rename\", !!!updated_data$list_rename)))\n        }\n        if (!is.null(data) && isTruthy(updated_data$list_select) && length(updated_data$list_select) > 0) {\n          code <- c(code, list(expr(select(-any_of(c(!!!updated_data$list_select))))))\n        }\n        if (length(code) > 0) {\n          attr(data, \"code\") <- Reduce(\n            f = function(x, y) expr(!!x %>% !!y),\n            x = code\n          )\n        }\n        return(data)\n      }))\n    }\n  )\n}\n\n\n\n\n\n\n# utils -------------------------------------------------------------------\n\n\n#' Get variables classes from a \\code{data.frame}\n#'\n#' @param data a \\code{data.frame}\n#'\n#' @return a \\code{character} vector as same length as number of variables\n#' @noRd\n#'\n#' @examples\n#'\n#' get_classes(mtcars)\nget_classes <- function(data) {\n  classes <- lapply(\n    X = data,\n    FUN = function(x) {\n      paste(class(x), collapse = \", \")\n    }\n  )\n  unlist(classes, use.names = FALSE)\n}\n\n\n#' Get count of unique values in variables of \\code{data.frame}\n#'\n#' @param data a \\code{data.frame}\n#'\n#' @return a \\code{numeric} vector as same length as number of variables\n#' @noRd\n#'\n#' @importFrom data.table uniqueN\n#'\n#' @examples\n#' get_n_unique(mtcars)\nget_n_unique <- function(data) {\n  u <- lapply(data, FUN = function(x) {\n    if (is.atomic(x)) {\n      uniqueN(x)\n    } else {\n      NA_integer_\n    }\n  })\n  unlist(u, use.names = FALSE)\n}\n\n\n\n#' Add padding 0 to a vector\n#'\n#' @param x a \\code{vector}\n#'\n#' @return a \\code{character} vector\n#' @noRd\n#'\n#' @examples\n#'\n#' pad0(1:10)\n#' pad0(c(1, 15, 150, NA))\npad0 <- function(x) {\n  NAs <- which(is.na(x))\n  x <- formatC(x, width = max(nchar(as.character(x)), na.rm = TRUE), flag = \"0\")\n  x[NAs] <- NA\n  x\n}\n\n\n\n#' Variables summary\n#'\n#' @param data a \\code{data.frame}\n#'\n#' @return a \\code{data.frame}\n#' @noRd\n#'\n#' @examples\n#'\n#' summary_vars(iris)\n#' summary_vars(mtcars)\nsummary_vars <- function(data) {\n  data <- as.data.frame(data)\n  datsum <- data.frame(\n    name = names(data),\n    class = get_classes(data),\n    n_missing = unname(colSums(is.na(data))),\n    stringsAsFactors = FALSE\n  )\n  datsum$p_complete <- 1 - datsum$n_missing / nrow(data)\n  datsum$n_unique <- get_n_unique(data)\n  datsum\n}\n\n\n\nadd_var_toset <- function(data, var_name, default = \"\") {\n  datanames <- names(data)\n  datanames <- append(\n    x = datanames,\n    values = paste0(var_name, \"_toset\"),\n    after = which(datanames == var_name)\n  )\n  data[[paste0(var_name, \"_toset\")]] <- default\n  data[, datanames]\n}\n\n#' @importFrom toastui datagrid grid_columns grid_format grid_style_column\n#'  grid_style_column grid_editor grid_editor_opts grid_selection_row\nupdate_variables_datagrid <- function(data, height = NULL, selectionId = NULL, buttonId = NULL) {\n\n  data <- add_var_toset(data, \"name\", \"Enter new name\")\n  data <- add_var_toset(data, \"class\", \"Select new class\")\n\n  gridTheme <- getOption(\"datagrid.theme\")\n  if (length(gridTheme) < 1) {\n    apply_grid_theme()\n  }\n  on.exit(toastui::reset_grid_theme())\n\n  grid <- datagrid(\n    data = data,\n    theme = \"default\",\n    colwidths = NULL\n  )\n  grid <- grid_columns(\n    grid = grid,\n    columns = c(\"name\", \"name_toset\", \"class\", \"class_toset\", \"n_missing\", \"p_complete\", \"n_unique\"),\n    header = c(\"Name\", \"New name\", \"Class\", \"New class\", \"Missing values\", \"Complete obs.\", \"Unique values\"),\n    minWidth = 120\n  )\n  grid <- grid_format(\n    grid = grid,\n    \"p_complete\",\n    formatter = toastui::JS(\"function(obj) {return (obj.value*100).toFixed(0) + '%';}\")\n  )\n  grid <- grid_style_column(\n    grid = grid,\n    column = \"name_toset\",\n    fontStyle = \"italic\"\n  )\n  grid <- grid_style_column(\n    grid = grid,\n    column = \"class_toset\",\n    fontStyle = \"italic\"\n  )\n  grid <- grid_editor(\n    grid = grid,\n    column = \"name_toset\",\n    type = \"text\"\n  )\n  grid <- grid_editor(\n    grid = grid,\n    column = \"class_toset\",\n    type = \"select\",\n    choices = c(\"Select new class\", \"character\", \"factor\", \"numeric\", \"integer\", \"date\", \"datetime\")\n  )\n  grid <- grid_editor_opts(\n    grid = grid,\n    editingEvent = \"click\",\n    actionButtonId = NULL,\n    session = NULL\n  )\n  grid <- grid_selection_row(\n    grid = grid,\n    inputId = selectionId,\n    type = \"checkbox\",\n    return = \"index\"\n  )\n  return(grid)\n}\n\n\n\n\n#' Convert a variable to specific new class\n#'\n#' @param data A \\code{data.frame}\n#' @param variable Name of the variable to convert\n#' @param new_class Class to set\n#' @param ... Other arguments passed on to methods.\n#'\n#' @return A \\code{data.frame}\n#' @noRd\n#'\n#' @importFrom utils type.convert\n#' @importFrom rlang sym expr\n#'\n#' @examples\n#' dat <- data.frame(\n#'   v1 = month.name,\n#'   v2 = month.abb,\n#'   v3 = 1:12,\n#'   v4 = as.numeric(Sys.Date() + 0:11),\n#'   v5 = as.character(Sys.Date() + 0:11),\n#'   v6 = as.factor(c(\"a\", \"a\", \"b\", \"a\", \"b\", \"a\", \"a\", \"b\", \"a\", \"b\", \"b\", \"a\")),\n#'   v7 = as.character(11:22),\n#'   stringsAsFactors = FALSE\n#' )\n#'\n#' str(dat)\n#'\n#' str(convert_to(dat, \"v3\", \"character\"))\n#' str(convert_to(dat, \"v6\", \"character\"))\n#' str(convert_to(dat, \"v7\", \"numeric\"))\n#' str(convert_to(dat, \"v4\", \"date\", origin = \"1970-01-01\"))\n#' str(convert_to(dat, \"v5\", \"date\"))\n#'\n#' str(convert_to(dat, c(\"v1\", \"v3\"), c(\"factor\", \"character\")))\n#'\n#' str(convert_to(dat, c(\"v1\", \"v3\", \"v4\"), c(\"factor\", \"character\", \"date\"), origin = \"1970-01-01\"))\n#'\nconvert_to <- function(data,\n                       variable,\n                       new_class = c(\"character\", \"factor\", \"numeric\", \"integer\", \"date\", \"datetime\"),\n                       ...) {\n  new_class <- match.arg(new_class, several.ok = TRUE)\n  stopifnot(length(new_class) == length(variable))\n  args <- list(...)\n  if (length(variable) > 1) {\n    for (i in seq_along(variable)) {\n      data <- convert_to(data, variable[i], new_class[i], ...)\n    }\n    return(data)\n  }\n  if (identical(new_class, \"character\")) {\n    data[[variable]] <- as.character(x = data[[variable]], ...)\n    attr(data, \"code_03_convert\") <- c(\n      attr(data, \"code_03_convert\"),\n      setNames(list(expr(as.character(!!sym(variable)))), variable)\n    )\n  } else if (identical(new_class, \"factor\")) {\n    data[[variable]] <- as.factor(x = data[[variable]])\n    attr(data, \"code_03_convert\") <- c(\n      attr(data, \"code_03_convert\"),\n      setNames(list(expr(as.factor(!!sym(variable)))), variable)\n    )\n  } else if (identical(new_class, \"numeric\")) {\n    data[[variable]] <- as.numeric(type.convert(data[[variable]], as.is = TRUE, ...))\n    attr(data, \"code_03_convert\") <- c(\n      attr(data, \"code_03_convert\"),\n      setNames(list(expr(as.numeric(!!sym(variable)))), variable)\n    )\n  } else if (identical(new_class, \"integer\")) {\n    data[[variable]] <- as.integer(x = data[[variable]], ...)\n    attr(data, \"code_03_convert\") <- c(\n      attr(data, \"code_03_convert\"),\n      setNames(list(expr(as.integer(!!sym(variable)))), variable)\n    )\n  } else if (identical(new_class, \"date\")) {\n    data[[variable]] <- as.Date(x = data[[variable]], ...)\n    attr(data, \"code_03_convert\") <- c(\n      attr(data, \"code_03_convert\"),\n      setNames(list(expr(as.Date(!!sym(variable), origin = !!args$origin))), variable)\n    )\n  } else if (identical(new_class, \"datetime\")) {\n    data[[variable]] <- as.POSIXct(x = data[[variable]], ...)\n    attr(data, \"code_03_convert\") <- c(\n      attr(data, \"code_03_convert\"),\n      setNames(list(expr(as.POSIXct(!!sym(variable)))), variable)\n    )\n  }\n  return(data)\n}\n\n\n\n\n\n\n\n\n#' Get variable(s) to convert\n#'\n#' @param vars Output of [summary_vars()]\n#' @param classes_input List of inputs containing new classes\n#'\n#' @return a `data.table`.\n#' @noRd\n#'\n#' @importFrom data.table data.table as.data.table\n#'\n#' @examples\n#' # 2 variables to convert\n#' new_classes <- list(\n#'   \"Sepal.Length\" = \"numeric\",\n#'   \"Sepal.Width\" = \"numeric\",\n#'   \"Petal.Length\" = \"character\",\n#'   \"Petal.Width\" = \"numeric\",\n#'   \"Species\" = \"character\"\n#' )\n#' get_vars_to_convert(summary_vars(iris), new_classes)\n#'\n#'\n#' # No changes\n#' new_classes <- list(\n#'   \"Sepal.Length\" = \"numeric\",\n#'   \"Sepal.Width\" = \"numeric\",\n#'   \"Petal.Length\" = \"numeric\",\n#'   \"Petal.Width\" = \"numeric\",\n#'   \"Species\" = \"factor\"\n#' )\n#' get_vars_to_convert(summary_vars(iris), new_classes)\n#'\n#' # Not set = NA or \"\"\n#' new_classes <- list(\n#'   \"Sepal.Length\" = NA,\n#'   \"Sepal.Width\" = NA,\n#'   \"Petal.Length\" = NA,\n#'   \"Petal.Width\" = NA,\n#'   \"Species\" = NA\n#' )\n#' get_vars_to_convert(summary_vars(iris), new_classes)\n#'\n#' # Set for one var\n#' new_classes <- list(\n#'   \"Sepal.Length\" = \"\",\n#'   \"Sepal.Width\" = \"\",\n#'   \"Petal.Length\" = \"\",\n#'   \"Petal.Width\" = \"\",\n#'   \"Species\" = \"character\"\n#' )\n#' get_vars_to_convert(summary_vars(iris), new_classes)\n#'\n#' new_classes <- list(\n#'   \"mpg\" = \"character\",\n#'   \"cyl\" = \"numeric\",\n#'   \"disp\" = \"character\",\n#'   \"hp\" = \"numeric\",\n#'   \"drat\" = \"character\",\n#'   \"wt\" = \"character\",\n#'   \"qsec\" = \"numeric\",\n#'   \"vs\" = \"character\",\n#'   \"am\" = \"numeric\",\n#'   \"gear\" = \"character\",\n#'   \"carb\" = \"integer\"\n#' )\n#' get_vars_to_convert(summary_vars(mtcars), new_classes)\nget_vars_to_convert <- function(vars, classes_input) {\n  vars <- as.data.table(vars)\n  classes_input <- data.table(\n    name = names(classes_input),\n    class_to_set = unlist(classes_input, use.names = FALSE),\n    stringsAsFactors = FALSE\n  )\n  classes_input <- classes_input[!is.na(class_to_set) & class_to_set != \"\"]\n  classes_df <- merge(x = vars, y = classes_input, by = \"name\")\n  classes_df <- classes_df[!is.na(class_to_set)]\n  classes_df[class != class_to_set]\n}\n"
  },
  {
    "path": "R/utils-shiny.R",
    "content": "\n#' @importFrom htmltools htmlDependency\n#' @importFrom utils packageVersion\nhtml_dependency_datamods <- function() {\n  htmlDependency(\n    name = \"datamods\",\n    version = packageVersion(\"datamods\"),\n    src = list(href = \"datamods\", file = \"assets\"),\n    package = \"datamods\",\n    script = \"js/datamods.js\",\n    stylesheet = \"css/datamods.css\"\n  )\n}\n\n\n#' Enable or disable a widget from server\n#'\n#' @param inputId Widget's inputId.\n#' @param enable Enable or disable the input.\n#' @param session Shiny session.\n#'\n#' @noRd\ntoggle_widget <- function(inputId,\n                        enable = TRUE,\n                        session = shiny::getDefaultReactiveDomain()) {\n  session$sendCustomMessage(\n    type = \"datamods-toggleWidget\",\n    message = list(id = session$ns(inputId), enable = enable)\n  )\n}\n\n\n#' Insert an alert into a placeholder in UI\n#'\n#' @param selector Id for alert, the placeholder maust have \\code{\"-placeholder\"} suffix.\n#' @param ... Arguments passed to \\code{shinyWidgets::alert}.\n#'\n#' @return No value.\n#' @noRd\n#'\n#' @importFrom shiny removeUI insertUI\n#' @importFrom shinyWidgets alert\n#'\ninsert_alert <- function(selector, ...) {\n  removeUI(selector = paste0(\"#\", selector, \"-result\"))\n  insertUI(\n    selector = paste0(\"#\", selector, \"-placeholder\"),\n    ui = alert(\n      id = paste0(selector, \"-result\"),\n      ...\n    )\n  )\n}\n\n\n\n\n\nshowUI <- function(selector = NULL,\n                   inline = FALSE,\n                   id = NULL,\n                   session = shiny::getDefaultReactiveDomain()) {\n  if (!is.null(id))\n    id <- session$ns(id)\n  session$sendCustomMessage(\n    type = \"datamods-showUI\",\n    message = dropNulls(list(\n      selector = selector,\n      inline = inline,\n      id = id\n    ))\n  )\n}\n\nhideUI <- function(selector = NULL,\n                   inline = FALSE,\n                   id = NULL,\n                   session = shiny::getDefaultReactiveDomain()) {\n  if (!is.null(id))\n    id <- session$ns(id)\n  session$sendCustomMessage(\n    type = \"datamods-hideUI\",\n    message = dropNulls(list(\n      selector = selector,\n      inline = inline,\n      id = id\n    ))\n  )\n}\n\n\nenable_tab <- function(id, value, session = shiny::getDefaultReactiveDomain()) {\n  session$sendCustomMessage(\n    type = \"datamods-enableTab\",\n    message = list(id = session$ns(id), value = value)\n  )\n}\n\ndisable_tab <- function(id, value, session = shiny::getDefaultReactiveDomain()) {\n  session$sendCustomMessage(\n    type = \"datamods-disableTab\",\n    message = list(id = session$ns(id), value = value)\n  )\n}\n\n#' @importFrom htmltools doRenderTags\nupdate_tab_label <- function(id, value, label, session = shiny::getDefaultReactiveDomain()) {\n  session$sendCustomMessage(\n    type = \"datamods-updateTabLabel\",\n    message = list(id = session$ns(id), value = value, label = doRenderTags(label))\n  )\n}\n\n\n#' @importFrom htmltools tagList tags\n#' @importFrom shiny icon getDefaultReactiveDomain\nmake_success_alert <- function(data,\n                               trigger_return,\n                               btn_show_data,\n                               extra = NULL,\n                               session = shiny::getDefaultReactiveDomain()) {\n  if (identical(trigger_return, \"button\")) {\n    success_message <- tagList(\n      tags$b(phosphoricons::ph(\"check\", weight = \"bold\"), i18n(\"Data ready to be imported!\")),\n      sprintf(\n        i18n(\"data has %s obs. of %s variables.\"),\n        nrow(data), ncol(data)\n      ),\n      extra\n    )\n  } else {\n    success_message <- tagList(\n      tags$b(phosphoricons::ph(\"check\", weight = \"bold\"), i18n(\"Data successfully imported!\")),\n      sprintf(\n        i18n(\"data has %s obs. of %s variables.\"),\n        nrow(data), ncol(data)\n      ),\n      extra\n    )\n  }\n  if (isTRUE(btn_show_data)) {\n    success_message <- tagList(\n      success_message,\n      tags$br(),\n      actionLink(\n        inputId = session$ns(\"see_data\"),\n        label = tagList(phosphoricons::ph(\"table\"), i18n(\"click to see data\"))\n      )\n    )\n  }\n  return(success_message)\n}\n\ninsert_error <- function(mssg = i18n(\"Something went wrong...\"),\n                         selector = \"import\",\n                         session = shiny::getDefaultReactiveDomain()) {\n  insert_alert(\n    selector = session$ns(selector),\n    status = \"danger\",\n    tags$b(phosphoricons::ph(\"warning\"), i18n(\"Ooops\")),\n    mssg\n  )\n}\n\n\n#' @importFrom htmltools tagList tags doRenderTags\nhelp_popup <- function(text) {\n  tagList(\n    tags$span(\n      phosphoricons::ph(\"question\", title = i18n(\"Help\")),\n      `data-toggle` = \"popover\",\n      `data-trigger` = \"focus\",\n      title = i18n(\"Help\"),\n      `data-html` = \"true\",\n      `data-content` = htmltools::doRenderTags(text),\n      tabindex = \"0\",\n      role = \"button\"\n    ),\n    tags$script(\n      \"$(function () { $(\\'[data-toggle=\\\"popover\\\"]\\').popover({container: 'body'}); })\"\n    )\n  )\n}\n\n#' @importFrom shiny actionButton icon getDefaultReactiveDomain\nbutton_import <- function(session = shiny::getDefaultReactiveDomain()) {\n  actionButton(\n    inputId = session$ns(\"confirm\"),\n    label = tagList(\n      phosphoricons::ph(\"arrow-circle-right\", title = i18n(\"Import data\")),\n      i18n(\"Import data\")\n    ),\n    width = \"100%\",\n    disabled = \"disabled\",\n    class = \"btn-primary\",\n    `aria-label` = i18n(\"Import data\")\n  )\n}\n\n\n\nbutton_close_modal <- function() {\n  tags$button(\n    phosphoricons::ph(\"x\", title = i18n(\"Close\"), height = \"2em\"),\n    class = \"btn btn-link\",\n    style = css(border = \"0 none\", position = \"absolute\", top = \"5px\", right = \"5px\"),\n    `data-dismiss` = \"modal\",\n    `data-bs-dismiss` = \"modal\",\n    `aria-label` = i18n(\"Close\")\n  )\n}\n\n\n#' @importFrom bslib bs_current_theme is_bs_theme bs_get_variables\nget_primary_color <- function() {\n  theme <- bslib::bs_current_theme()\n  if (!bslib::is_bs_theme(theme)) {\n    return(\"#112466\")\n  }\n  primary <- bslib::bs_get_variables(theme, \"primary\")\n  unname(primary)\n}\n\n"
  },
  {
    "path": "R/utils.R",
    "content": "`%||%` <- function(x, y) {\n  if (is.null(x))\n    y\n  else x\n}\n\ndropNulls <- function(x) {\n  x[!vapply(x, is.null, FUN.VALUE = logical(1))]\n}\n\ndropNullsOrEmpty <- function(x) {\n  x[!vapply(x, nullOrEmpty, FUN.VALUE = logical(1))]\n}\n\nnullOrEmpty <- function(x) {\n  is.null(x) || length(x) == 0 || x == \"\"\n}\n\n#' @importFrom data.table .SD\ndropListColumns <- function(x) {\n  type_col <- vapply(\n    X = x,\n    FUN = typeof,\n    FUN.VALUE = character(1),\n    USE.NAMES = FALSE\n  )\n  if (inherits(x, \"data.table\")) {\n    x[, .SD, .SDcols = type_col != \"list\"]\n  } else {\n    x[, type_col != \"list\", drop = FALSE]\n  }\n}\n\n\n#' Search for object with specific class in an environment\n#'\n#' @param what a class to look for\n#' @param env An environment\n#'\n#' @return Character vector of the names of objects, NULL if none\n#' @noRd\n#'\n#' @examples\n#'\n#' # NULL if no data.frame\n#' search_obj(\"data.frame\")\n#'\n#' library(ggplot2)\n#' data(\"mpg\")\n#' search_obj(\"data.frame\")\n#'\n#'\n#' gg <- ggplot()\n#' search_obj(\"ggplot\")\n#'\nsearch_obj <- function(what = \"data.frame\", env = globalenv()) {\n  all <- ls(name = env)\n  objs <- lapply(\n    X = all,\n    FUN = function(x) {\n      if (inherits(get(x, envir = env), what = what)) {\n        x\n      } else {\n        NULL\n      }\n    }\n  )\n  objs <- unlist(objs)\n  if (length(objs) == 1 && objs == \"\") {\n    NULL\n  } else {\n    objs\n  }\n}\n\n\n\n\n#' @importFrom data.table as.data.table\n#' @importFrom tibble as_tibble\nas_out <- function(x, return_class = c(\"data.frame\", \"data.table\", \"tbl_df\", \"raw\")) {\n  if (is.null(x))\n    return(NULL)\n  return_class <- match.arg(return_class)\n  if (identical(return_class, \"raw\"))\n    return(x)\n  is_sf <- inherits(x, \"sf\")\n  x <- if (identical(return_class, \"data.frame\")) {\n    as.data.frame(x)\n  } else if (identical(return_class, \"data.table\")) {\n    as.data.table(x)\n  } else {\n    as_tibble(x)\n  }\n  if (is_sf)\n    class(x) <- c(\"sf\", class(x))\n  return(x)\n}\n\n\ngenId <- function(bytes = 12) {\n  paste(format(as.hexmode(sample(256, bytes, replace = TRUE) - 1), width = 2), collapse = \"\")\n}\n\nmakeId <- function(x) {\n  if (length(x) < 1)\n    return(NULL)\n  x <- as.character(x)\n  x <- lapply(X = x, FUN = function(y) {\n    paste(as.character(charToRaw(y)), collapse = \"\")\n  })\n  x <- unlist(x, use.names = FALSE)\n  make.unique(x, sep = \"_\")\n}\n\n\n`%inT%` <- function(x, table) {\n  if (!is.null(table) && ! \"\" %in% table) {\n    x %in% table\n  } else {\n    rep_len(TRUE, length(x))\n  }\n}\n\n\n\n`%inF%` <- function(x, table) {\n  if (!is.null(table) && ! \"\" %in% table) {\n    x %in% table\n  } else {\n    rep_len(FALSE, length(x))\n  }\n}\n\n#' @importFrom utils hasName\nheader_with_classes <- function(data) {\n  function(value) {\n    if (!hasName(data, value))\n      return(\"\")\n    classes <- tags$div(\n      style = \"font-style: italic; font-weight: normal; font-size: small;\",\n      get_classes(data[, value, drop = FALSE])\n    )\n    tags$div(title = value, value, classes)\n  }\n}\n\n\nsplit_char <- function(x, split = \",\") {\n  if (is.null(x))\n    return(NULL)\n  unlist(strsplit(x, split = split))\n}\n\n\n\napply_grid_theme <- function() {\n  toastui::set_grid_theme(\n    cell.normal.background = \"#FFF\",\n    cell.normal.border = \"#D8DEE9\",\n    cell.normal.showVerticalBorder = TRUE,\n    cell.normal.showHorizontalBorder = TRUE,\n    cell.header.border = \"#D8DEE9\",\n    area.header.border = \"#4C566A\",\n    cell.summary.border = \"#D8DEE9\",\n    cell.summary.showVerticalBorder = TRUE,\n    cell.summary.showHorizontalBorder = TRUE\n  )\n}\n"
  },
  {
    "path": "R/validation.R",
    "content": "\n#' @title Validation module\n#'\n#' @description Check that a dataset respect some validation expectations.\n#'\n#' @param id Module's ID.\n#' @param display Display validation results in a dropdown menu\n#'  by clicking on a button or display results directly in interface.\n#' @param max_height Maximum height for validation results element, useful if you have many rules.\n#' @param ... Arguments passed to \\code{actionButton} or \\code{uiOutput} depending on display mode,\n#'  you cannot use \\code{inputId}/\\code{outputId}, \\code{label} or \\code{icon} (button only).\n#'\n#' @return\n#'  * UI: HTML tags that can be included in shiny's UI\n#'  * Server: a \\code{list} with two slots:\n#'    + **status**: a \\code{reactive} function returning the best status available between \\code{\"OK\"}, \\code{\"Failed\"} or \\code{\"Error\"}.\n#'    + **details**: a \\code{reactive} function returning a \\code{list} with validation details.\n#' @export\n#'\n#' @importFrom shiny NS actionButton icon uiOutput\n#' @importFrom htmltools tagList validateCssUnit\n#' @importFrom shinyWidgets dropMenu\n#'\n#' @rdname validation\n#'\n#' @example examples/validation.R\nvalidation_ui <- function(id, display = c(\"dropdown\", \"inline\"), max_height = NULL, ...) {\n  ns <- NS(id)\n  display <- match.arg(display)\n  max_height <- if (!is.null(max_height)) {\n    paste0(\"overflow-y: auto; max-height:\", validateCssUnit(max_height), \";\")\n  }\n  if (identical(display, \"dropdown\")) {\n    ui <- dropMenu(\n      actionButton(\n        inputId = ns(\"menu\"),\n        label = tagList(\n          phosphoricons::ph(\"caret-down\", weight = \"fill\", title = i18n(\"Validation:\")),\n          i18n(\"Validation:\")\n        ),\n        ...\n      ),\n      uiOutput(\n        outputId = ns(\"results\"),\n        style = \"width: 300px;\",\n        style = max_height\n      )\n    )\n  } else {\n    ui <- uiOutput(\n      outputId = ns(\"results\"),\n      ...,\n      style = max_height\n    )\n  }\n  tagList(\n    ui, html_dependency_datamods()\n  )\n}\n\n#' @export\n#'\n#' @param data a \\code{reactive} function returning a \\code{data.frame}.\n#' @param n_row,n_col A one-sided formula to check number of rows and columns respectively, see below for examples.\n#' @param n_row_label,n_col_label Text to be displayed with the result of the check for number of rows/columns.\n#' @param btn_label Label for the dropdown button, will be followed by validation result.\n#' @param rules An object of class \\code{validator} created with \\code{validate::validator}.\n#' @param bs_version Bootstrap version used, it may affect rendering, especially status badges.\n#'\n#' @rdname validation\n#'\n#' @importFrom shiny moduleServer reactiveValues observeEvent updateActionButton renderUI reactive\n#' @importFrom htmltools doRenderTags tags tagList\nvalidation_server <- function(id,\n                              data,\n                              n_row = NULL,\n                              n_col = NULL,\n                              n_row_label = i18n(\"Valid number of rows\"),\n                              n_col_label = i18n(\"Valid number of columns\"),\n                              btn_label = i18n(\"Dataset validation:\"),\n                              rules = NULL,\n                              bs_version = 3) {\n  moduleServer(\n    id = id,\n    module = function(input, output, session) {\n\n      valid_ui <- reactiveValues(x = NULL)\n\n      valid_rv <- reactiveValues(status = NULL, details = NULL)\n\n      observeEvent(data(), {\n        to_validate <- data()\n        valid_dims <- check_data(to_validate, n_row = n_row, n_col = n_col)\n\n        if (all(c(valid_dims$nrows, valid_dims$ncols))) {\n          valid_status <- \"OK\"\n        } else {\n          valid_status <- \"Failed\"\n        }\n\n        valid_results <- lapply(\n          X = c(\"nrows\", \"ncols\"),\n          FUN = function(x) {\n            if (is.null(valid_dims[[x]]))\n              return(NULL)\n            label <- switch(\n              x,\n              \"nrows\" = n_row_label,\n              \"ncols\" = n_col_label\n            )\n            list(\n              status = ifelse(valid_dims[[x]], \"OK\", \"Failed\"),\n              label = paste0(\"<b>\", label, \"</b>\")\n            )\n          }\n        )\n\n        if (!is.null(rules) && inherits(rules, \"validator\")) {\n          validate_results <- validate::confront(to_validate, rules)\n          validate_results <- validate::summary(validate_results)\n          validate_results <- merge(\n            x = validate_results,\n            y = validate::as.data.frame(rules),\n            by = \"name\"\n          )\n          # validate_results <- format_validate(validate_results)\n          if (any(validate_results$error)) {\n            valid_status <- \"Error\"\n          } else if (any(validate_results$fails > 0)) {\n            valid_status <- \"Failed\"\n          }\n          valid_results <- c(\n            valid_results,\n            format_validate(validate_results)\n          )\n        }\n\n        if (identical(valid_status, \"OK\")) {\n          label <- doRenderTags(tagList(\n            btn_label,\n            tags$span(\n              class = badge_class(bs_version, \"success\"),\n              phosphoricons::ph(\"check\", weight = \"bold\", title = i18n(\"OK\")),\n              i18n(\"OK\")\n            )\n          ))\n        } else if (identical(valid_status, \"Failed\")) {\n          label <- doRenderTags(tagList(\n            btn_label,\n            tags$span(\n              class = badge_class(bs_version, \"warning\"),\n              phosphoricons::ph(\"warning\", weight = \"bold\", title = i18n(\"Failed\")),\n              i18n(\"Failed\")\n            )\n          ))\n        } else if (identical(valid_status, \"Error\")) {\n          label <- doRenderTags(tagList(\n            btn_label,\n            tags$span(\n              class = badge_class(bs_version, \"danger\"),\n              phosphoricons::ph(\"x\", weight = \"bold\", title = i18n(\"Error\")),\n              i18n(\"Error\")\n            )\n          ))\n        }\n        updateActionButton(session = session, inputId = \"menu\", label = label)\n\n        valid_results <- dropNulls(valid_results)\n\n        total <- unlist(lapply(valid_results, `[[`, \"status\"))\n\n        header <- tags$div(\n          class = \"datamods-validation-results\",\n          tags$div(\n            class = \"datamods-validation-summary\",\n            style = \"border-right: 1px solid #e6e6e6;\",\n            tags$span(\n              class = badge_class(bs_version, \"success\"),\n              i18n(\"OK\"),\n              tags$span(sum(total == \"OK\"), class = \"datamods-validation-item\")\n            )\n          ),\n          tags$div(\n            class = \"datamods-validation-summary\",\n            style = \"border-right: 1px solid #e6e6e6;\",\n            tags$span(\n              class = badge_class(bs_version, \"warning\"),\n              i18n(\"Failed\"),\n              tags$span(sum(total == \"Failed\"), class = \"datamods-validation-item\")\n            )\n          ),\n          tags$div(\n            class = \"datamods-validation-summary\",\n            tags$span(\n              class = badge_class(bs_version, \"danger\"),\n              i18n(\"Error\"),\n              tags$span(sum(total == \"Error\"), class = \"datamods-validation-item\")\n            )\n          )\n        )\n\n        valid_ui$x <- tagList(\n          header,\n          tags$br(),\n          make_validation_alerts(valid_results)\n        )\n\n        valid_rv$status <- valid_status\n        valid_rv$details <- valid_results\n      })\n\n      output$results <- renderUI({\n        valid_ui$x\n      })\n\n      return(list(\n        status = reactive(valid_rv$status),\n        details = reactive(valid_rv$details)\n      ))\n    }\n  )\n}\n\n#' @importFrom rlang as_label as_function enquo\ncheck_fun <- function(fun, what) {\n  label <- as_label(enquo(what))\n  if (inherits(fun, \"formula\")) {\n    fun <- as_function(fun)\n    result <- try(fun(what))\n    if (inherits(result, \"try-error\") | !is.logical(result)) {\n      warning(\"Checking \", label, \" must return a logical\", call. = FALSE)\n      return(FALSE)\n    }\n  } else {\n    result <- NULL\n  }\n  return(result)\n}\n\ncheck_data <- function(data, n_row = NULL, n_col = NULL) {\n  list(\n    nrows = check_fun(n_row, nrow(data)),\n    ncols = check_fun(n_col, ncol(data))\n  )\n}\n\n\n#' @importFrom shiny icon\n#' @importFrom shinyWidgets alert\n#' @importFrom htmltools HTML\nmake_validation_alerts <- function(.list) {\n  lapply(\n    X = .list,\n    FUN = function(x) {\n      icon <- switch(\n        x$status,\n        \"OK\" = phosphoricons::ph(\"check\", title = i18n(\"OK\")),\n        \"Failed\" = phosphoricons::ph(\"warning\", title = i18n(\"Failed\")),\n        \"Error\" = phosphoricons::ph(\"x\", title = i18n(\"Error\"))\n      )\n      status <- switch(\n        x$status,\n        \"OK\" = \"success\",\n        \"Failed\" = \"warning\",\n        \"Error\" = \"danger\",\n        \"info\"\n      )\n      alert(\n        icon, HTML(x$label),\n        status = status,\n        style = \"margin-bottom: 10px; padding: 10px;\"\n      )\n    }\n  )\n}\n\n\nformat_validate <- function(data) {\n  lapply(\n    X = seq_len(nrow(data)),\n    FUN = function(i) {\n      res <- data[i, ]\n      if (isTRUE(res$error)) {\n        status <- \"Error\"\n      } else {\n        if (res$fails > 0) {\n          status <- \"Failed\"\n        } else {\n          status <- \"OK\"\n        }\n      }\n      if (!is.null(res$label)) {\n        label <- paste0(\"<b>\", res$label, \"</b>\")\n        if (!is.null(res$description) && nzchar(res$description)) {\n          label <- paste(label, res$description, sep = \": \")\n        }\n      } else {\n        label <- res$name\n      }\n      if (identical(status, \"Failed\")) {\n        label <- paste0(label, \"| failed: \", res$fails, \" / \", res$items)\n      }\n      list(\n        status = status,\n        label = label,\n        summary = res\n      )\n    }\n  )\n}\n\n\nbadge_class <- function(bs_version, status) {\n  if (!is.numeric(bs_version))\n    stop(\"`bs_version` must be a numeric.\")\n  if (bs_version <= 3) {\n    paste0(\"label label-\", status)\n  } else {\n    sprintf(\"badge badge-%1$s bg-%1$s\", status)\n  }\n}\n\n\n"
  },
  {
    "path": "R/zzz.R",
    "content": "\nutils::globalVariables(c(\n  \"%>%\", \"filter\", \"group_by\", \"label\", \"translation\",\n  \".datamods_edit_update\", \".datamods_edit_delete\", \".datamods_id\",\n  \"..var_edit\", \"..vars_datamods_edit\",\n  \"select\", \"any_of\", \"rename\",\n  \"class_to_set\"\n))\n"
  },
  {
    "path": "README.Rmd",
    "content": "---\noutput: github_document\n---\n\n<!-- README.md is generated from README.Rmd. Please edit that file -->\n\n```{r, include = FALSE}\nknitr::opts_chunk$set(\n  collapse = TRUE,\n  comment = \"#>\",\n  fig.path = \"man/figures/README-\",\n  out.width = \"100%\"\n)\n```\n\n# datamods\n\n> Shiny modules to import and manipulate data into an application or addin.\n\n<!-- badges: start -->\n[![CRAN status](https://www.r-pkg.org/badges/version/datamods)](https://CRAN.R-project.org/package=datamods)\n[![cranlogs](https://cranlogs.r-pkg.org/badges/datamods)](https://cran.r-project.org/package=datamods)\n[![R-CMD-check](https://github.com/dreamRs/datamods/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/dreamRs/datamods/actions/workflows/R-CMD-check.yaml)\n[![Codecov test coverage](https://codecov.io/gh/dreamRs/datamods/graph/badge.svg)](https://app.codecov.io/gh/dreamRs/datamods)\n<!-- badges: end -->\n\n\n### Overview\n\nThis package provides custom shiny modules to import data from various sources, select, rename and convert variables in a dataset and validate content with [validate](https://github.com/data-cleaning/validate) package.  \nThe modules can be used in any standard shiny application or RStudio add-in.\n\n\n### Internationalization\n\n```{r, include=FALSE}\ni18n_flag <- function(code, language) {\n  code <- strsplit(code, split = \"|\", fixed = TRUE)[[1]]\n  flag <- sprintf(\"<img src=\\\"man/figures/i18n/%s.svg\\\" height=\\\"16\\\" style=\\\"height:16px\\\"/>\", code)\n  paste(paste(flag, collapse = \"\"), language)\n}\ni18n_flags <- function(languages) {\n  mapply(\n    FUN = i18n_flag, \n    code = names(languages),\n    language = unlist(languages, use.names = FALSE),\n    USE.NAMES = FALSE\n  )\n}\nlanguages <- list(\n  gb = \"english (default)\",\n  fr = \"french\",\n  mk = \"macedonian\",\n  \"br|pt\" = \"brazilian portuguese\",\n  al = \"albanian\",\n  cn = \"chinese\",\n  es = \"spanish\",\n  de = \"german\",\n  tr = \"turkish\",\n  kr = \"korean\",\n  pl = \"polish\",\n  ja = \"japanese\"\n)\n```\n\n\nCurrently you can use {datamods} in the following language: `r i18n_flags(languages)`.\n\nIf you want another language to be supported, you can submit a Pull Request to add a CSV file like the one used for french (file is located in `inst/i18n` folder in the package, you can see it [here on GitHub](https://github.com/dreamRs/datamods/blob/master/inst/i18n/fr.csv)).\n\nSee the [online vignette](https://dreamrs.github.io/datamods/articles/i18n.html) for more on this topic.\n\n\n### Installation\n\nInstall from [CRAN](https://CRAN.R-project.org/package=datamods) with:\n\n```r\ninstall.packages(\"datamods\")\n```\n\nYou can install the development version of datamods from [GitHub](https://github.com/dreamRs/datamods) with:\n\n```r\nremotes::install_github(\"dreamRs/datamods\")\n```\n\n\n### Import\n\nImport data from:\n\n* **environment**: such as Global environment or from a package\n* **file**: text files, Excel, SAS or SPSS format... anything that package [rio](https://github.com/gesistsa/rio#supported-file-formats) can handle\n* **copy/paste**: paste data from an other source like Excel or text file\n* **Google Sheet**: use the URL to import the Googlesheet\n* **URL**: use a URL to import from a flat table\n\nEach module is available in the form `import_file_ui()` / `import_file_server()` and can be use independently.\n\nOr all modules can be launched together in a modal window via `import_modal()` / `import_server()`:\n\n![](man/figures/datamods-modal.png)\n\nThis module also allow to view imported data and to update variables.\n\n\n### Update\n\nModule `update_variables_ui()` / `update_variables_server()` allow to:\n\n* **select** variables of interest in a dataset\n* **rename** variables to be used in application after that\n* **convert** variables to change their class, from character to numeric for example\n\n![](man/figures/datamods-update.png)\n\n\n### Validate\n\nDefine some validation rules with package [validate](https://github.com/data-cleaning/validate) and check whether data lives up to those expectations.\n\n![](man/figures/datamods-validation.png)\n\n\n### Filter\n\nInteractively filter a `data.frame`, this module also generates the code to reproduce the filters.\n\n![](man/figures/datamods-filter.png)\n\n\n### Sample\n\nThis module extracts a sample from a `data.frame`, based either on a fixed number of rows or on a percentage of total rows.\n\n![](man/figures/datamods-sample.png)\n\n### Edit\n\nThis module makes a `data.frame` editable, allowing the user to add, modify or delete rows.\n\n![](man/figures/datamods-edit-data.png)\n\n\n### Create column\n\nThis module allow to enter an expression to create a new column in a `data.frame`.\n\n![](man/figures/create_column.png)\n\n\n\n### Cut numeric variable\n\nThis module contain an interface to cut a numeric into several intervals.\n\n![](man/figures/cut_variable.png)\n\n\n\n\n\n\n### Update factor\n\nThis module contain an interface to reorder the levels of a factor variable.\n\n![](man/figures/update_factor.png)\n\n\n"
  },
  {
    "path": "README.md",
    "content": "\n<!-- README.md is generated from README.Rmd. Please edit that file -->\n\n# datamods\n\n> Shiny modules to import and manipulate data into an application or\n> addin.\n\n<!-- badges: start -->\n\n[![CRAN\nstatus](https://www.r-pkg.org/badges/version/datamods)](https://CRAN.R-project.org/package=datamods)\n[![cranlogs](https://cranlogs.r-pkg.org/badges/datamods)](https://cran.r-project.org/package=datamods)\n[![R-CMD-check](https://github.com/dreamRs/datamods/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/dreamRs/datamods/actions/workflows/R-CMD-check.yaml)\n[![Codecov test\ncoverage](https://codecov.io/gh/dreamRs/datamods/graph/badge.svg)](https://app.codecov.io/gh/dreamRs/datamods)\n<!-- badges: end -->\n\n### Overview\n\nThis package provides custom shiny modules to import data from various\nsources, select, rename and convert variables in a dataset and validate\ncontent with [validate](https://github.com/data-cleaning/validate)\npackage.  \nThe modules can be used in any standard shiny application or RStudio\nadd-in.\n\n### Internationalization\n\nCurrently you can use {datamods} in the following language:\n<img src=\"man/figures/i18n/gb.svg\" height=\"16\" style=\"height:16px\"/>\nenglish (default),\n<img src=\"man/figures/i18n/fr.svg\" height=\"16\" style=\"height:16px\"/>\nfrench,\n<img src=\"man/figures/i18n/mk.svg\" height=\"16\" style=\"height:16px\"/>\nmacedonian,\n<img src=\"man/figures/i18n/br.svg\" height=\"16\" style=\"height:16px\"/><img src=\"man/figures/i18n/pt.svg\" height=\"16\" style=\"height:16px\"/>\nbrazilian portuguese,\n<img src=\"man/figures/i18n/al.svg\" height=\"16\" style=\"height:16px\"/>\nalbanian,\n<img src=\"man/figures/i18n/cn.svg\" height=\"16\" style=\"height:16px\"/>\nchinese,\n<img src=\"man/figures/i18n/es.svg\" height=\"16\" style=\"height:16px\"/>\nspanish,\n<img src=\"man/figures/i18n/de.svg\" height=\"16\" style=\"height:16px\"/>\ngerman,\n<img src=\"man/figures/i18n/tr.svg\" height=\"16\" style=\"height:16px\"/>\nturkish,\n<img src=\"man/figures/i18n/kr.svg\" height=\"16\" style=\"height:16px\"/>\nkorean,\n<img src=\"man/figures/i18n/pl.svg\" height=\"16\" style=\"height:16px\"/>\npolish,\n<img src=\"man/figures/i18n/ja.svg\" height=\"16\" style=\"height:16px\"/>\njapanese.\n\nIf you want another language to be supported, you can submit a Pull\nRequest to add a CSV file like the one used for french (file is located\nin `inst/i18n` folder in the package, you can see it [here on\nGitHub](https://github.com/dreamRs/datamods/blob/master/inst/i18n/fr.csv)).\n\nSee the [online\nvignette](https://dreamrs.github.io/datamods/articles/i18n.html) for\nmore on this topic.\n\n### Installation\n\nInstall from [CRAN](https://CRAN.R-project.org/package=datamods) with:\n\n``` r\ninstall.packages(\"datamods\")\n```\n\nYou can install the development version of datamods from\n[GitHub](https://github.com/dreamRs/datamods) with:\n\n``` r\nremotes::install_github(\"dreamRs/datamods\")\n```\n\n### Import\n\nImport data from:\n\n- **environment**: such as Global environment or from a package\n- **file**: text files, Excel, SAS or SPSS format… anything that package\n  [rio](https://github.com/gesistsa/rio#supported-file-formats) can\n  handle\n- **copy/paste**: paste data from an other source like Excel or text\n  file\n- **Google Sheet**: use the URL to import the Googlesheet\n- **URL**: use a URL to import from a flat table\n\nEach module is available in the form `import_file_ui()` /\n`import_file_server()` and can be use independently.\n\nOr all modules can be launched together in a modal window via\n`import_modal()` / `import_server()`:\n\n![](man/figures/datamods-modal.png)\n\nThis module also allow to view imported data and to update variables.\n\n### Update\n\nModule `update_variables_ui()` / `update_variables_server()` allow to:\n\n- **select** variables of interest in a dataset\n- **rename** variables to be used in application after that\n- **convert** variables to change their class, from character to numeric\n  for example\n\n![](man/figures/datamods-update.png)\n\n### Validate\n\nDefine some validation rules with package\n[validate](https://github.com/data-cleaning/validate) and check whether\ndata lives up to those expectations.\n\n![](man/figures/datamods-validation.png)\n\n### Filter\n\nInteractively filter a `data.frame`, this module also generates the code\nto reproduce the filters.\n\n![](man/figures/datamods-filter.png)\n\n### Sample\n\nThis module extracts a sample from a `data.frame`, based either on a\nfixed number of rows or on a percentage of total rows.\n\n![](man/figures/datamods-sample.png)\n\n### Edit\n\nThis module makes a `data.frame` editable, allowing the user to add,\nmodify or delete rows.\n\n![](man/figures/datamods-edit-data.png)\n\n### Create column\n\nThis module allow to enter an expression to create a new column in a\n`data.frame`.\n\n![](man/figures/create_column.png)\n\n### Cut numeric variable\n\nThis module contain an interface to cut a numeric into several\nintervals.\n\n![](man/figures/cut_variable.png)\n\n### Update factor\n\nThis module contain an interface to reorder the levels of a factor\nvariable.\n\n![](man/figures/update_factor.png)\n"
  },
  {
    "path": "_pkgdown.yml",
    "content": "url: https://dreamrs.github.io/datamods\n\ntemplate:\n  bootstrap: 5\n  bootswatch: zephyr\n  bslib:\n    base_font: {google: \"Poppins\"}\n    primary: \"#112446\"\n\nnavbar:\n  bg: primary\n\nauthors:\n  Victor Perrier:\n    href: https://twitter.com/_pvictorr\n    html: <img src=\"https://pbs.twimg.com/profile_images/844237339404722177/E1U61aM8_normal.jpg\"/> Victor Perrier\n  Fanny Meyer:\n    href: https://twitter.com/_mfaan\n    html: <img src=\"https://pbs.twimg.com/profile_images/912313931326218240/o1-wvA18_normal.jpg\" /> Fanny Meyer\n  Zauad Shahreer Abeer:\n    href: https://twitter.com/shahreyarabeer\n    html: <img src=\"http://pbs.twimg.com/profile_images/1272445553503113217/RUViNXpI_normal.jpg\" /> Zauad Shahreer Abeer\n"
  },
  {
    "path": "cran-comments.md",
    "content": "## Test environments\n* local R installation, R 4.4.1\n* ubuntu 22.04, Windows 10, macOS (on GitHub Actions), R 4.4.1\n* win-builder (devel)\n\n## R CMD check results\n\n0 errors | 0 warnings | 0 note\n\nThanks,\n\nVictor\n"
  },
  {
    "path": "data-raw/demo_edit.R",
    "content": "## code to prepare `demo_edit` dataset goes here\n\n#library(charlatan)\ndemo_edit <- data.frame(\n  \"name\" = ch_name(n = 20),\n  \"job\" = ch_job(n = 20),\n  \"credit card provider\" = as.factor(ch_credit_card_provider(n = 20)),\n  \"credit card security code\" = as.numeric(ch_credit_card_security_code(n = 20)),\n  \"date obtained\" = sample(seq(as.Date('2015/01/01'), as.Date('2022/01/01'), by = \"year\"), 20, replace = TRUE),\n  \"contactless card\" = sample(c(TRUE, FALSE), 20, replace = TRUE)\n)\ndemo_edit <- janitor::clean_names(demo_edit)\n\nusethis::use_data(demo_edit, overwrite = TRUE)\n"
  },
  {
    "path": "examples/create_column.R",
    "content": "\nlibrary(shiny)\nlibrary(datamods)\nlibrary(reactable)\n\nui <- fluidPage(\n  theme = bslib::bs_theme(version = 5L, preset = \"bootstrap\"),\n  shinyWidgets::html_dependency_winbox(),\n  tags$h2(\"Create new column\"),\n  fluidRow(\n    column(\n      width = 4,\n      create_column_ui(\"inline\"),\n      actionButton(\"modal\", \"Or click here to open a modal to create a column\"),\n      tags$br(), tags$br(),\n      actionButton(\"winbox\", \"Or click here to open a WinBox to create a column\")\n    ),\n    column(\n      width = 8,\n      reactableOutput(outputId = \"table\"),\n      verbatimTextOutput(\"code\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  rv <- reactiveValues(data = MASS::Cars93[, c(1, 3, 4, 5, 6, 10)])\n\n  # inline mode\n  data_inline_r <- create_column_server(\n    id = \"inline\",\n    data_r = reactive(rv$data)\n  )\n  observeEvent(data_inline_r(), rv$data <- data_inline_r())\n\n  # modal window mode\n  observeEvent(input$modal, modal_create_column(\"modal\"))\n  data_modal_r <- create_column_server(\n    id = \"modal\",\n    data_r = reactive(rv$data)\n  )\n  observeEvent(data_modal_r(), rv$data <- data_modal_r())\n\n  # WinBox window mode\n  observeEvent(input$winbox, winbox_create_column(\"winbox\"))\n  data_winbox_r <- create_column_server(\n    id = \"winbox\",\n    data_r = reactive(rv$data)\n  )\n  observeEvent(data_winbox_r(), rv$data <- data_winbox_r())\n\n  # Show result\n  output$table <- renderReactable({\n    data <- req(rv$data)\n    reactable(\n      data = data,\n      bordered = TRUE,\n      compact = TRUE,\n      striped = TRUE\n    )\n  })\n\n  output$code <- renderPrint({\n    attr(rv$data, \"code\")\n  })\n}\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "examples/cut_variable.R",
    "content": "\nlibrary(shiny)\nlibrary(datamods)\nlibrary(reactable)\n\nui <- fluidPage(\n  theme = bslib::bs_theme(version = 5L, preset = \"bootstrap\"),\n  shinyWidgets::html_dependency_winbox(),\n  tags$h2(\"Convert Numeric to Factor\"),\n  fluidRow(\n    column(\n      width = 6,\n      cut_variable_ui(\"inline\"),\n      actionButton(\"modal\", \"Or click here to open a modal to cut a variable\"),\n      tags$br(), tags$br(),\n      actionButton(\"winbox\", \"Or click here to open a WinBox to cut a variable\")\n    ),\n    column(\n      width = 6,\n      reactableOutput(outputId = \"table\"),\n      verbatimTextOutput(\"code\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  rv <- reactiveValues(data = MASS::Cars93[, c(1, 3, 4, 5, 6, 10)])\n\n  # inline mode\n  data_inline_r <- cut_variable_server(\n    id = \"inline\",\n    data_r = reactive(rv$data)\n  )\n  observeEvent(data_inline_r(), rv$data <- data_inline_r())\n\n  # modal window mode\n  observeEvent(input$modal, modal_cut_variable(\"modal\"))\n  data_modal_r <- cut_variable_server(\n    id = \"modal\",\n    data_r = reactive(rv$data)\n  )\n  observeEvent(data_modal_r(), rv$data <- data_modal_r())\n\n  # WinBox window mode\n  observeEvent(input$winbox, winbox_cut_variable(\"winbox\"))\n  data_winbox_r <- cut_variable_server(\n    id = \"winbox\",\n    data_r = reactive(rv$data)\n  )\n  observeEvent(data_winbox_r(), rv$data <- data_winbox_r())\n\n  # Show result\n  output$table <- renderReactable({\n    data <- req(rv$data)\n    reactable(\n      data = data,\n      bordered = TRUE,\n      compact = TRUE,\n      striped = TRUE\n    )\n  })\n\n  output$code <- renderPrint({\n    attr(rv$data, \"code\")\n  })\n}\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "examples/edit_data-callback.R",
    "content": "\n# -------------------------------------------------------------------------\n# Edit data only with callbacks -------------------------------------------\n# -------------------------------------------------------------------------\n\n\n\n# Packages ----------------------------------------------------------------\n\nlibrary(data.table)\nlibrary(datamods)\nlibrary(shiny)\nlibrary(bslib)\nlibrary(shinybusy)\nlibrary(reactable)\n\n\n\n# Fake data ---------------------------------------------------------------\n\nmydata <- charlatan::ch_generate()\nsetDT(mydata)\nmydata[, ID := seq_len(.N)] # internal ID\nmydata[, user := paste0(\"user\", seq_len(.N))]\nsetcolorder(mydata, c(\"ID\", \"user\"))\n\npath_to_data <- tempfile(pattern = \"mydata\", fileext = \".rds\")\nsaveRDS(mydata, file = path_to_data)\n\n\n\n# Utilities to update data ------------------------------------------------\n\nupdate_data <- function(modified) {\n  res <- try({\n    base <- readRDS(path_to_data)\n    setDT(base)\n    base[ID == modified$ID, (names(modified)) := as.list(modified)]\n    saveRDS(base, path_to_data)\n  })\n  inherits(res, \"try-error\")\n}\n\ndelete_data <- function(deleted) {\n  res <- try({\n    base <- readRDS(path_to_data)\n    setDT(base)\n    base <- base[ID != deleted$ID]\n    saveRDS(base, path_to_data)\n  })\n  inherits(res, \"try-error\")\n}\n\nadd_data <- function(added) {\n  res <- try({\n    base <- readRDS(path_to_data)\n    setDT(base)\n    if (added$user %in% base$user) {\n      shinybusy::report_warning(\"Warning\", \"User already exist.\")\n      return(FALSE)\n    }\n    added$ID <- max(base$ID) + 1\n    base <- rbind(base, added[, .SD, .SDcols = !is.na(added)], use.names = TRUE, fill = TRUE)\n    saveRDS(base, path_to_data)\n  })\n  inherits(res, \"try-error\")\n}\n\n\n\n\n# App ---------------------------------------------------------------------\n\nui <- fluidPage(\n  theme = bs_theme(\n    version = 5\n  ),\n  edit_data_ui(id = \"EDIT\"),\n  verbatimTextOutput(\"result\")\n)\n\nserver <- function(input, output, session) {\n\n  data_r <- reactiveFileReader(\n    intervalMillis = 1000,\n    session = session,\n    filePath = path_to_data,\n    readFunc = readRDS\n  )\n\n  # Tableau\n  edited_gestion_utilisateurs_r <- edit_data_server(\n    id = \"EDIT\",\n    data_r = data_r,\n    add = TRUE,\n    update = TRUE,\n    delete = TRUE,\n    download_csv = FALSE,\n    download_excel = TRUE,\n    modal_size = \"xl\",\n    n_column = 2,\n    var_edit = c(\"user\", \"name\", \"job\", \"phone_number\"),\n    callback_update = function(data, row) {\n      result <- update_data(row)\n      if (isTRUE(result))\n        shinybusy::report_failure(\"Error\", \"Failed to update data\")\n      removeModal()\n      return(TRUE)\n    },\n    callback_delete = function(data, row) {\n      result <- delete_data(row)\n      if (isTRUE(result))\n        shinybusy::report_failure(\"Error\", \"Failed to delete data\")\n      removeModal()\n      return(TRUE)\n    },\n    callback_add = function(data, add) {\n      result <- add_data(add)\n      if (isTRUE(result))\n        shinybusy::report_failure(\"Error\", \"Failed to add data\")\n      removeModal()\n      return(TRUE)\n    },\n    only_callback = TRUE,\n    use_notify = FALSE,\n    reactable_options = list(\n      pagination = FALSE,\n      outline = TRUE,\n      striped = TRUE,\n      columns = list(\n        ID = colDef(show = FALSE)\n      )\n    )\n  )\n\n}\n\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "examples/edit_data-callback_add.R",
    "content": "library(shiny)\nlibrary(datamods)\nlibrary(bslib)\nlibrary(reactable)\n\nui <- fluidPage(\n  theme = bs_theme(\n    version = 5\n  ),\n  edit_data_ui(id = \"id\"),\n  verbatimTextOutput(\"result\")\n)\n\n\nserver <- function(input, output, session) {\n\n  edited_r <- edit_data_server(\n    id = \"id\",\n    data_r = reactive(data.frame(Month = month.name, Values = 1:12)),\n    add = TRUE,\n    callback_add = function(data, add) {\n      print(data)\n      print(add)\n      if (!add$Month %in% month.name)\n        return(FALSE)\n      if (add$Values > 20) {\n        shinybusy::notify_warning(\"Value must be equal or inferior to 20\")\n        return(FALSE)\n      }\n      # else add data to table\n      return(TRUE)\n    }\n  )\n\n  output$result <- renderPrint({\n    str(edited_r())\n  })\n\n}\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "examples/edit_data-callback_delete.R",
    "content": "library(shiny)\nlibrary(datamods)\nlibrary(bslib)\nlibrary(reactable)\n\nui <- fluidPage(\n  theme = bs_theme(\n    version = 5\n  ),\n  edit_data_ui(id = \"id\"),\n  verbatimTextOutput(\"result\")\n)\n\n\nserver <- function(input, output, session) {\n\n  edited_r <- edit_data_server(\n    id = \"id\",\n    data_r = reactive(data.frame(Month = month.name, Values = 1:12)),\n    add = TRUE,\n    callback_delete = function(data, row) {\n      print(data)\n      print(row)\n      if (row$Month == \"September\") {\n        shinybusy::notify_warning(\"You cannot delete September\")\n        return(FALSE)\n      }\n      return(TRUE)\n    }\n  )\n\n  output$result <- renderPrint({\n    str(edited_r())\n  })\n\n}\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "examples/edit_data-callback_update-row_style.R",
    "content": "library(shiny)\n# library(datamods)\npkgload::load_all()\nlibrary(bslib)\nlibrary(reactable)\n\nui <- fluidPage(\n  theme = bs_theme(\n    version = 5,\n    preset = \"bootstrap\"\n  ),\n  uiOutput(outputId = \"custom_styles\"),\n  edit_data_ui(id = \"id\"),\n  verbatimTextOutput(\"row_updated\")\n)\n\n\nserver <- function(input, output, session) {\n\n  rv <- reactiveValues(row_updated = NULL)\n\n  edited_r <- edit_data_server(\n    id = \"id\",\n    data_r = reactive(data.frame(\n      row_id = 1:12,\n      Month = month.name,\n      Values = 1:12,\n      Comment = letters[1:12]\n    )),\n    add = TRUE,\n    var_edit = c(\"Month\", \"Values\", \"Comment\"),\n    reactable_options = list(\n      pagination = FALSE,\n      compact = TRUE,\n      columns = list(row_id = colDef(show = FALSE)),\n      rowClass = function(index) {\n        paste0(\"table-row-\", index)\n      }\n    ),\n    callback_add = function(data, row) {\n      print(row)\n      return(TRUE)\n    },\n    callback_delete = function(data, row) {\n      print(row)\n      return(TRUE)\n    },\n    callback_update = function(data, row) {\n      print(row)\n      rv$row_updated <- row$row_id\n      return(TRUE)\n    }\n  )\n\n  output$row_updated <- renderPrint({\n    paste(\"Last row updated:\", rv$row_updated)\n  })\n\n  output$custom_styles <- renderUI({\n    req(rv$row_updated)\n    tags$style(sprintf(\n      \".table-row-%s { background: #FE2E2E; transition: background 1s cubic-bezier(0.785, 0.135, 0.15, 0.86); color: white; }\",\n      rv$row_updated\n    ))\n  })\n\n}\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "examples/edit_data-callback_update.R",
    "content": "library(shiny)\nlibrary(datamods)\nlibrary(bslib)\nlibrary(reactable)\n\nui <- fluidPage(\n  theme = bs_theme(\n    version = 5\n  ),\n  edit_data_ui(id = \"id\"),\n  verbatimTextOutput(\"result\")\n)\n\n\nserver <- function(input, output, session) {\n\n  edited_r <- edit_data_server(\n    id = \"id\",\n    data_r = reactive(data.frame(Month = month.name, Values = 1:12)),\n    add = TRUE,\n    callback_update = function(data, row) {\n      print(data)\n      print(row)\n      if (!row$Month %in% month.name)\n        return(FALSE)\n      if (row$Values > 20) {\n        shinybusy::notify_warning(\"Value must be equal or inferior to 20\")\n        return(FALSE)\n      }\n      # else update data\n      return(TRUE)\n    }\n  )\n\n  output$result <- renderPrint({\n    str(edited_r())\n  })\n\n}\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "examples/edit_data.R",
    "content": "library(shiny)\nlibrary(datamods)\nlibrary(bslib)\nlibrary(reactable)\n\nui <- fluidPage(\n  theme = bs_theme(\n    version = 5\n  ),\n  tags$h2(\"Edit data\", align = \"center\"),\n  edit_data_ui(id = \"id\"),\n  verbatimTextOutput(\"result\")\n)\n\n\nserver <- function(input, output, session) {\n\n  edited_r <- edit_data_server(\n    id = \"id\",\n    data_r = reactive(demo_edit),\n    add = TRUE,\n    update = TRUE,\n    delete = TRUE,\n    download_csv = TRUE,\n    download_excel = TRUE,\n    file_name_export = \"datas\",\n    # var_edit = c(\"name\", \"job\", \"credit_card_provider\", \"credit_card_security_code\"),\n    var_mandatory = c(\"name\", \"job\"),\n    var_labels = list(\n      name = \"Name\",\n      credit_card_security_code = \"Credit card security code\",\n      date_obtained = \"Date obtained\",\n      contactless_card = \"Contactless Card\",\n      credit_card_provider = \"Credit card provider\"\n    ),\n    add_default_values = list(\n      name = \"Please enter your name here\",\n      date_obtained = Sys.Date()\n    ),\n    n_column = 2,\n    modal_size = \"l\",\n    modal_easy_close = TRUE,\n    reactable_options = list(\n      defaultColDef = colDef(filterable = TRUE),\n      selection = \"single\",\n      columns = list(\n        name = colDef(name = \"Name\", style = list(fontWeight = \"bold\")),\n        credit_card_security_code = colDef(name = \"Credit card security code\"),\n        date_obtained = colDef(name = \"Date obtained\", format = colFormat(date = TRUE)),\n        contactless_card = colDef(\n          name = \"Contactless Card\",\n          cell = htmlwidgets::JS(\n            \"function(cellInfo) {\n              return cellInfo.value ? '\\u2714\\ufe0f Yes' : '\\u274c No';\n            }\"\n          )\n        ),\n        credit_card_provider = colDef(\n          name = \"Credit card provider\",\n          style = htmlwidgets::JS(\n            \"function(rowInfo) {\n              console.log(rowInfo);\n              var value = rowInfo.values['credit_card_provider'];\n              var color;\n              if (value == 'Mastercard') {\n                color = '#e06631';\n              } else if (value == 'VISA 16 digit') {\n                color = '#0c13cf';\n              } else if (value == 'American Express') {\n                color = '#4d8be8';\n              } else if (value == 'JCB 16 digit') {\n                color = '#23c45e';\n              } else {\n                color = '#777'\n              }\n              return {color: color, fontWeight: 'bold'}\n            }\"\n          )\n        )\n      ),\n      bordered = TRUE,\n      compact = TRUE,\n      searchable = TRUE,\n      highlight = TRUE\n    )\n  )\n\n  output$result <- renderPrint({\n    str(edited_r())\n  })\n\n}\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "examples/filter_data-basic.R",
    "content": "library(shiny)\nlibrary(datamods)\n\n\nui <- fluidPage(\n  tags$h2(\"Filter data.frame\"),\n  fluidRow(\n    column(\n      width = 3,\n      filter_data_ui(\"filtering\", max_height = \"500px\")\n    ),\n    column(\n      width = 9,\n      reactable::reactableOutput(outputId = \"table\"),\n      tags$b(\"Code dplyr:\"),\n      verbatimTextOutput(outputId = \"code_dplyr\"),\n      tags$b(\"Expression:\"),\n      verbatimTextOutput(outputId = \"code\"),\n      tags$b(\"Filtered data:\"),\n      verbatimTextOutput(outputId = \"res_str\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  res_filter <- filter_data_server(\n    id = \"filtering\",\n    data = reactive(data.frame(\n      varchar = month.name,\n      varnum = 1:12,\n      vardate = Sys.Date() + 1:12\n    )),\n    vars = reactive(list(\n      \"Variable character\" = \"varchar\",\n      \"Variable date\" = \"vardate\",\n      \"Variable numeric\" = \"varnum\"\n    )),\n    drop_ids = FALSE\n  )\n\n  output$table <- reactable::renderReactable({\n    reactable::reactable(res_filter$filtered(), pagination = FALSE)\n  })\n\n  output$code_dplyr <- renderPrint({\n    res_filter$code()\n  })\n  output$code <- renderPrint({\n    res_filter$expr()\n  })\n\n  output$res_str <- renderPrint({\n    str(res_filter$filtered())\n  })\n\n}\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "examples/filter_data.R",
    "content": "library(shiny)\nlibrary(shinyWidgets)\nlibrary(datamods)\nlibrary(MASS)\n\n# Add some NAs to mpg\nmtcars_na <- mtcars\nmtcars_na[] <- lapply(\n  X = mtcars_na,\n  FUN = function(x) {\n    x[sample.int(n = length(x), size = sample(5:10, 1))] <- NA\n    x\n  }\n)\n\ndatetime <- data.frame(\n  date = seq(Sys.Date(), by = \"day\", length.out = 300),\n  datetime = seq(Sys.time(), by = \"hour\", length.out = 300),\n  num = sample.int(1e5, 300)\n)\n\none_column_numeric <- data.frame(\n  var1 = rnorm(100)\n)\n\nui <- fluidPage(\n  tags$h2(\"Filter data.frame\"),\n  actionButton(\"saveFilterButton\",\"Save Filter Values\"),\n  actionButton(\"loadFilterButton\",\"Load Filter Values\"),\n  radioButtons(\n    inputId = \"dataset\",\n    label = \"Data:\",\n    choices = c(\n      \"iris\",\n      \"mtcars\",\n      \"mtcars_na\",\n      \"Cars93\",\n      \"datetime\",\n      \"one_column_numeric\"\n    ),\n    inline = TRUE\n  ),\n\n  fluidRow(\n    column(\n      width = 3,\n      filter_data_ui(\"filtering\", max_height = \"500px\")\n    ),\n    column(\n      width = 9,\n      progressBar(\n        id = \"pbar\", value = 100,\n        total = 100, display_pct = TRUE\n      ),\n      reactable::reactableOutput(outputId = \"table\"),\n      tags$b(\"Code dplyr:\"),\n      verbatimTextOutput(outputId = \"code_dplyr\"),\n      tags$b(\"Expression:\"),\n      verbatimTextOutput(outputId = \"code\"),\n      tags$b(\"Filtered data:\"),\n      verbatimTextOutput(outputId = \"res_str\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n  savedFilterValues <- reactiveVal()\n  data <- reactive({\n    get(input$dataset)\n  })\n\n  vars <- reactive({\n    if (identical(input$dataset, \"mtcars\")) {\n      setNames(as.list(names(mtcars)[1:5]), c(\n        \"Miles/(US) gallon\",\n        \"Number of cylinders\",\n        \"Displacement (cu.in.)\",\n        \"Gross horsepower\",\n        \"Rear axle ratio\"\n      ))\n    } else {\n      NULL\n    }\n  })\n  \n  observeEvent(input$saveFilterButton,{\n    savedFilterValues <<- res_filter$values()\n  },ignoreInit = T)\n  \n  defaults <- reactive({\n    input$loadFilterButton\n    savedFilterValues\n  })\n\n  res_filter <- filter_data_server(\n    id = \"filtering\",\n    data = data,\n    name = reactive(input$dataset),\n    vars = vars,\n    defaults = defaults,\n    widget_num = \"slider\",\n    widget_date = \"slider\",\n    label_na = \"Missing\"\n  )\n\n  observeEvent(res_filter$filtered(), {\n    updateProgressBar(\n      session = session, id = \"pbar\",\n      value = nrow(res_filter$filtered()), total = nrow(data())\n    )\n  })\n\n  output$table <- reactable::renderReactable({\n    reactable::reactable(res_filter$filtered())\n  })\n\n\n  output$code_dplyr <- renderPrint({\n    res_filter$code()\n  })\n  output$code <- renderPrint({\n    res_filter$expr()\n  })\n\n  output$res_str <- renderPrint({\n    str(res_filter$filtered())\n  })\n\n}\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "examples/from-copypaste.R",
    "content": "\nlibrary(shiny)\nlibrary(datamods)\n\nui <- fluidPage(\n  tags$h3(\"Import data with copy & paste\"),\n  fluidRow(\n    column(\n      width = 4,\n      import_copypaste_ui(\"myid\")\n    ),\n    column(\n      width = 8,\n      tags$b(\"Import status:\"),\n      verbatimTextOutput(outputId = \"status\"),\n      tags$b(\"Name:\"),\n      verbatimTextOutput(outputId = \"name\"),\n      tags$b(\"Data:\"),\n      verbatimTextOutput(outputId = \"data\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  imported <- import_copypaste_server(\"myid\")\n\n  output$status <- renderPrint({\n    imported$status()\n  })\n  output$name <- renderPrint({\n    imported$name()\n  })\n  output$data <- renderPrint({\n    imported$data()\n  })\n\n}\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "examples/from-file.R",
    "content": "\n\nlibrary(shiny)\nlibrary(datamods)\n\nui <- fluidPage(\n  # theme = bslib::bs_theme(version = 5L),\n  # theme = bslib::bs_theme(version = 5L, preset = \"bootstrap\"),\n  tags$h3(\"Import data from a file\"),\n  fluidRow(\n    column(\n      width = 4,\n      import_file_ui(\n        id = \"myid\",\n        file_extensions = c(\".csv\", \".txt\", \".xls\", \".xlsx\", \".json\"),\n        layout_params = \"inline\" # or \"dropdown\"\n      )\n    ),\n    column(\n      width = 8,\n      tags$b(\"Import status:\"),\n      verbatimTextOutput(outputId = \"status\"),\n      tags$b(\"Name:\"),\n      verbatimTextOutput(outputId = \"name\"),\n      tags$b(\"Code:\"),\n      verbatimTextOutput(outputId = \"code\"),\n      tags$b(\"Data:\"),\n      verbatimTextOutput(outputId = \"data\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  imported <- import_file_server(\n    id = \"myid\",\n    # Custom functions to read data\n    read_fns = list(\n      xls = function(file, sheet, skip, encoding) {\n        readxl::read_xls(path = file, sheet = sheet, skip = skip)\n      },\n      json = function(file) {\n        jsonlite::read_json(file, simplifyVector = TRUE)\n      }\n    ),\n    show_data_in = \"modal\"\n  )\n\n  output$status <- renderPrint({\n    imported$status()\n  })\n  output$name <- renderPrint({\n    imported$name()\n  })\n  output$code <- renderPrint({\n    imported$code()\n  })\n  output$data <- renderPrint({\n    imported$data()\n  })\n\n}\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "examples/from-globalenv.R",
    "content": "if (interactive()) {\n  library(shiny)\n  library(datamods)\n\n  # Create some data.frames\n\n  my_df <- data.frame(\n    variable1 = sample(letters, 20, TRUE),\n    variable2 = sample(1:100, 20, TRUE)\n  )\n\n  results_analysis <- data.frame(\n    id = sample(letters, 20, TRUE),\n    measure = sample(1:100, 20, TRUE),\n    response = sample(1:100, 20, TRUE)\n  )\n\n\n  # Application\n\n  ui <- fluidPage(\n    fluidRow(\n      column(\n        width = 4,\n        import_globalenv_ui(\"myid\")\n      ),\n      column(\n        width = 8,\n        tags$b(\"Import status:\"),\n        verbatimTextOutput(outputId = \"status\"),\n        tags$b(\"Name:\"),\n        verbatimTextOutput(outputId = \"name\"),\n        tags$b(\"Data:\"),\n        verbatimTextOutput(outputId = \"data\")\n      )\n    )\n  )\n\n  server <- function(input, output, session) {\n\n    imported <- import_globalenv_server(\"myid\")\n\n    output$status <- renderPrint({\n      imported$status()\n    })\n    output$name <- renderPrint({\n      imported$name()\n    })\n    output$data <- renderPrint({\n      imported$data()\n    })\n\n  }\n\n  shinyApp(ui, server)\n}\n"
  },
  {
    "path": "examples/from-googlesheets.R",
    "content": "\nlibrary(shiny)\nlibrary(datamods)\n\nui <- fluidPage(\n  tags$h3(\"Import data from Googlesheets\"),\n  fluidRow(\n    column(\n      width = 4,\n      import_googlesheets_ui(\"myid\")\n    ),\n    column(\n      width = 8,\n      tags$b(\"Import status:\"),\n      verbatimTextOutput(outputId = \"status\"),\n      tags$b(\"Name:\"),\n      verbatimTextOutput(outputId = \"name\"),\n      tags$b(\"Data:\"),\n      verbatimTextOutput(outputId = \"data\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  imported <- import_googlesheets_server(\"myid\")\n\n  output$status <- renderPrint({\n    imported$status()\n  })\n  output$name <- renderPrint({\n    imported$name()\n  })\n  output$data <- renderPrint({\n    imported$data()\n  })\n\n}\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "examples/from-url.R",
    "content": "\nlibrary(shiny)\nlibrary(datamods)\n\nui <- fluidPage(\n  tags$h3(\"Import data from URL\"),\n  fluidRow(\n    column(\n      width = 4,\n      import_url_ui(\"myid\")\n    ),\n    column(\n      width = 8,\n      tags$b(\"Import status:\"),\n      verbatimTextOutput(outputId = \"status\"),\n      tags$b(\"Name:\"),\n      verbatimTextOutput(outputId = \"name\"),\n      tags$b(\"Data:\"),\n      verbatimTextOutput(outputId = \"data\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  imported <- import_url_server(\n    \"myid\",\n    btn_show_data = FALSE,\n    return_class = \"raw\"\n  )\n\n  output$status <- renderPrint({\n    imported$status()\n  })\n  output$name <- renderPrint({\n    imported$name()\n  })\n  output$data <- renderPrint({\n    imported$data()\n  })\n\n}\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "examples/i18n.R",
    "content": "library(datamods)\n\n# Use with an objet\nmy.translations <- list(\n  \"Hello\" = \"Bonjour\"\n)\ni18n(\"Hello\", my.translations)\n\n# Use with options()\noptions(\"i18n\" = list(\n  \"Hello\" = \"Bonjour\"\n))\ni18n(\"Hello\")\n\n# With a package\noptions(\"datamods.i18n\" = \"fr\")\ni18n(\"Browse...\", translations = i18n_translations(\"datamods\"))\n# If you call i18n() from within a function of your package\n# you don't need second argument, e.g.:\n# i18n(\"Browse...\")\n"
  },
  {
    "path": "examples/modal-validation.R",
    "content": "\nlibrary(shiny)\nlibrary(datamods)\n\nif (requireNamespace(\"validate\")) {\n  library(validate)\n  # Define some rules to be applied to data\n  myrules <- validator(\n    is.character(Manufacturer) | is.factor(Manufacturer),\n    is.character(Model) | is.factor(Model),\n    is_unique(Manufacturer, Model),\n    is.numeric(Price),\n    is.numeric(Min.Price),\n    is.numeric(Max.Price),\n    Price > 12, # we should use 0 for testing positivity, but that's for the example\n    !is.na(Luggage.room),\n    in_range(Cylinders, min = 4, max = 8),\n    Man.trans.avail %in% c(\"Yes\", \"No\")\n  )\n  # Add some labels\n  label(myrules) <- c(\n    \"Variable Manufacturer must be character\",\n    \"Variable Model must be character\",\n    \"Manufacturer X Model are unique\",\n    \"Variable Price must be numeric\",\n    \"Variable Min.Price must be numeric\",\n    \"Variable Max.Price must be numeric\",\n    \"Variable Price must be strictly positive\",\n    \"Luggage.room must not contain any missing values\",\n    \"Cylinders must be between 4 and 8\",\n    \"Man.trans.avail must be 'Yes' or 'No'\"\n  )\n  # you can also add a description()\n\n  ui <- fluidPage(\n    fluidRow(\n      column(\n        width = 4,\n        checkboxGroupInput(\n          inputId = \"from\",\n          label = \"From\",\n          choices = c(\"env\", \"file\", \"copypaste\", \"googlesheets\", \"url\"),\n          selected = c(\"file\", \"copypaste\")\n        ),\n        actionButton(\"launch_modal\", \"Launch modal window\")\n      ),\n      column(\n        width = 8,\n        tags$b(\"Imported data:\"),\n        verbatimTextOutput(outputId = \"name\"),\n        verbatimTextOutput(outputId = \"data\")\n      )\n    )\n  )\n\n  server <- function(input, output, session) {\n\n    observeEvent(input$launch_modal, {\n      req(input$from)\n      import_modal(\n        id = \"myid\",\n        from = input$from,\n        title = \"Import data to be used in application\"\n      )\n    })\n\n    imported <- import_server(\n      id = \"myid\",\n      return_class = \"tbl_df\",\n      validation_opts = list(\n        # rules = validator(.file = system.file(\"extdata/rules.yaml\", package = \"datamods\"))\n        rules = myrules\n      )\n    )\n\n    output$name <- renderPrint({\n      req(imported$name())\n      imported$name()\n    })\n\n    output$data <- renderPrint({\n      req(imported$data())\n      imported$data()\n    })\n  }\n\n  if (interactive())\n    shinyApp(ui, server)\n}\n"
  },
  {
    "path": "examples/modal.R",
    "content": "\nlibrary(shiny)\nlibrary(datamods)\n\nui <- fluidPage(\n  # Try with different Bootstrap version\n  theme = bslib::bs_theme(version = 5, preset = \"bootstrap\"),\n  fluidRow(\n    column(\n      width = 4,\n      checkboxGroupInput(\n        inputId = \"from\",\n        label = \"From\",\n        choices = c(\"env\", \"file\", \"copypaste\", \"googlesheets\", \"url\"),\n        selected = c(\"file\", \"copypaste\")\n      ),\n      actionButton(\"launch_modal\", \"Launch modal window\")\n    ),\n    column(\n      width = 8,\n      tags$b(\"Imported data:\"),\n      verbatimTextOutput(outputId = \"name\"),\n      verbatimTextOutput(outputId = \"data\"),\n      verbatimTextOutput(outputId = \"str_data\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  observeEvent(input$launch_modal, {\n    req(input$from)\n    import_modal(\n      id = \"myid\",\n      from = input$from,\n      title = \"Import data to be used in application\"\n    )\n  })\n\n  imported <- import_server(\"myid\", return_class = \"tbl_df\")\n\n  output$name <- renderPrint({\n    req(imported$name())\n    imported$name()\n  })\n\n  output$data <- renderPrint({\n    req(imported$data())\n    imported$data()\n  })\n\n  output$str_data <- renderPrint({\n    req(imported$data())\n    str(imported$data())\n  })\n\n}\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "examples/sample.R",
    "content": "library(shiny)\nlibrary(datamods)\nlibrary(reactable)\n\n\nui <- fluidPage(\n\n  tags$h2(\"Sampling\"),\n\n  fluidRow(\n    column(\n      width = 3,\n      sample_ui(\"myID\")\n    ),\n    column(\n      width = 9,\n      reactableOutput(\"table\")\n    )\n  )\n)\n\n\nserver <- function(input, output, session) {\n\n  result_sample <- sample_server(\"myID\", reactive(iris))\n\n  output$table <- renderReactable({\n    table_sample <- reactable(\n      data = result_sample(),\n      defaultColDef = colDef(\n        align = \"center\"\n      ),\n      borderless = TRUE,\n      highlight = TRUE,\n      striped = TRUE\n    )\n    return(table_sample)\n  })\n}\n\nif (interactive())\n  shinyApp(ui, server)\n\n"
  },
  {
    "path": "examples/select-group-default.R",
    "content": "# Default -----------------------------------------------------------------\n\nlibrary(shiny)\nlibrary(datamods)\nlibrary(shinyWidgets)\n\n\nui <- fluidPage(\n  # theme = bslib::bs_theme(version = 5L),\n  fluidRow(\n    column(\n      width = 10, offset = 1,\n      tags$h3(\"Filter data with select group module\"),\n      shinyWidgets::panel(\n        select_group_ui(\n          id = \"my-filters\",\n          params = list(\n            list(inputId = \"Manufacturer\", label = \"Manufacturer:\"),\n            list(inputId = \"Type\", label = \"Type:\"),\n            list(inputId = \"AirBags\", label = \"AirBags:\"),\n            list(inputId = \"DriveTrain\", label = \"DriveTrain:\")\n          ), vs_args = list(disableSelectAll = FALSE)\n        ),\n        status = \"primary\"\n      ),\n      reactable::reactableOutput(outputId = \"table\"),\n      tags$b(\"Inputs values:\"),\n      verbatimTextOutput(\"inputs\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n  res_mod <- select_group_server(\n    id = \"my-filters\",\n    data = reactive(MASS::Cars93),\n    vars = reactive(c(\"Manufacturer\", \"Type\", \"AirBags\", \"DriveTrain\"))\n  )\n\n  output$table <- reactable::renderReactable({\n    reactable::reactable(res_mod())\n  })\n\n  output$inputs <- renderPrint({\n    attr(res_mod(), \"inputs\")\n  })\n}\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "examples/select-group-selected.R",
    "content": "\n\n# Selected value --------------------------------------------------------------------\n\nlibrary(shiny)\nlibrary(datamods)\n\nui <- fluidPage(\n  select_group_ui(\n    id = \"my-filters\",\n    params = list(\n      list(inputId = \"Manufacturer\", label = \"Manufacturer:\"),\n      list(inputId = \"Type\", label = \"Type:\")\n    ),\n    vs_args = list(\n      disableSelectAll = FALSE\n    )\n  ),\n  actionButton(\"set_sel\", \"Set Manufacturer=Acura\"),\n  verbatimTextOutput(\"res\")\n)\n\nserver <- function(input, output, session) {\n  # We use a reactiveValue so that it can be updated\n  rv <- reactiveValues(selected = list(Manufacturer = \"Audi\")) # for init\n  res_r <- select_group_server(\n    id = \"my-filters\",\n    data = reactive(MASS::Cars93),\n    vars = reactive(c(\"Manufacturer\", \"Type\")),\n    selected_r = reactive(rv$selected)\n  )\n  output$res <- renderPrint({\n    res_r()\n  })\n  observeEvent(input$set_sel, {\n    rv$selected <- list(Manufacturer = \"Acura\")\n  })\n}\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "examples/select-group-subset.R",
    "content": "\n# Subset data -------------------------------------------------------------\n\nlibrary(shiny)\nlibrary(datamods)\nlibrary(shinyWidgets)\n\n\nui <- fluidPage(\n  fluidRow(\n    column(\n      width = 10, offset = 1,\n      tags$h3(\"Filter data with select group module\"),\n      panel(\n        pickerInput(\n          inputId = \"car_select\",\n          choices = unique(MASS::Cars93$Manufacturer),\n          options = list(\n            `live-search` = TRUE,\n            title = \"None selected\"\n          )\n        ),\n        select_group_ui(\n          id = \"my-filters\",\n          params = list(\n            list(inputId = \"Manufacturer\", label = \"Manufacturer:\"),\n            list(inputId = \"Type\", label = \"Type:\"),\n            list(inputId = \"AirBags\", label = \"AirBags:\"),\n            list(inputId = \"DriveTrain\", label = \"DriveTrain:\")\n          )\n        ),\n        status = \"primary\"\n      ),\n      reactable::reactableOutput(outputId = \"table\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  cars_r <- reactive({\n    subset(MASS::Cars93, Manufacturer %in% input$car_select)\n  })\n\n  res_mod <- select_group_server(\n    id = \"my-filters\",\n    data = cars_r,\n    vars = c(\"Manufacturer\", \"Type\", \"AirBags\", \"DriveTrain\")\n  )\n\n  output$table <- reactable::renderReactable({\n    reactable::reactable(res_mod())\n  })\n}\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "examples/select-group-vars.R",
    "content": "\n# Select variables --------------------------------------------------------\n\nlibrary(shiny)\nlibrary(datamods)\nlibrary(shinyWidgets)\n\nui <- fluidPage(\n  fluidRow(\n    column(\n      width = 10, offset = 1,\n      tags$h3(\"Filter data with select group module\"),\n      panel(\n        checkboxGroupInput(\n          inputId = \"vars\",\n          label = \"Variables to use:\",\n          choices = c(\"Manufacturer\", \"Type\", \"AirBags\", \"DriveTrain\"),\n          selected = c(\"Manufacturer\", \"Type\", \"AirBags\", \"DriveTrain\"),\n          inline = TRUE\n        ),\n        select_group_ui(\n          id = \"my-filters\",\n          params = list(\n            list(inputId = \"Manufacturer\", label = \"Manufacturer:\"),\n            list(inputId = \"Type\", label = \"Type:\"),\n            list(inputId = \"AirBags\", label = \"AirBags:\"),\n            list(inputId = \"DriveTrain\", label = \"DriveTrain:\")\n          ),\n          inline = TRUE\n        ),\n        status = \"primary\"\n      ),\n      reactable::reactableOutput(outputId = \"table\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  vars_r <- reactive({\n    input$vars\n  })\n\n  res_mod <- select_group_server(\n    id = \"my-filters\",\n    data = MASS::Cars93,\n    vars = vars_r\n  )\n\n  output$table <- reactable::renderReactable({\n    reactable::reactable(res_mod())\n  })\n}\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "examples/show_data.R",
    "content": "\nlibrary(shiny)\nlibrary(datamods)\n\nui <- fluidPage(\n  theme = bslib::bs_theme(version = 5L),\n  shinyWidgets::html_dependency_winbox(),\n  actionButton(\n    inputId = \"show1\",\n    label = \"Show data in popup\",\n    icon = icon(\"eye\")\n  ),\n  actionButton(\n    inputId = \"show2\",\n    label = \"Show data in modal\",\n    icon = icon(\"eye\")\n  ),\n  actionButton(\n    inputId = \"show3\",\n    label = \"Show data without classes\",\n    icon = icon(\"eye\")\n  ),\n  actionButton(\n    inputId = \"show4\",\n    label = \"Show data in Winbox\",\n    icon = icon(\"eye\")\n  )\n)\n\nserver <- function(input, output, session) {\n  observeEvent(input$show1, {\n    show_data(MASS::Cars93, title = \"MASS::Cars93 dataset\", type = \"popup\")\n  })\n  observeEvent(input$show2, {\n    show_data(MASS::Cars93, title = \"MASS::Cars93 dataset\", type = \"modal\")\n  })\n  observeEvent(input$show3, {\n    show_data(\n      data = MASS::Cars93,\n      title = \"MASS::Cars93 dataset\",\n      show_classes = FALSE,\n      options = list(pagination = 10),\n      type = \"modal\"\n    )\n  })\n  observeEvent(input$show4, {\n    show_data(\n      MASS::Cars93,\n      title = \"MASS::Cars93 dataset\",\n      type = \"winbox\",\n      wbOptions = shinyWidgets::wbOptions(background = \"forestgreen\")\n    )\n  })\n}\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "examples/update_factor.R",
    "content": "\nlibrary(shiny)\nlibrary(datamods)\nlibrary(ggplot2)\n\nui <- fluidPage(\n  theme = bslib::bs_theme(version = 5L, preset = \"bootstrap\"),\n  shinyWidgets::html_dependency_winbox(),\n  tags$h2(\"Reorder the Levels of a Factor\"),\n  fluidRow(\n    column(\n      width = 6,\n      update_factor_ui(\"id\"),\n      actionButton(\"modal\", \"Or click here to open a modal to update factor's level\"),\n      tags$br(), tags$br(),\n      actionButton(\"winbox\", \"Or click here to open a WinBox to create a column\")\n    ),\n    column(\n      width = 6,\n      selectInput(\n        \"var\",\n        label = \"Variable to plot:\",\n        choices = NULL\n      ),\n      plotOutput(\"plot\"),\n      verbatimTextOutput(\"res\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  rv <- reactiveValues(data = MASS::Cars93[c(1, 2, 3, 9, 10, 11, 16, 26, 27)])\n  observe(\n    updateSelectInput(inputId = \"var\", choices = names(rv$data))\n  )\n\n  # Inline mode\n  data_inline_r <- update_factor_server(\n    id = \"id\",\n    data_r = reactive(rv$data)\n  )\n  observeEvent(data_inline_r(), rv$data <- data_inline_r())\n\n  # modal window mode\n  observeEvent(input$modal, modal_update_factor(\"modal\"))\n  data_modal_r <- update_factor_server(\n    id = \"modal\",\n    data_r = reactive(rv$data)\n  )\n  observeEvent(data_modal_r(), {\n    shiny::removeModal()\n    rv$data <- data_modal_r()\n  })\n\n  # winbox mode\n  observeEvent(input$winbox, winbox_update_factor(\"winbox\"))\n  data_winbox_r <- update_factor_server(\n    id = \"winbox\",\n    data_r = reactive(rv$data)\n  )\n  observeEvent(data_winbox_r(), rv$data <- data_winbox_r())\n\n  # Plot results\n  output$plot <- renderPlot({\n    req(input$var, rv$data)\n    ggplot(rv$data) +\n      aes(x = !!sym(input$var)) +\n      geom_bar()\n  })\n  # Show results\n  output$res <- renderPrint({\n    data <- req(rv$data)\n    str(data)\n  })\n}\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "examples/validation.R",
    "content": "library(datamods)\nlibrary(shiny)\n\nif (requireNamespace(\"validate\")) {\n  library(validate)\n\n  # Define some rules to be applied to data\n  myrules <- validator(\n    is.character(Manufacturer) | is.factor(Manufacturer),\n    is.numeric(Price),\n    Price > 12, # we should use 0 for testing positivity, but that's for the example\n    !is.na(Luggage.room),\n    in_range(Cylinders, min = 4, max = 8),\n    Man.trans.avail %in% c(\"Yes\", \"No\")\n  )\n  # Add some labels\n  label(myrules) <- c(\n    \"Variable Manufacturer must be character\",\n    \"Variable Price must be numeric\",\n    \"Variable Price must be strictly positive\",\n    \"Luggage.room must not contain any missing values\",\n    \"Cylinders must be between 4 and 8\",\n    \"Man.trans.avail must be 'Yes' or 'No'\"\n  )\n  # you can also add a description()\n\n  ui <- fluidPage(\n    tags$h2(\"Validation\"),\n    fluidRow(\n      column(\n        width = 4,\n        radioButtons(\n          inputId = \"dataset\",\n          label = \"Choose dataset:\",\n          choices = c(\"mtcars\", \"MASS::Cars93\")\n        ),\n        tags$p(\"Dropdown example:\"),\n        validation_ui(\"validation1\"),\n\n        tags$br(),\n\n        tags$p(\"Inline example:\"),\n        validation_ui(\"validation2\", display = \"inline\")\n      ),\n      column(\n        width = 8,\n        tags$b(\"Status:\"),\n        verbatimTextOutput(\"status\"),\n        tags$b(\"Details:\"),\n        verbatimTextOutput(\"details\")\n      )\n    )\n  )\n\n  server <- function(input, output, session) {\n\n    dataset <- reactive({\n      if (input$dataset == \"mtcars\") {\n        mtcars\n      } else {\n        MASS::Cars93\n      }\n    })\n\n    results <- validation_server(\n      id = \"validation1\",\n      data = dataset,\n      n_row = ~ . > 20, # more than 20 rows\n      n_col = ~ . >= 3, # at least 3 columns\n      rules = myrules\n    )\n\n    validation_server(\n      id = \"validation2\",\n      data = dataset,\n      n_row = ~ . > 20, # more than 20 rows\n      n_col = ~ . >= 3, # at least 3 columns\n      rules = myrules\n    )\n\n    output$status <- renderPrint(results$status())\n    output$details <- renderPrint(results$details())\n\n  }\n\n  if (interactive())\n    shinyApp(ui, server)\n}\n"
  },
  {
    "path": "examples/variables.R",
    "content": "\nlibrary(shiny)\nlibrary(datamods)\n\ntestdata <- data.frame(\n  date_as_char = as.character(Sys.Date() + 0:9),\n  date_as_num = as.numeric(Sys.Date() + 0:9),\n  datetime_as_char = as.character(Sys.time() + 0:9 * 3600*24),\n  datetime_as_num = as.numeric(Sys.time() + 0:9 * 3600*24),\n  num_as_char = as.character(1:10),\n  char = month.name[1:10],\n  char_na = c(\"A\", \"A\", \"B\", NA, \"B\", \"A\", NA, \"B\", \"A\", \"B\"),\n  stringsAsFactors = FALSE\n)\n\nui <- fluidPage(\n  theme = bslib::bs_theme(version = 5L, preset = \"bootstrap\"),\n  tags$h3(\"Select, rename and convert variables\"),\n  fluidRow(\n    column(\n      width = 6,\n      # radioButtons()\n      update_variables_ui(\"vars\")\n    ),\n    column(\n      width = 6,\n      tags$b(\"original data:\"),\n      verbatimTextOutput(\"original\"),\n      verbatimTextOutput(\"original_str\"),\n      tags$b(\"Modified data:\"),\n      verbatimTextOutput(\"modified\"),\n      verbatimTextOutput(\"modified_str\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  updated_data <- update_variables_server(\n    id = \"vars\",\n    data = reactive(testdata),\n    return_data_on_init = FALSE\n  )\n\n  output$original <- renderPrint({\n    testdata\n  })\n  output$original_str <- renderPrint({\n    str(testdata)\n  })\n\n  output$modified <- renderPrint({\n    updated_data()\n  })\n  output$modified_str <- renderPrint({\n    str(updated_data())\n  })\n}\n\nif (interactive())\n  shinyApp(ui, server)\n"
  },
  {
    "path": "inst/assets/css/datamods.css",
    "content": "/*!\n * Copyright (c) 2020 dreamRs\n *\n * datamods, CSS styles\n * https://github.com/dreamRs/datamods\n *\n * @version 0.0.1\n */\n\n.show-block {\n  display: block !important;\n}\n.show-inline {\n  display: inline !important;\n}\n.hidden {\n  display: none !important;\n}\n.invisible {\n  visibility: hidden;\n}\n\n.container-rule {\n  position: relative;\n  text-align: center;\n  height: 25px;\n  margin-bottom: 5px;\n}\n\n.horizontal-rule {\n  position: absolute;\n  top: 11px;\n  right: 0;\n  left: 0;\n  background-color: #d0cfcf;\n  height: 1px;\n  z-index: 100;\n  margin: 0;\n  border: none;\n}\n\n.label-rule {\n  background: #FFF;\n  opacity: 1;\n  z-index: 101;\n  background-color: #FFF;\n  position: relative;\n  padding: 0 10px 0 10px;\n}\n\n.datamods-table-container {\n  overflow: auto;\n  word-break: keep-all;\n  white-space: nowrap;\n}\n\n.datamods-table-container > .table {\n  margin-bottom: 0 !important;\n}\n\n.datamods-file-import {\n  display: grid;\n  grid-template-columns: auto 50px;\n  grid-column-gap: 10px;\n}\n\n.datamods-dt-nowrap {\n  word-break: keep-all;\n  white-space: nowrap;\n}\n\n\n\n/* validation */\n.datamods-validation-results {\n  display: grid;\n  grid-template-columns: repeat(3, 1fr);\n  grid-template-rows: 1fr;\n  height: 50px;\n  line-height: 50px;\n  font-size: large;\n}\n\n.datamods-validation-summary {\n  font-weight: bold;\n  text-align: center;\n}\n\n.datamods-validation-item {\n  font-size: larger;\n}\n\n\n\n/* from esquisse */\n.btn-column-discrete {\n  background-color: #EF562D;\n  color: #FFFFFF;\n}\n.btn-column-continuous {\n  background-color: #0C4C8A;\n  color: #FFFFFF;\n}\n.btn-column-datetime {\n  background-color: #97D5E0;\n  color: #FFFFFF;\n}\n.btn-column-id {\n  background-color: #848484;\n  color: #FFFFFF;\n}\n.btn-column-other {\n  background-color: #2E2E2E;\n  color: #FFFFFF;\n}\n\n"
  },
  {
    "path": "inst/assets/js/datamods.js",
    "content": "/*!\n * Copyright (c) 2020 dreamRs\n *\n * datamods, JavaScript utilities\n * https://github.com/dreamRs/datamods\n *\n * @version 0.0.1\n */\n\n/*jshint\n  jquery:true\n*/\n/*global Shiny */\n\n// Block or unblock an input widget\nShiny.addCustomMessageHandler(\"datamods-toggleWidget\", function(data) {\n  $(\"#\" + data.id).prop(\"disabled\", !data.enable);\n  if ($(\"#\" + data.id).hasClass(\"selectpicker\")) {\n    $(\"#\" + data.id).selectpicker(\"refresh\");\n  }\n});\n\n// Hide or show UI component\nShiny.addCustomMessageHandler(\"datamods-showUI\", function(data) {\n  var sel = data.selector;\n  if (data.hasOwnProperty(\"id\")) {\n    sel = \"#\" + $.escapeSelector(data.id);\n  }\n  if (data.inline) {\n    $(sel).addClass(\"show-inline\");\n    $(sel).removeClass(\"hidden\");\n  } else {\n    $(sel).addClass(\"show-block\");\n    $(sel).removeClass(\"hidden\");\n  }\n});\nShiny.addCustomMessageHandler(\"datamods-hideUI\", function(data) {\n  var sel = data.selector;\n  if (data.hasOwnProperty(\"id\")) {\n    sel = \"#\" + $.escapeSelector(data.id);\n  }\n  if (data.inline) {\n    $(sel).addClass(\"hidden\");\n    $(sel).removeClass(\"show-inline\");\n  } else {\n    $(sel).addClass(\"hidden\");\n    $(sel).removeClass(\"show-block\");\n  }\n});\n\n\nfunction fadeTab(data) {\n  var tabId = $(\"#\" + data.id).attr(\"data-tabsetid\");\n  $(\"#\" + data.id)\n    .parent()\n    .find(\".tab-pane\")\n    .each(function(index) {\n      if ($(this).parent().attr(\"data-tabsetid\") == tabId) {\n        $( this ).addClass(\"fade\");\n        if (index < 1) {\n          $( this ).addClass(\"in\");\n        }\n      }\n    });\n}\n\nfunction updateTabLabel(data) {\n  var el = $(\"#\" + data.id).find(\"[data-value='\" + data.value + \"']\");\n  if (typeof el[0] != \"undefined\") {\n    $(el[0]).html(data.label);\n  }\n}\nShiny.addCustomMessageHandler(\"datamods-updateTabLabel\", updateTabLabel);\n\nfunction disableTab(data) {\n  var el = $(\"#\" + data.id).find(\"[data-value='\" + data.value + \"']\");\n  if (typeof el[0] != \"undefined\") {\n    $(el[0]).removeAttr(\"data-toggle\");\n    $(el[0]).parent().addClass(\"disabled\");\n    $(el[0]).addClass(\"disabled\");\n  }\n}\nShiny.addCustomMessageHandler(\"datamods-disableTab\", disableTab);\n\nfunction enableTab(data) {\n  var el = $(\"#\" + data.id).find(\"[data-value='\" + data.value + \"']\");\n  if (typeof el[0] != \"undefined\") {\n    $(el[0]).attr(\"data-toggle\", \"tab\");\n    $(el[0]).parent().removeClass(\"disabled\");\n    $(el[0]).removeClass(\"disabled\");\n  }\n}\nShiny.addCustomMessageHandler(\"datamods-enableTab\", enableTab);\n\n"
  },
  {
    "path": "inst/extdata/mtcars.csv",
    "content": "mpg,cyl,disp,hp,drat,wt,qsec,vs,am,gear,carb\n21,6,160,110,3.9,2.62,16.46,0,1,4,4\n21,6,160,110,3.9,2.875,17.02,0,1,4,4\n22.8,4,108,93,3.85,2.32,18.61,1,1,4,1\n21.4,6,258,110,3.08,3.215,19.44,1,0,3,1\n18.7,8,360,175,3.15,3.44,17.02,0,0,3,2\n18.1,6,225,105,2.76,3.46,20.22,1,0,3,1\n14.3,8,360,245,3.21,3.57,15.84,0,0,3,4\n24.4,4,146.7,62,3.69,3.19,20,1,0,4,2\n22.8,4,140.8,95,3.92,3.15,22.9,1,0,4,2\n19.2,6,167.6,123,3.92,3.44,18.3,1,0,4,4\n17.8,6,167.6,123,3.92,3.44,18.9,1,0,4,4\n16.4,8,275.8,180,3.07,4.07,17.4,0,0,3,3\n17.3,8,275.8,180,3.07,3.73,17.6,0,0,3,3\n15.2,8,275.8,180,3.07,3.78,18,0,0,3,3\n10.4,8,472,205,2.93,5.25,17.98,0,0,3,4\n10.4,8,460,215,3,5.424,17.82,0,0,3,4\n14.7,8,440,230,3.23,5.345,17.42,0,0,3,4\n32.4,4,78.7,66,4.08,2.2,19.47,1,1,4,1\n30.4,4,75.7,52,4.93,1.615,18.52,1,1,4,2\n33.9,4,71.1,65,4.22,1.835,19.9,1,1,4,1\n21.5,4,120.1,97,3.7,2.465,20.01,1,0,3,1\n15.5,8,318,150,2.76,3.52,16.87,0,0,3,2\n15.2,8,304,150,3.15,3.435,17.3,0,0,3,2\n13.3,8,350,245,3.73,3.84,15.41,0,0,3,4\n19.2,8,400,175,3.08,3.845,17.05,0,0,3,2\n27.3,4,79,66,4.08,1.935,18.9,1,1,4,1\n26,4,120.3,91,4.43,2.14,16.7,0,1,5,2\n30.4,4,95.1,113,3.77,1.513,16.9,1,1,5,2\n15.8,8,351,264,4.22,3.17,14.5,0,1,5,4\n19.7,6,145,175,3.62,2.77,15.5,0,1,5,6\n15,8,301,335,3.54,3.57,14.6,0,1,5,8\n21.4,4,121,109,4.11,2.78,18.6,1,1,4,2\n"
  },
  {
    "path": "inst/extdata/mtcars.json",
    "content": "[{\"mpg\":21,\"cyl\":6,\"disp\":160,\"hp\":110,\"drat\":3.9,\"wt\":2.62,\"qsec\":16.46,\"vs\":0,\"am\":1,\"gear\":4,\"carb\":4,\"_row\":\"Mazda RX4\"},{\"mpg\":21,\"cyl\":6,\"disp\":160,\"hp\":110,\"drat\":3.9,\"wt\":2.875,\"qsec\":17.02,\"vs\":0,\"am\":1,\"gear\":4,\"carb\":4,\"_row\":\"Mazda RX4 Wag\"},{\"mpg\":22.8,\"cyl\":4,\"disp\":108,\"hp\":93,\"drat\":3.85,\"wt\":2.32,\"qsec\":18.61,\"vs\":1,\"am\":1,\"gear\":4,\"carb\":1,\"_row\":\"Datsun 710\"},{\"mpg\":21.4,\"cyl\":6,\"disp\":258,\"hp\":110,\"drat\":3.08,\"wt\":3.215,\"qsec\":19.44,\"vs\":1,\"am\":0,\"gear\":3,\"carb\":1,\"_row\":\"Hornet 4 Drive\"},{\"mpg\":18.7,\"cyl\":8,\"disp\":360,\"hp\":175,\"drat\":3.15,\"wt\":3.44,\"qsec\":17.02,\"vs\":0,\"am\":0,\"gear\":3,\"carb\":2,\"_row\":\"Hornet Sportabout\"},{\"mpg\":18.1,\"cyl\":6,\"disp\":225,\"hp\":105,\"drat\":2.76,\"wt\":3.46,\"qsec\":20.22,\"vs\":1,\"am\":0,\"gear\":3,\"carb\":1,\"_row\":\"Valiant\"},{\"mpg\":14.3,\"cyl\":8,\"disp\":360,\"hp\":245,\"drat\":3.21,\"wt\":3.57,\"qsec\":15.84,\"vs\":0,\"am\":0,\"gear\":3,\"carb\":4,\"_row\":\"Duster 360\"},{\"mpg\":24.4,\"cyl\":4,\"disp\":146.7,\"hp\":62,\"drat\":3.69,\"wt\":3.19,\"qsec\":20,\"vs\":1,\"am\":0,\"gear\":4,\"carb\":2,\"_row\":\"Merc 240D\"},{\"mpg\":22.8,\"cyl\":4,\"disp\":140.8,\"hp\":95,\"drat\":3.92,\"wt\":3.15,\"qsec\":22.9,\"vs\":1,\"am\":0,\"gear\":4,\"carb\":2,\"_row\":\"Merc 230\"},{\"mpg\":19.2,\"cyl\":6,\"disp\":167.6,\"hp\":123,\"drat\":3.92,\"wt\":3.44,\"qsec\":18.3,\"vs\":1,\"am\":0,\"gear\":4,\"carb\":4,\"_row\":\"Merc 280\"},{\"mpg\":17.8,\"cyl\":6,\"disp\":167.6,\"hp\":123,\"drat\":3.92,\"wt\":3.44,\"qsec\":18.9,\"vs\":1,\"am\":0,\"gear\":4,\"carb\":4,\"_row\":\"Merc 280C\"},{\"mpg\":16.4,\"cyl\":8,\"disp\":275.8,\"hp\":180,\"drat\":3.07,\"wt\":4.07,\"qsec\":17.4,\"vs\":0,\"am\":0,\"gear\":3,\"carb\":3,\"_row\":\"Merc 450SE\"},{\"mpg\":17.3,\"cyl\":8,\"disp\":275.8,\"hp\":180,\"drat\":3.07,\"wt\":3.73,\"qsec\":17.6,\"vs\":0,\"am\":0,\"gear\":3,\"carb\":3,\"_row\":\"Merc 450SL\"},{\"mpg\":15.2,\"cyl\":8,\"disp\":275.8,\"hp\":180,\"drat\":3.07,\"wt\":3.78,\"qsec\":18,\"vs\":0,\"am\":0,\"gear\":3,\"carb\":3,\"_row\":\"Merc 450SLC\"},{\"mpg\":10.4,\"cyl\":8,\"disp\":472,\"hp\":205,\"drat\":2.93,\"wt\":5.25,\"qsec\":17.98,\"vs\":0,\"am\":0,\"gear\":3,\"carb\":4,\"_row\":\"Cadillac Fleetwood\"},{\"mpg\":10.4,\"cyl\":8,\"disp\":460,\"hp\":215,\"drat\":3,\"wt\":5.424,\"qsec\":17.82,\"vs\":0,\"am\":0,\"gear\":3,\"carb\":4,\"_row\":\"Lincoln Continental\"},{\"mpg\":14.7,\"cyl\":8,\"disp\":440,\"hp\":230,\"drat\":3.23,\"wt\":5.345,\"qsec\":17.42,\"vs\":0,\"am\":0,\"gear\":3,\"carb\":4,\"_row\":\"Chrysler Imperial\"},{\"mpg\":32.4,\"cyl\":4,\"disp\":78.7,\"hp\":66,\"drat\":4.08,\"wt\":2.2,\"qsec\":19.47,\"vs\":1,\"am\":1,\"gear\":4,\"carb\":1,\"_row\":\"Fiat 128\"},{\"mpg\":30.4,\"cyl\":4,\"disp\":75.7,\"hp\":52,\"drat\":4.93,\"wt\":1.615,\"qsec\":18.52,\"vs\":1,\"am\":1,\"gear\":4,\"carb\":2,\"_row\":\"Honda Civic\"},{\"mpg\":33.9,\"cyl\":4,\"disp\":71.1,\"hp\":65,\"drat\":4.22,\"wt\":1.835,\"qsec\":19.9,\"vs\":1,\"am\":1,\"gear\":4,\"carb\":1,\"_row\":\"Toyota Corolla\"},{\"mpg\":21.5,\"cyl\":4,\"disp\":120.1,\"hp\":97,\"drat\":3.7,\"wt\":2.465,\"qsec\":20.01,\"vs\":1,\"am\":0,\"gear\":3,\"carb\":1,\"_row\":\"Toyota Corona\"},{\"mpg\":15.5,\"cyl\":8,\"disp\":318,\"hp\":150,\"drat\":2.76,\"wt\":3.52,\"qsec\":16.87,\"vs\":0,\"am\":0,\"gear\":3,\"carb\":2,\"_row\":\"Dodge Challenger\"},{\"mpg\":15.2,\"cyl\":8,\"disp\":304,\"hp\":150,\"drat\":3.15,\"wt\":3.435,\"qsec\":17.3,\"vs\":0,\"am\":0,\"gear\":3,\"carb\":2,\"_row\":\"AMC Javelin\"},{\"mpg\":13.3,\"cyl\":8,\"disp\":350,\"hp\":245,\"drat\":3.73,\"wt\":3.84,\"qsec\":15.41,\"vs\":0,\"am\":0,\"gear\":3,\"carb\":4,\"_row\":\"Camaro Z28\"},{\"mpg\":19.2,\"cyl\":8,\"disp\":400,\"hp\":175,\"drat\":3.08,\"wt\":3.845,\"qsec\":17.05,\"vs\":0,\"am\":0,\"gear\":3,\"carb\":2,\"_row\":\"Pontiac Firebird\"},{\"mpg\":27.3,\"cyl\":4,\"disp\":79,\"hp\":66,\"drat\":4.08,\"wt\":1.935,\"qsec\":18.9,\"vs\":1,\"am\":1,\"gear\":4,\"carb\":1,\"_row\":\"Fiat X1-9\"},{\"mpg\":26,\"cyl\":4,\"disp\":120.3,\"hp\":91,\"drat\":4.43,\"wt\":2.14,\"qsec\":16.7,\"vs\":0,\"am\":1,\"gear\":5,\"carb\":2,\"_row\":\"Porsche 914-2\"},{\"mpg\":30.4,\"cyl\":4,\"disp\":95.1,\"hp\":113,\"drat\":3.77,\"wt\":1.513,\"qsec\":16.9,\"vs\":1,\"am\":1,\"gear\":5,\"carb\":2,\"_row\":\"Lotus Europa\"},{\"mpg\":15.8,\"cyl\":8,\"disp\":351,\"hp\":264,\"drat\":4.22,\"wt\":3.17,\"qsec\":14.5,\"vs\":0,\"am\":1,\"gear\":5,\"carb\":4,\"_row\":\"Ford Pantera L\"},{\"mpg\":19.7,\"cyl\":6,\"disp\":145,\"hp\":175,\"drat\":3.62,\"wt\":2.77,\"qsec\":15.5,\"vs\":0,\"am\":1,\"gear\":5,\"carb\":6,\"_row\":\"Ferrari Dino\"},{\"mpg\":15,\"cyl\":8,\"disp\":301,\"hp\":335,\"drat\":3.54,\"wt\":3.57,\"qsec\":14.6,\"vs\":0,\"am\":1,\"gear\":5,\"carb\":8,\"_row\":\"Maserati Bora\"},{\"mpg\":21.4,\"cyl\":4,\"disp\":121,\"hp\":109,\"drat\":4.11,\"wt\":2.78,\"qsec\":18.6,\"vs\":1,\"am\":1,\"gear\":4,\"carb\":2,\"_row\":\"Volvo 142E\"}]\n"
  },
  {
    "path": "inst/extdata/mtcars_fr.csv",
    "content": "mpg;cyl;disp;hp;drat;wt;qsec;vs;am;gear;carb\n21,0;6;160,0;110;3,90;2,620;16,46;0;1;4;4\n21,0;6;160,0;110;3,90;2,875;17,02;0;1;4;4\n22,8;4;108,0;93;3,85;2,320;18,61;1;1;4;1\n21,4;6;258,0;110;3,08;3,215;19,44;1;0;3;1\n18,7;8;360,0;175;3,15;3,440;17,02;0;0;3;2\n18,1;6;225,0;105;2,76;3,460;20,22;1;0;3;1\n14,3;8;360,0;245;3,21;3,570;15,84;0;0;3;4\n24,4;4;146,7;62;3,69;3,190;20,00;1;0;4;2\n22,8;4;140,8;95;3,92;3,150;22,90;1;0;4;2\n19,2;6;167,6;123;3,92;3,440;18,30;1;0;4;4\n17,8;6;167,6;123;3,92;3,440;18,90;1;0;4;4\n16,4;8;275,8;180;3,07;4,070;17,40;0;0;3;3\n17,3;8;275,8;180;3,07;3,730;17,60;0;0;3;3\n15,2;8;275,8;180;3,07;3,780;18,00;0;0;3;3\n10,4;8;472,0;205;2,93;5,250;17,98;0;0;3;4\n10,4;8;460,0;215;3,00;5,424;17,82;0;0;3;4\n14,7;8;440,0;230;3,23;5,345;17,42;0;0;3;4\n32,4;4;78,7;66;4,08;2,200;19,47;1;1;4;1\n30,4;4;75,7;52;4,93;1,615;18,52;1;1;4;2\n33,9;4;71,1;65;4,22;1,835;19,90;1;1;4;1\n21,5;4;120,1;97;3,70;2,465;20,01;1;0;3;1\n15,5;8;318,0;150;2,76;3,520;16,87;0;0;3;2\n15,2;8;304,0;150;3,15;3,435;17,30;0;0;3;2\n13,3;8;350,0;245;3,73;3,840;15,41;0;0;3;4\n19,2;8;400,0;175;3,08;3,845;17,05;0;0;3;2\n27,3;4;79,0;66;4,08;1,935;18,90;1;1;4;1\n26,0;4;120,3;91;4,43;2,140;16,70;0;1;5;2\n30,4;4;95,1;113;3,77;1,513;16,90;1;1;5;2\n15,8;8;351,0;264;4,22;3,170;14,50;0;1;5;4\n19,7;6;145,0;175;3,62;2,770;15,50;0;1;5;6\n15,0;8;301,0;335;3,54;3,570;14,60;0;1;5;8\n21,4;4;121,0;109;4,11;2,780;18,60;1;1;4;2\n"
  },
  {
    "path": "inst/extdata/pop-fra-dep.txt",
    "content": "Code région\tNom de la région\tCode département\tNom du département\tNombre d'arrondissements\tNombre de cantons\tNombre de communes\tPopulation municipale\tPopulation totale\n84\tAuvergne-Rhône-Alpes\t01\tAin\t4\t23\t393\t643 350\t659 180\n32\tHauts-de-France\t02\tAisne\t5\t21\t800\t534 490\t546 527\n84\tAuvergne-Rhône-Alpes\t03\tAllier\t3\t19\t317\t337 988\t347 035\n93\tProvence-Alpes-Côte d'Azur\t04\tAlpes-de-Haute-Provence\t4\t15\t198\t163 915\t168 381\n93\tProvence-Alpes-Côte d'Azur\t05\tHautes-Alpes\t2\t15\t162\t141 284\t145 883\n93\tProvence-Alpes-Côte d'Azur\t06\tAlpes-Maritimes\t2\t27\t163\t1 083 310\t1 097 496\n84\tAuvergne-Rhône-Alpes\t07\tArdèche\t3\t17\t335\t325 712\t334 688\n44\tGrand Est\t08\tArdennes\t4\t19\t449\t273 579\t280 032\n76\tOccitanie\t09\tAriège\t3\t13\t327\t153 153\t157 210\n44\tGrand Est\t10\tAube\t3\t17\t431\t310 020\t317 118\n76\tOccitanie\t11\tAude\t3\t19\t433\t370 260\t379 094\n76\tOccitanie\t12\tAveyron\t3\t23\t285\t279 206\t289 488\n93\tProvence-Alpes-Côte d'Azur\t13\tBouches-du-Rhône\t4\t29\t119\t2 024 162\t2 048 504\n28\tNormandie\t14\tCalvados\t4\t25\t527\t694 002\t708 344\n84\tAuvergne-Rhône-Alpes\t15\tCantal\t3\t15\t246\t145 143\t150 185\n75\tNouvelle-Aquitaine\t16\tCharente\t3\t19\t366\t352 335\t361 539\n75\tNouvelle-Aquitaine\t17\tCharente-Maritime\t5\t27\t463\t644 303\t659 968\n24\tCentre-Val de Loire\t18\tCher\t3\t19\t287\t304 256\t311 456\n75\tNouvelle-Aquitaine\t19\tCorrèze\t3\t19\t280\t241 464\t249 135\n94\tCorse\t2A\tCorse-du-Sud\t2\t11\t124\t157 249\t159 768\n94\tCorse\t2B\tHaute-Corse\t3\t15\t236\t177 689\t180 465\n27\tBourgogne-Franche-Comté\t21\tCôte-d'Or\t3\t23\t700\t533 819\t545 798\n53\tBretagne\t22\tCôtes-d'Armor\t4\t27\t348\t598 814\t617 107\n75\tNouvelle-Aquitaine\t23\tCreuse\t2\t15\t256\t118 638\t122 133\n75\tNouvelle-Aquitaine\t24\tDordogne\t4\t25\t505\t413 606\t424 095\n27\tBourgogne-Franche-Comté\t25\tDoubs\t3\t19\t573\t539 067\t552 643\n84\tAuvergne-Rhône-Alpes\t26\tDrôme\t3\t19\t364\t511 553\t524 574\n28\tNormandie\t27\tEure\t3\t23\t585\t601 843\t614 926\n24\tCentre-Val de Loire\t28\tEure-et-Loir\t4\t15\t365\t433 233\t443 538\n53\tBretagne\t29\tFinistère\t4\t27\t277\t909 028\t933 992\n76\tOccitanie\t30\tGard\t3\t23\t351\t744 178\t757 764\n76\tOccitanie\t31\tHaute-Garonne\t3\t27\t586\t1 362 672\t1 385 122\n76\tOccitanie\t32\tGers\t3\t17\t461\t191 091\t197 953\n75\tNouvelle-Aquitaine\t33\tGironde\t6\t33\t535\t1 583 384\t1 607 545\n76\tOccitanie\t34\tHérault\t3\t25\t342\t1 144 892\t1 162 867\n53\tBretagne\t35\tIlle-et-Vilaine\t4\t27\t333\t1 060 199\t1 084 554\n24\tCentre-Val de Loire\t36\tIndre\t4\t13\t241\t222 232\t227 999\n24\tCentre-Val de Loire\t37\tIndre-et-Loire\t3\t19\t272\t606 511\t618 820\n84\tAuvergne-Rhône-Alpes\t38\tIsère\t3\t29\t512\t1 258 722\t1 283 384\n27\tBourgogne-Franche-Comté\t39\tJura\t3\t17\t494\t260 188\t269 344\n75\tNouvelle-Aquitaine\t40\tLandes\t2\t15\t327\t407 444\t419 709\n24\tCentre-Val de Loire\t41\tLoir-et-Cher\t3\t15\t267\t331 915\t340 499\n84\tAuvergne-Rhône-Alpes\t42\tLoire\t3\t21\t323\t762 941\t777 328\n84\tAuvergne-Rhône-Alpes\t43\tHaute-Loire\t3\t19\t257\t227 283\t234 190\n52\tPays de la Loire\t44\tLoire-Atlantique\t3\t31\t207\t1 394 909\t1 423 152\n24\tCentre-Val de Loire\t45\tLoiret\t3\t21\t326\t678 105\t692 540\n76\tOccitanie\t46\tLot\t3\t17\t313\t173 828\t179 556\n75\tNouvelle-Aquitaine\t47\tLot-et-Garonne\t4\t21\t319\t332 842\t341 270\n76\tOccitanie\t48\tLozère\t2\t13\t152\t76 601\t80 240\n52\tPays de la Loire\t49\tMaine-et-Loire\t4\t21\t177\t813 493\t833 154\n28\tNormandie\t50\tManche\t4\t27\t446\t496 883\t512 923\n44\tGrand Est\t51\tMarne\t4\t23\t613\t568 895\t580 671\n44\tGrand Est\t52\tHaute-Marne\t3\t17\t426\t175 640\t180 753\n52\tPays de la Loire\t53\tMayenne\t3\t17\t242\t307 445\t316 750\n44\tGrand Est\t54\tMeurthe-et-Moselle\t4\t23\t591\t733 481\t745 300\n44\tGrand Est\t55\tMeuse\t3\t17\t499\t187 187\t192 588\n53\tBretagne\t56\tMorbihan\t3\t21\t250\t750 863\t771 911\n44\tGrand Est\t57\tMoselle\t5\t27\t725\t1 043 522\t1 062 217\n27\tBourgogne-Franche-Comté\t58\tNièvre\t4\t17\t309\t207 182\t212 742\n32\tHauts-de-France\t59\tNord\t6\t41\t648\t2 604 361\t2 635 255\n32\tHauts-de-France\t60\tOise\t4\t21\t679\t824 503\t841 948\n28\tNormandie\t61\tOrne\t3\t21\t385\t283 372\t291 557\n32\tHauts-de-France\t62\tPas-de-Calais\t7\t39\t890\t1 468 018\t1 489 983\n84\tAuvergne-Rhône-Alpes\t63\tPuy-de-Dôme\t5\t31\t464\t653 742\t668 301\n75\tNouvelle-Aquitaine\t64\tPyrénées-Atlantiques\t3\t27\t546\t677 309\t695 965\n76\tOccitanie\t65\tHautes-Pyrénées\t3\t17\t469\t228 530\t234 591\n76\tOccitanie\t66\tPyrénées-Orientales\t3\t17\t226\t474 452\t482 368\n44\tGrand Est\t67\tBas-Rhin\t5\t23\t514\t1 125 559\t1 141 511\n44\tGrand Est\t68\tHaut-Rhin\t4\t17\t366\t764 030\t777 917\n84\tAuvergne-Rhône-Alpes\t69\tRhône\t2\t13\t267\t1 843 319\t1 869 599\n27\tBourgogne-Franche-Comté\t70\tHaute-Saône\t2\t17\t539\t236 659\t243 264\n27\tBourgogne-Franche-Comté\t71\tSaône-et-Loire\t5\t29\t565\t553 595\t569 531\n52\tPays de la Loire\t72\tSarthe\t3\t21\t354\t566 506\t579 650\n84\tAuvergne-Rhône-Alpes\t73\tSavoie\t3\t19\t273\t431 174\t443 787\n84\tAuvergne-Rhône-Alpes\t74\tHaute-Savoie\t4\t17\t279\t807 360\t828 417\n11\tÎle-de-France\t75\tParis\t1\t\t1\t2 187 526\t2 204 773\n28\tNormandie\t76\tSeine-Maritime\t3\t35\t708\t1 254 378\t1 275 559\n11\tÎle-de-France\t77\tSeine-et-Marne\t5\t23\t507\t1 403 997\t1 420 469\n11\tÎle-de-France\t78\tYvelines\t4\t21\t259\t1 438 266\t1 463 091\n75\tNouvelle-Aquitaine\t79\tDeux-Sèvres\t3\t17\t256\t374 351\t384 479\n32\tHauts-de-France\t80\tSomme\t4\t23\t772\t572 443\t582 464\n76\tOccitanie\t81\tTarn\t2\t23\t314\t387 890\t398 412\n76\tOccitanie\t82\tTarn-et-Garonne\t2\t15\t195\t258 349\t264 130\n93\tProvence-Alpes-Côte d'Azur\t83\tVar\t3\t23\t153\t1 058 740\t1 075 653\n93\tProvence-Alpes-Côte d'Azur\t84\tVaucluse\t3\t17\t151\t559 479\t570 762\n52\tPays de la Loire\t85\tVendée\t3\t17\t258\t675 247\t693 455\n75\tNouvelle-Aquitaine\t86\tVienne\t3\t19\t266\t436 876\t447 150\n75\tNouvelle-Aquitaine\t87\tHaute-Vienne\t3\t21\t195\t374 426\t381 379\n44\tGrand Est\t88\tVosges\t3\t17\t507\t367 673\t378 986\n27\tBourgogne-Franche-Comté\t89\tYonne\t3\t21\t423\t338 291\t346 902\n27\tBourgogne-Franche-Comté\t90\tTerritoire de Belfort\t1\t9\t101\t142 622\t145 640\n11\tÎle-de-France\t91\tEssonne\t3\t21\t194\t1 296 130\t1 310 599\n11\tÎle-de-France\t92\tHauts-de-Seine\t3\t23\t36\t1 609 306\t1 625 917\n11\tÎle-de-France\t93\tSeine-Saint-Denis\t3\t21\t40\t1 623 111\t1 630 133\n11\tÎle-de-France\t94\tVal-de-Marne\t3\t25\t47\t1 387 926\t1 397 035\n11\tÎle-de-France\t95\tVal-d'Oise\t3\t21\t184\t1 228 618\t1 239 262\n01\tGuadeloupe\t971\tGuadeloupe\t2\t21\t32\t390 253\t396 153\n02\tMartinique\t972\tMartinique\t4\t\t34\t372 594\t377 711\n03\tGuyane\t973\tGuyane\t2\t\t22\t268 700\t271 124\n04\tLa Réunion\t974\tLa Réunion\t4\t25\t24\t853 659\t863 063\n"
  },
  {
    "path": "inst/extdata/rules.yaml",
    "content": "rules:\n- expr: speed >= 0\n  name: 'speed'\n  label: 'speed positivity'\n  description: |\n    speed can not be negative\n  created: 2020-11-02 11:15:11\n  meta:\n    language: validate 0.9.3.36\n    severity: error\n- expr: dist >= 0\n  name: 'dist'\n  label: 'distance positivity'\n  description: |\n    distance cannot be negative.\n  created: 2020-11-02 11:15:11\n  meta:\n    language: validate 0.9.3.36\n    severity: error\n- expr: speed/dist <= 1.5\n  name: 'ratio'\n  label: 'ratio limit'\n  description: |\n    The speed to distance ratio can\n    not exceed 1.5.\n  created: 2020-11-02 11:15:11\n  meta:\n    language: validate 0.9.3.36\n    severity: error\n"
  },
  {
    "path": "inst/i18n/al.csv",
    "content": "\"label\",\"translation\",\"comment\"\n\"% of the total\",\"% e totalit\",\"Automatically translated\"\n\"% of the total, i.e.\",\"% e totalit, d.m.th.\",\"Automatically translated\"\n\"A shareable link, in that case first sheet will be read\",\"Linku që mund të ndahet, në këtë rast do të lexohet fleta e parë\",\"\"\n\"Add a label to data\",\"Shtoni një etiketë në të dhëna\",\"#TODO #CHECK\"\n\"Add a row\",\"Shtoni një rresht\",\"\"\n\"Apply changes\",\"Apliko ndryshimet\",\"\"\n\"Browse...\",\"Shfletoni...\",\"\"\n\"Cancel\",\"Anulo\",\"\"\n\"Choose a name for the column to be created or modified,\",\"Zgjidhni një emër për kolonën që do të krijohet ose modifikohet,\",\"Automatically translated\"\n\"Choose a number of rows :\",\"Zgjidhni një numër rreshtash:\",\"Automatically translated\"\n\"Choose a percentage :\",\"Zgjidhni një përqindje:\",\"Automatically translated\"\n\"Click on a column name to add it to the expression:\",\"Klikoni në emrin e një kolone për ta shtuar atë në shprehjen:\",\"Automatically translated\"\n\"Click to delete\",\"Klikoni për të fshirë\",\"\"\n\"Click to edit\",\"Klikoni për të redaktuar\",\"\"\n\"Close\",\"Мbyll\",\"\"\n\"Close intervals on the right\",\"Mbyllni intervalet në të djathtë\",\"Automatically translated\"\n\"Column added!\",\"Kolona u shtua!\",\"Automatically translated\"\n\"Convert Numeric to Factor\",\"Konvertoni numerik në faktor\",\"Automatically translated\"\n\"Copy & paste data\",\"Kopjoni dhe ngjisni të dhënat\",\"\"\n\"Copy / Paste\",\"Kopjoni / ngjisni\",\"\"\n\"Count\",\"Numëroni\",\"Automatically translated\"\n\"Create a new column\",\"Krijo një kolonë të re\",\"Automatically translated\"\n\"Create a new variable otherwise replaces the one selected\",\"Krijoni një variabël të ri përndryshe zëvendëson atë të zgjedhur\",\"Automatically translated\"\n\"Create column\",\"Krijo kolonë\",\"Automatically translated\"\n\"Create factor variable\",\"Krijo variabël faktor\",\"Automatically translated\"\n\"Data has %s observations and %s variables.\",\"Të dhënat kanë %s vëzhgime dhe %s variabla\",\"\"\n\"Data ready to be imported!\",\"Të dhënat që janë gati për t'u importuar\",\"\"\n\"Data successfully imported!\",\"Të dhënat u importuan me sukses\",\"\"\n\"Data successfully updated!\",\"Të dhënat janë azhurnuar me sukses!\",\"\"\n\"Data wasn't deleted\",\"Të dhënat nuk u fshinë\",\"Automatically translated\"\n\"Data wasn't updated\",\"Të dhënat nuk u përditësuan\",\"Automatically translated\"\n\"Dataset validation:\",\"Vërtetimi i grupit të të dhënave:\",\"Automatically translated\"\n\"Date format:\",\"Formati i datës:\",\"\"\n\"Date to use as origin to convert date/datetime:\",\"Data që do të përdoret për të konvertuar ndryshoren date/datetime\",\"\"\n\"Decimal separator:\",\"Ndarësi dhjetor:\",\"\"\n\"Delete\",\"Fshije\",\"\"\n\"Do you want to delete the selected row ?\",\"Dëshironi të fshini rreshtin e zgjedhur?\",\"\"\n\"Encoding:\",\"Kodimi:\",\"\"\n\"Enter URL to data:\",\"Futni URL-në e të dhënave:\",\"Automatically translated\"\n\"Enter a shareable link to a GoogleSheet:\",\"Futni një link që mund të ndahet në GoogleSheet:\",\"\"\n\"Enter an expression to define new column:\",\"Futni një shprehje për të përcaktuar kolonën e re:\",\"Automatically translated\"\n\"Environment\",\"Mjedisi\",\"\"\n\"Error\",\"Gabim\",\"\"\n\"External file\",\"Skedari i jashtëm\",\"\"\n\"Factor variable to reorder:\",\"Ndryshorja e faktorit për të rirenditur:\",\"Automatically translated\"\n\"Failed\",\"Dështim\",\"\"\n\"First five rows are shown below:\",\"Pesë rreshtat e parë janë treguar më poshtë:\",\"\"\n\"Googlesheets\",\"Googlesheets\",\"\"\n\"Group calculation by:\",\"Llogaritja e grupit sipas:\",\"Automatically translated\"\n\"Help\",\"Ndihmë\",\"\"\n\"How to import data?\",\"Si të importoni të dhëna?\",\"\"\n\"Import\",\"Importo\",\"\"\n\"Import Google Spreadsheet\",\"Importoni GoogleSheet\",\"\"\n\"Import Url\",\"Importo Url\",\"Automatically translated\"\n\"Import a dataset from an environment\",\"Importoni një grup të dhënash nga mjedisi\",\"\"\n\"Import a file\",\"Importoni skedar\",\"\"\n\"Import data\",\"Importoni të dhënat\",\"\"\n\"Imported data\",\"Të dhëna të importuara\",\"Automatically translated\"\n\"Include lowest value\",\"Përfshi vlerën më të ulët\",\"Automatically translated\"\n\"Information\",\"Informacion\",\"\"\n\"Item has been modified\",\"Artikulli është modifikuar\",\"\"\n\"Levels\",\"Nivelet\",\"Automatically translated\"\n\"List of data.frame...\",\"Lista e tabelave të të dhënave (data.frame)\",\"\"\n\"Max:\",\"Maksimumi:\",\"Automatically translated\"\n\"Mean:\",\"Mesatarja:\",\"Automatically translated\"\n\"Method:\",\"Metoda:\",\"Automatically translated\"\n\"Min:\",\"Min.:\",\"Automatically translated\"\n\"Missing values characters:\",\"Karakteret e vlerave që mungojnë:\",\"Automatically translated\"\n\"Missing:\",\"Mungon:\",\"Automatically translated\"\n\"Most Common:\",\"Më e zakonshme:\",\"Automatically translated\"\n\"New column name cannot be empty\",\"Emri i kolonës së re nuk mund të jetë bosh\",\"Automatically translated\"\n\"New column name:\",\"Emri i kolonës së re:\",\"Automatically translated\"\n\"No\",\"Nr\",\"\"\n\"No data selected!\",\"Nuk ka të dhëna të zgjedhura!\",\"\"\n\"No data to display.\",\"Nuk ka të dhëna për t’u shfaqur.\",\"\"\n\"No data.frame here...\",\"Këtu nuk ka të dhëna (data.frame) ...\",\"\"\n\"No file selected\",\"Nuk është zgjedhur asnjë dokument\",\"\"\n\"No file selected:\",\"Nuk është zgjedhur asnjë dokument:\",\"\"\n\"Not a data.frame\",\"Jo një të dhëna.kornizë\",\"Automatically translated\"\n\"Nothing pasted yet!\",\"Asgjë nuk është ngjitur deri më tani!\",\"\"\n\"Number of breaks:\",\"Numri i pushimeve:\",\"Automatically translated\"\n\"Number of rows:\",\"Numri i rreshtave:\",\"\"\n\"OK\",\"Në rregull\",\"\"\n\"Ooops\",\"Ups\",\"\"\n\"Paste data here:\",\"Ngjitni të dhënat tuaja këtu:\",\"\"\n\"Please copy and paste some data in the dialog box above.\",\"Ju lutemi kopjoni dhe ngjisni disa të dhëna në dritaren e dialogut më poshtë\",\"\"\n\"Please fill in the required fields\",\"Ju lutemi plotësoni fushat e kërkuara\",\"\"\n\"Please paste a valid GoogleSheet link in the dialog box above.\",\"Ju lutemi ngjisni një link të vlefshëm në GoogleSheet në dritaren e dialogut më poshtë.\",\"\"\n\"Please paste a valid link in the dialog box above.\",\"Ju lutemi ngjitni një lidhje të vlefshme në kutinë e dialogut të mësipërm.\",\"Automatically translated\"\n\"Registered\",\"I regjistruar\",\"\"\n\"Required field\",\"Fusha e kërkuar\",\"\"\n\"Row has been saved\",\"Rreshti është ruajtur\",\"\"\n\"Row was not deleted\",\"Rreshti nuk u fshi\",\"\"\n\"Rows to skip before reading data:\",\"Rreshtat për t'u kapërcyer përpara se të lexohen të dhënat:\",\"Automatically translated\"\n\"Sample data by :\",\"Mostra e të dhënave sipas:\",\"Automatically translated\"\n\"Save\",\"Ruaj\",\"\"\n\"Select\",\"Zgjidhni\",\"\"\n\"Select a data.frame:\",\"Zgjidhni data.frame\",\"\"\n\"Select an environment in which to search:\",\"Zgjidhni një mjedis në të cilin do të kërkoni\",\"\"\n\"Select environment\",\"Zgjidhni një mjedis\",\"\"\n\"Select sheet to import:\",\"Zgjidhni një fletë për ta importuar\",\"\"\n\"Some operations are not allowed\",\"Disa operacione nuk lejohen\",\"Automatically translated\"\n\"Something went wrong...\",\"Diçka shkoi keq...\",\"\"\n\"Sort count\",\"Rendit numërimin\",\"Automatically translated\"\n\"The URL that appear in your browser, in that case the current sheet will be read\",\"URL-ja që shfaqet në shfletuesin tuaj, në këtë rast do të lexohet fleta e parë\",\"\"\n\"The row has been deleted\",\"Rreshti është fshirë\",\"\"\n\"The row wasn't added to the data\",\"Rreshti nuk u shtua te të dhënat\",\"Automatically translated\"\n\"URL\",\"URL\",\"Automatically translated\"\n\"Unable to add the row, contact the platform administrator\",\"Rreshti nuk mund të shtohet, kontakto me administratorin e platformës\",\"\"\n\"Unable to delete the row, contact platform administrator\",\"Rreshti nuk mund të fshihet, kontakto me administratorin e platformës\",\"\"\n\"Unable to modify the item, contact the platform administrator\",\"Artikulli nuk mund të modifikohet, kontaktoni administratorin e platformës\",\"\"\n\"Unique values:\",\"Vlerat unike:\",\"Automatically translated\"\n\"Unique:\",\"Unike:\",\"Automatically translated\"\n\"Update\",\"Azhurno\",\"\"\n\"Update & select variables\",\"Azhurnoni dhe zgjidhni variablat\",\"\"\n\"Update factor variable\",\"Përditëso variablin e faktorit\",\"Automatically translated\"\n\"Update levels of a factor\",\"Përditëso nivelet e një faktori\",\"Automatically translated\"\n\"Update row\",\"Përditëso rreshtin\",\"\"\n\"Upload a file:\",\"Bashkangjitni një dokument:\",\"\"\n\"Use a data.frame from your environment or from the environment of a package.\",\"Përdorni data.frame nga mjedisi juaj ose nga mjedisi i paketës\",\"\"\n\"Valid number of columns\",\"Numri i vlefshëm i kolonave\",\"Automatically translated\"\n\"Valid number of rows\",\"Numri i vlefshëm i rreshtave\",\"Automatically translated\"\n\"Validate\",\"Verifiko\",\"\"\n\"Validation:\",\"Verifikimi:\",\"\"\n\"Variable to cut:\",\"Ndryshore për prerje:\",\"Automatically translated\"\n\"View\",\"Shiko\",\"\"\n\"Warning\",\"Paralajmërim\",\"Automatically translated\"\n\"Yes\",\"po\",\"\"\n\"You can either use:\",\"Mund ta përdorni edhe ndonjërën nga këto:\",\"\"\n\"You can import %s files\",\"Mund të importoni dokumente %s\",\"\"\n\"You can import from flat table format supported by\",\"Mund të importoni nga formati i tabelës së sheshtë i mbështetur nga\",\"Automatically translated\"\n\"click to see data\",\"Klikoni këtu për t’i parë të dhënat\",\"\"\n\"data has %s obs. of %s variables.\",\"Të dhënat kanë %vëzhgime dhe %variabla\",\"\"\n\"if several use a comma ',' to separate them\",\"nëse disa përdorin presje ',' për t'i ndarë\",\"Automatically translated\"\n\"lines, i.e.\",\"vijat, d.m.th.\",\"Automatically translated\"\n\"number of rows\",\"numri i rreshtave\",\"Automatically translated\"\n\"proportion of rows\",\"proporcioni i rreshtave\",\"Automatically translated\"\n\"rows\",\"rreshtave\",\"Automatically translated\"\n\"then enter an expression before clicking on the button above to validate or on \",\"pastaj futni një shprehje përpara se të klikoni në butonin e mësipërm për të vërtetuar ose aktivizuar\",\"Automatically translated\"\n\"to delete it.\",\"për ta fshirë.\",\"Automatically translated\"\n\"Sort by count\",\"Rendit sipas numërimit\",\"Automatically translated\"\n\"Sort by levels\",\"Rendit sipas niveleve\",\"Automatically translated\"\n"
  },
  {
    "path": "inst/i18n/cn.csv",
    "content": "\"label\",\"translation\",\"comment\"\n\"% of the total\",\"鍗犳€绘暟鐨�%\",\"Automatically translated\"\n\"% of the total, i.e.\",\"鍗犳€绘暟鐨�%锛屽嵆\",\"Automatically translated\"\n\"A shareable link, in that case first sheet will be read\",\"文件共享链接，我们将导入首个工作簿的数据\",\"\"\n\"Add a label to data\",\"添加数据标签\",\"\"\n\"Add a row\",\"添加一行\",\"\"\n\"Apply changes\",\"应用更改\",\"\"\n\"Browse...\",\"浏览...\",\"\"\n\"Cancel\",\"取消\",\"\"\n\"Choose a name for the column to be created or modified,\",\"涓鸿鍒涘缓鎴栦慨鏀圭殑鍒楅€夋嫨涓€涓悕绉帮紝\",\"Automatically translated\"\n\"Choose a number of rows :\",\"閫夋嫨琛屾暟锛�\",\"Automatically translated\"\n\"Choose a percentage :\",\"閫夋嫨涓€涓櫨鍒嗘瘮锛�\",\"Automatically translated\"\n\"Click on a column name to add it to the expression:\",\"鍗曞嚮鍒楀悕绉板皢鍏舵坊鍔犲埌琛ㄨ揪寮忎腑锛�\",\"Automatically translated\"\n\"Click to delete\",\"点击删除\",\"\"\n\"Click to edit\",\"点击编辑\",\"\"\n\"Close\",\"取消\",\"\"\n\"Close intervals on the right\",\"鍙宠竟闂撮殧寰堣繎\",\"Automatically translated\"\n\"Column added!\",\"涓撴爮宸叉坊鍔狅紒\",\"Automatically translated\"\n\"Convert Numeric to Factor\",\"灏嗘暟瀛楄浆鎹负鍥犲瓙\",\"Automatically translated\"\n\"Copy & paste data\",\"复制粘贴数据\",\"\"\n\"Copy / Paste\",\"复制粘贴\",\"\"\n\"Count\",\"鏁版暟\",\"Automatically translated\"\n\"Create a new column\",\"鍒涘缓涓€涓柊鍒�\",\"Automatically translated\"\n\"Create a new variable otherwise replaces the one selected\",\"鍒涘缓涓€涓柊鍙橀噺锛屽惁鍒欐浛鎹㈡墍閫夊彉閲�\",\"Automatically translated\"\n\"Create column\",\"鍒涘缓涓撴爮\",\"Automatically translated\"\n\"Create factor variable\",\"鍒涘缓鍥犲瓙鍙橀噺\",\"Automatically translated\"\n\"Data has %s observations and %s variables.\",\"数据有 %s 行 %s 列.\",\"\"\n\"Data ready to be imported!\",\"数据等待导入！\",\"\"\n\"Data successfully imported!\",\"数据导入成功！\",\"\"\n\"Data successfully updated!\",\"数据上传成功!\",\"\"\n\"Data wasn't deleted\",\"鏁版嵁娌℃湁琚垹闄�\",\"Automatically translated\"\n\"Data wasn't updated\",\"鏁版嵁鏈洿鏂�\",\"Automatically translated\"\n\"Dataset validation:\",\"鏁版嵁闆嗛獙璇侊細\",\"Automatically translated\"\n\"Date format:\",\"日期格式:\",\"\"\n\"Date to use as origin to convert date/datetime:\",\"日期转换的起始时间:\",\"\"\n\"Decimal separator:\",\"小数点:\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\",\"\"\n\"Delete\",\"删除\",\"\"\n\"Do you want to delete the selected row ?\",\"您要删除选定的行吗？\",\"\"\n\"Encoding:\",\"文件编码:\",\"\"\n\"Enter URL to data:\",\"杈撳叆鏁版嵁鐨� URL锛�\",\"Automatically translated\"\n\"Enter a shareable link to a GoogleSheet:\",\"输入GoogleSheet的共享链接:\",\"\"\n\"Enter an expression to define new column:\",\"杈撳叆琛ㄨ揪寮忔潵瀹氫箟鏂板垪锛�\",\"Automatically translated\"\n\"Environment\",\"环境\",\"\"\n\"Error\",\"错误\",\"\"\n\"External file\",\"外部文件\",\"\"\n\"Factor variable to reorder:\",\"瑕侀噸鏂版帓搴忕殑鍥犲瓙鍙橀噺锛�\",\"Automatically translated\"\n\"Failed\",\"失败\",\"\"\n\"First five rows are shown below:\",\"如下是前5行数据:\",\"\"\n\"Googlesheets\",\"Googlesheets\",\"\"\n\"Group calculation by:\",\"鍒嗙粍璁＄畻鏂瑰紡锛�\",\"Automatically translated\"\n\"Help\",\"帮助\",\"\"\n\"How to import data?\",\"如何导入数据？\",\"\"\n\"Import\",\"导入\",\"\"\n\"Import Google Spreadsheet\",\"导入Google数据文件\",\"\"\n\"Import Url\",\"瀵煎叆缃戝潃\",\"Automatically translated\"\n\"Import a dataset from an environment\",\"从环境中导入数据\",\"\"\n\"Import a file\",\"导入文件\",\"\"\n\"Import data\",\"导入数据\",\"\"\n\"Imported data\",\"瀵煎叆鏁版嵁\",\"Automatically translated\"\n\"Include lowest value\",\"鍖呮嫭鏈€浣庡€�\",\"Automatically translated\"\n\"Information\",\"信息\",\"\"\n\"Item has been modified\",\"项目已修改\",\"\"\n\"Levels\",\"绾у埆\",\"Automatically translated\"\n\"List of data.frame...\",\"所有数据文件\",\"\"\n\"Max:\",\"鏈€澶ч檺搴︼細\",\"Automatically translated\"\n\"Mean:\",\"鎰忔€濇槸锛�\",\"Automatically translated\"\n\"Method:\",\"鏂规硶锛�\",\"Automatically translated\"\n\"Min:\",\"鍒嗛挓锛�\",\"Automatically translated\"\n\"Missing values characters:\",\"缂哄け鍊煎瓧绗︼細\",\"Automatically translated\"\n\"Missing:\",\"涓㈠け鐨勶細\",\"Automatically translated\"\n\"Most Common:\",\"鏈€甯歌鐨勶細\",\"Automatically translated\"\n\"New column name cannot be empty\",\"鏂板垪鍚嶄笉鑳戒负绌�\",\"Automatically translated\"\n\"New column name:\",\"鏂板垪鍚嶇О锛�\",\"Automatically translated\"\n\"No\",\"不\",\"\"\n\"No data selected!\",\"未选择数据！\",\"\"\n\"No data to display.\",\"无数据.\",\"\"\n\"No data.frame here...\",\"未检测到数据集...\",\"\"\n\"No file selected\",\"尚未选择文件\",\"\"\n\"No file selected:\",\"尚未选择文件\",\"\"\n\"Not a data.frame\",\"涓嶆槸鏁版嵁妗�\",\"Automatically translated\"\n\"Nothing pasted yet!\",\"尚未粘贴任何数据!\",\"\"\n\"Number of breaks:\",\"浼戞伅娆℃暟锛�\",\"Automatically translated\"\n\"Number of rows:\",\"行数:\",\"\"\n\"OK\",\"OK\",\"\"\n\"Ooops\",\"啊\",\"\"\n\"Paste data here:\",\"粘贴位置:\",\"\"\n\"Please copy and paste some data in the dialog box above.\",\"请在上面的对话框中复制粘贴数据.\",\"\"\n\"Please fill in the required fields\",\"请填写必填字段\",\"\"\n\"Please paste a valid GoogleSheet link in the dialog box above.\",\"链接无效，请核对链接.\",\"\"\n\"Please paste a valid link in the dialog box above.\",\"璇峰湪涓婇潰鐨勫璇濇涓矘璐存湁鏁堢殑閾炬帴銆�\",\"Automatically translated\"\n\"Registered\",\"挂号的\",\"\"\n\"Required field\",\"必填项目\",\"\"\n\"Row has been saved\",\"行已保存”\",\"\"\n\"Row was not deleted\",\"行未删除\",\"\"\n\"Rows to skip before reading data:\",\"璇诲彇鏁版嵁涔嬪墠瑕佽烦杩囩殑琛岋細\",\"Automatically translated\"\n\"Sample data by :\",\"鏍锋湰鏁版嵁锛�\",\"Automatically translated\"\n\"Save\",\"节省\",\"\"\n\"Select\",\"选择\",\"\"\n\"Select a data.frame:\",\"选择数据文件:\",\"\"\n\"Select an environment in which to search:\",\"选择搜索环境:\",\"\"\n\"Select environment\",\"选择环境\",\"\"\n\"Select sheet to import:\",\"选择工作簿:\",\"\"\n\"Some operations are not allowed\",\"鏈変簺鎿嶄綔鏄笉鍏佽鐨�\",\"Automatically translated\"\n\"Something went wrong...\",\"出错了...\",\"\"\n\"Sort count\",\"鎺掑簭璁℃暟\",\"Automatically translated\"\n\"The URL that appear in your browser, in that case the current sheet will be read\",\"浏览器复制链接，我们将导入当前工作簿的数据\",\"\"\n\"The row has been deleted\",\"该行已被删除\",\"\"\n\"The row wasn't added to the data\",\"璇ヨ鏈坊鍔犲埌鏁版嵁涓�\",\"Automatically translated\"\n\"URL\",\"缃戝潃\",\"Automatically translated\"\n\"Unable to add the row, contact the platform administrator\",\"无法添加行，联系平台管理员\",\"\"\n\"Unable to delete the row, contact platform administrator\",\"无法删除行，联系平台管理员\",\"\"\n\"Unable to modify the item, contact the platform administrator\",\"无法修改物品，联系平台管理员\",\"\"\n\"Unique values:\",\"鐙壒鐨勪环鍊艰锛�\",\"Automatically translated\"\n\"Unique:\",\"鐙壒鐨勶細\",\"Automatically translated\"\n\"Update\",\"更新\",\"\"\n\"Update & select variables\",\"选择并更新数据\",\"\"\n\"Update factor variable\",\"鏇存柊鍥犲瓙鍙橀噺\",\"Automatically translated\"\n\"Update levels of a factor\",\"鏇存柊鍥犲瓙鐨勬按骞�\",\"Automatically translated\"\n\"Update row\",\"更新行\",\"\"\n\"Upload a file:\",\"上传文件:\",\"\"\n\"Use a data.frame from your environment or from the environment of a package.\",\"使用工作环境中或R包中数据集.\",\"\"\n\"Valid number of columns\",\"鏈夋晥鍒楁暟\",\"Automatically translated\"\n\"Valid number of rows\",\"鏈夋晥琛屾暟\",\"Automatically translated\"\n\"Validate\",\"验证\",\"\"\n\"Validation:\",\"验证:\",\"\"\n\"Variable to cut:\",\"瑕佸壀鍒囩殑鍙橀噺锛�\",\"Automatically translated\"\n\"View\",\"预览\",\"\"\n\"Warning\",\"璀﹀憡\",\"Automatically translated\"\n\"Yes\",\"是的\",\"\"\n\"You can either use:\",\"你还可以使用:\",\"\"\n\"You can import %s files\",\"你可以上传 %s 个文件\",\"\"\n\"You can import from flat table format supported by\",\"鎮ㄥ彲浠ヤ粠鏀寔鐨勫钩闈㈣〃鏍兼牸寮忓鍏�\",\"Automatically translated\"\n\"click to see data\",\"数据预览\",\"\"\n\"data has %s obs. of %s variables.\",\"数据有 %s 行 %s 列.\",\"\"\n\"if several use a comma ',' to separate them\",\"濡傛灉澶氫釜浣跨敤閫楀彿鈥�,鈥濆垎闅�\",\"Automatically translated\"\n\"lines, i.e.\",\"绾匡紝鍗�\",\"Automatically translated\"\n\"number of rows\",\"琛屾暟\",\"Automatically translated\"\n\"proportion of rows\",\"琛岀殑姣斾緥\",\"Automatically translated\"\n\"rows\",\"琛�\",\"Automatically translated\"\n\"then enter an expression before clicking on the button above to validate or on \",\"鐒跺悗杈撳叆涓€涓〃杈惧紡锛岀劧鍚庡崟鍑讳笂闈㈢殑鎸夐挳杩涜楠岃瘉鎴�\",\"Automatically translated\"\n\"to delete it.\",\"鍒犻櫎瀹冦€�\",\"Automatically translated\"\n\"Sort by count\",\"鎸夋暟閲忔帓搴�\",\"Automatically translated\"\n\"Sort by levels\",\"鎸夌骇鍒帓搴�\",\"Automatically translated\"\n"
  },
  {
    "path": "inst/i18n/de.csv",
    "content": "\"label\",\"translation\",\"comment\"\n\"% of the total\",\"% von allen\",\"Automatically translated\"\n\"% of the total, i.e.\",\"% der Gesamtmenge, d.h.\",\"Automatically translated\"\n\"A shareable link, in that case first sheet will be read\",\"Ein teilbarer Link, in diesem Fall wird das erste Arbeitsblatt eingelesen\",\"\"\n\"Add a label to data\",\"Bezeichnung zu Daten hinzufügen\",\"\"\n\"Add a row\",\"Fügen Sie eine Zeile hinzu\",\"\"\n\"Apply changes\",\"Änderungen übernehmen\",\"\"\n\"Browse...\",\"Durchsuchen...\",\"\"\n\"Cancel\",\"Absagen\",\"\"\n\"Choose a name for the column to be created or modified,\",\"Wählen Sie einen Namen für die Spalte, die erstellt oder geändert werden soll.\",\"Automatically translated\"\n\"Choose a number of rows :\",\"Wählen Sie eine Anzahl von Zeilen:\",\"Automatically translated\"\n\"Choose a percentage :\",\"Wählen Sie einen Prozentsatz:\",\"Automatically translated\"\n\"Click on a column name to add it to the expression:\",\"Klicken Sie auf einen Spaltennamen, um ihn dem Ausdruck hinzuzufügen:\",\"Automatically translated\"\n\"Click to delete\",\"Zum Löschen klicken\",\"\"\n\"Click to edit\",\"Zum Bearbeiten anklicken\",\"\"\n\"Close\",\"Schließen\",\"\"\n\"Close intervals on the right\",\"Schließen Sie die Intervalle rechts\",\"Automatically translated\"\n\"Column added!\",\"Spalte hinzugefügt!\",\"Automatically translated\"\n\"Convert Numeric to Factor\",\"Numerisch in Faktor umwandeln\",\"Automatically translated\"\n\"Copy & paste data\",\"Daten hier Kopieren und Einfügen\",\"\"\n\"Copy / Paste\",\"Kopieren / Einfügen\",\"\"\n\"Count\",\"Zählen\",\"Automatically translated\"\n\"Create a new column\",\"Erstellen Sie eine neue Spalte\",\"Automatically translated\"\n\"Create a new variable otherwise replaces the one selected\",\"Erstellen Sie eine neue Variable, andernfalls ersetzt sie die ausgewählte\",\"Automatically translated\"\n\"Create column\",\"Spalte erstellen\",\"Automatically translated\"\n\"Create factor variable\",\"Faktorvariable erstellen\",\"Automatically translated\"\n\"Data has %s observations and %s variables.\",\"Daten haben %s Einträge und %s Variablen.\",\"\"\n\"Data ready to be imported!\",\"Daten bereit zum Import\",\"\"\n\"Data successfully imported!\",\"Daten erfolgreich importiert!\",\"\"\n\"Data successfully updated!\",\"Daten Aktualisierung erfolgreich !\",\"\"\n\"Data wasn't deleted\",\"Daten wurden nicht gelöscht\",\"Automatically translated\"\n\"Data wasn't updated\",\"Daten wurden nicht aktualisiert\",\"Automatically translated\"\n\"Dataset validation:\",\"Datensatzvalidierung:\",\"Automatically translated\"\n\"Date format:\",\"Datumsformat :\",\"\"\n\"Date to use as origin to convert date/datetime:\",\"Ursprungsdatum zur Umwandlung von Datum/Datum-Zeit  :\",\"\"\n\"Decimal separator:\",\"Dezimaltrennzeichen:\",\"\"\n\"Delete\",\"Löschen\",\"\"\n\"Do you want to delete the selected row ?\",\"Möchten Sie die ausgewählte Zeile löschen?\",\"\"\n\"Encoding:\",\"Codierung:\",\"\"\n\"Enter URL to data:\",\"Geben Sie die URL zu den Daten ein:\",\"Automatically translated\"\n\"Enter a shareable link to a GoogleSheet:\",\"Teilbaren GoogleSheet Link eingeben:\",\"\"\n\"Enter an expression to define new column:\",\"Geben Sie einen Ausdruck ein, um eine neue Spalte zu definieren:\",\"Automatically translated\"\n\"Environment\",\"Umgebung\",\"\"\n\"Error\",\"Fehler\",\"\"\n\"External file\",\"Externe Datei\",\"\"\n\"Factor variable to reorder:\",\"Neu anzuordnende Faktorvariable:\",\"Automatically translated\"\n\"Failed\",\"Fehlgeschlagen\",\"\"\n\"First five rows are shown below:\",\"Die ersten fünf Reihen werden unten angezeigt:\",\"\"\n\"Googlesheets\",\"Googlesheets\",\"\"\n\"Group calculation by:\",\"Gruppenberechnung nach:\",\"Automatically translated\"\n\"Help\",\"Hilfe\",\"\"\n\"How to import data?\",\"Wie sollen Daten importiert werden ?\",\"\"\n\"Import\",\"Importieren\",\"\"\n\"Import Google Spreadsheet\",\"GoogleSheet importieren\",\"\"\n\"Import Url\",\"URL importieren\",\"Automatically translated\"\n\"Import a dataset from an environment\",\"Importieren Sie ein Datenset aus einer Umgebung\",\"\"\n\"Import a file\",\"Datei importieren\",\"\"\n\"Import data\",\"Daten importieren\",\"\"\n\"Imported data\",\"Importierte Daten\",\"Automatically translated\"\n\"Include lowest value\",\"Geben Sie den niedrigsten Wert an\",\"Automatically translated\"\n\"Information\",\"Information\",\"\"\n\"Item has been modified\",\"Artikel wurde geändert\",\"\"\n\"Levels\",\"Ebenen\",\"Automatically translated\"\n\"List of data.frame...\",\"Liste der Daten-Tabellen\",\"\"\n\"Max:\",\"Maximal:\",\"Automatically translated\"\n\"Mean:\",\"Bedeuten:\",\"Automatically translated\"\n\"Method:\",\"Methode:\",\"Automatically translated\"\n\"Min:\",\"Mindest:\",\"Automatically translated\"\n\"Missing values characters:\",\"Fehlende Wertezeichen:\",\"Automatically translated\"\n\"Missing:\",\"Fehlen:\",\"Automatically translated\"\n\"Most Common:\",\"Am gebräuchlichsten:\",\"Automatically translated\"\n\"New column name cannot be empty\",\"Der neue Spaltenname darf nicht leer sein\",\"Automatically translated\"\n\"New column name:\",\"Neuer Spaltenname:\",\"Automatically translated\"\n\"No\",\"Nein\",\"\"\n\"No data selected!\",\"Keine Daten ausgewählt!\",\"\"\n\"No data to display.\",\"Keine Daten zum Anzeigen.\",\"\"\n\"No data.frame here...\",\"Keine Daten-Tabellen hier...\",\"\"\n\"No file selected\",\"Keine Datei ausgewählt\",\"\"\n\"No file selected:\",\"Keine Datei ausgewählt\",\"\"\n\"Not a data.frame\",\"Kein Datenrahmen\",\"Automatically translated\"\n\"Nothing pasted yet!\",\"Noch nichts eingefügt!\",\"\"\n\"Number of breaks:\",\"Anzahl Pausen:\",\"Automatically translated\"\n\"Number of rows:\",\"Anzahl Reihen :\",\"\"\n\"OK\",\"OK\",\"\"\n\"Ooops\",\"Ooops\",\"\"\n\"Paste data here:\",\"Daten hier einfügen:\",\"\"\n\"Please copy and paste some data in the dialog box above.\",\"Bitte Daten in obige Dialog-Box Kopieren und Einfügen.\",\"\"\n\"Please fill in the required fields\",\"Bitte füllen Sie die erforderlichen Felder aus\",\"\"\n\"Please paste a valid GoogleSheet link in the dialog box above.\",\"Bitte gültigen GoogleSheet Link in die Dialog-Box oben einfügen .\",\"\"\n\"Please paste a valid link in the dialog box above.\",\"Bitte fügen Sie einen gültigen Link in das Dialogfeld oben ein.\",\"Automatically translated\"\n\"Registered\",\"Eingetragen\",\"\"\n\"Required field\",\"Pflichtfeld\",\"\"\n\"Row has been saved\",\"Zeile wurde gespeichert\",\"\"\n\"Row was not deleted\",\"Zeile wurde nicht gelöscht\",\"\"\n\"Rows to skip before reading data:\",\"Vor dem Lesen der Daten zu überspringende Zeilen:\",\"Automatically translated\"\n\"Sample data by :\",\"Beispieldaten von:\",\"Automatically translated\"\n\"Save\",\"Speichern\",\"\"\n\"Select\",\"Auswählen\",\"\"\n\"Select a data.frame:\",\"Daten-Tabelle auswählen:\",\"\"\n\"Select an environment in which to search:\",\"Wählen Sie eine Umgebung aus, in der gesucht werden soll:\",\"\"\n\"Select environment\",\"Umgebung auswählen\",\"\"\n\"Select sheet to import:\",\"Arbeitsblatt zum Importieren auswählen:\",\"\"\n\"Some operations are not allowed\",\"Einige Vorgänge sind nicht zulässig\",\"Automatically translated\"\n\"Something went wrong...\",\"Etwas ist schief gelaufen...\",\"\"\n\"Sort count\",\"Anzahl sortieren\",\"Automatically translated\"\n\"The URL that appear in your browser, in that case the current sheet will be read\",\"Die URL die im Browser aufscheint, in diesem Fall wird das aktuielle Arbeitsblatt eingelesen\",\"\"\n\"The row has been deleted\",\"Die Zeile wurde gelöscht\",\"\"\n\"The row wasn't added to the data\",\"Die Zeile wurde nicht zu den Daten hinzugefügt\",\"Automatically translated\"\n\"URL\",\"URL\",\"Automatically translated\"\n\"Unable to add the row, contact the platform administrator\",\"Die Zeile kann nicht hinzugefügt werden. Wenden Sie sich an den Plattformadministrator\",\"\"\n\"Unable to delete the row, contact platform administrator\",\"Die Zeile kann nicht gelöscht werden. Wenden Sie sich an den Plattformadministrator\",\"\"\n\"Unable to modify the item, contact the platform administrator\",\"Das Element kann nicht geändert werden. Wenden Sie sich an den Plattformadministrator\",\"\"\n\"Unique values:\",\"Einzigartige Werte:\",\"Automatically translated\"\n\"Unique:\",\"Einzigartig:\",\"Automatically translated\"\n\"Update\",\"Aktualisieren\",\"\"\n\"Update & select variables\",\"Variablen aktualisieren & auswählen\",\"\"\n\"Update factor variable\",\"Faktorvariable aktualisieren\",\"Automatically translated\"\n\"Update levels of a factor\",\"Aktualisieren Sie die Ebenen eines Faktors\",\"Automatically translated\"\n\"Update row\",\"Zeile aktualisieren\",\"\"\n\"Upload a file:\",\"Datei hochladen :\",\"\"\n\"Use a data.frame from your environment or from the environment of a package.\",\"Benutze eine Daten-Tabelle aus der eigenen Umgebung oder der Umgebung eines Pakets.\",\"\"\n\"Valid number of columns\",\"Gültige Anzahl von Spalten\",\"Automatically translated\"\n\"Valid number of rows\",\"Gültige Anzahl von Zeilen\",\"Automatically translated\"\n\"Validate\",\"Validieren\",\"\"\n\"Validation:\",\"Validierung :\",\"\"\n\"Variable to cut:\",\"Variable zum Schneiden:\",\"Automatically translated\"\n\"View\",\"Ansehen\",\"\"\n\"Warning\",\"Warnung\",\"Automatically translated\"\n\"Yes\",\"Ja\",\"\"\n\"You can either use:\",\"Sie können entweder verwenden :\",\"\"\n\"You can import %s files\",\"Sie können %s Datein importieren\",\"\"\n\"You can import from flat table format supported by\",\"Sie können aus dem von unterstützten Flat-Table-Format importieren\",\"Automatically translated\"\n\"click to see data\",\"klicken, um Daten anzuzeigen\",\"\"\n\"data has %s obs. of %s variables.\",\"Daten haben %s Einträge und %s Variablen.\",\"\"\n\"if several use a comma ',' to separate them\",\"Bei mehreren verwenden Sie zur Trennung ein Komma „,“.\",\"Automatically translated\"\n\"lines, i.e.\",\"Linien, d.h.\",\"Automatically translated\"\n\"number of rows\",\"Anzahl der Reihen\",\"Automatically translated\"\n\"proportion of rows\",\"Anteil der Reihen\",\"Automatically translated\"\n\"rows\",\"Reihen\",\"Automatically translated\"\n\"then enter an expression before clicking on the button above to validate or on \",\"Geben Sie dann einen Ausdruck ein, bevor Sie zum Bestätigen oder Einschalten auf die Schaltfläche oben klicken\",\"Automatically translated\"\n\"to delete it.\",\"um es zu löschen.\",\"Automatically translated\"\n\"Sort by count\",\"Nach Anzahl sortieren\",\"Automatically translated\"\n\"Sort by levels\",\"Nach Ebenen sortieren\",\"Automatically translated\"\n"
  },
  {
    "path": "inst/i18n/es.csv",
    "content": "\"label\",\"translation\",\"comment\"\n\"% of the total\",\"% del total\",\"Automatically translated\"\n\"% of the total, i.e.\",\"% del total, es decir\",\"Automatically translated\"\n\"A shareable link, in that case first sheet will be read\",\"Un enlace compartible, en ese caso, primera hoja se leerá\",\"\"\n\"Add a label to data\",\"Añadir una etiqueta a los datos\",\"\"\n\"Add a row\",\"Agregar una fila\",\"\"\n\"Apply changes\",\"Aplicar cambios\",\"\"\n\"Browse...\",\"Explorar...\",\"\"\n\"Cancel\",\"Cancelar\",\"\"\n\"Choose a name for the column to be created or modified,\",\"Elija un nombre para la columna que se creará o modificará,\",\"Automatically translated\"\n\"Choose a number of rows :\",\"Elija una cantidad de filas:\",\"Automatically translated\"\n\"Choose a percentage :\",\"Elige un porcentaje:\",\"Automatically translated\"\n\"Click on a column name to add it to the expression:\",\"Haga clic en el nombre de una columna para agregarla a la expresión:\",\"Automatically translated\"\n\"Click to delete\",\"Haga clic para eliminar\",\"\"\n\"Click to edit\",\"Haz click para editar\",\"\"\n\"Close\",\"Cerrar\",\"\"\n\"Close intervals on the right\",\"Cerrar intervalos a la derecha\",\"Automatically translated\"\n\"Column added!\",\"¡Columna agregada!\",\"Automatically translated\"\n\"Convert Numeric to Factor\",\"Convertir numérico a factor\",\"Automatically translated\"\n\"Copy & paste data\",\"Copiar y pegar datos\",\"Automatically translated\"\n\"Copy / Paste\",\"Copiar / Pegar\",\"\"\n\"Count\",\"Contar\",\"Automatically translated\"\n\"Create a new column\",\"Crear una nueva columna\",\"Automatically translated\"\n\"Create a new variable otherwise replaces the one selected\",\"Crea una nueva variable, de lo contrario reemplaza la seleccionada\",\"Automatically translated\"\n\"Create column\",\"Crear columna\",\"Automatically translated\"\n\"Create factor variable\",\"Crear variable de factor\",\"Automatically translated\"\n\"Data has %s observations and %s variables.\",\"Los datos tienen %s obs. de %s variables.\",\"\"\n\"Data ready to be imported!\",\"¡Datos listos para ser importados!\",\"Automatically translated\"\n\"Data successfully imported!\",\"Datos importados con éxito!\",\"\"\n\"Data successfully updated!\",\"Datos actualizados con éxito!\",\"\"\n\"Data wasn't deleted\",\"Los datos no fueron eliminados\",\"Automatically translated\"\n\"Data wasn't updated\",\"Los datos no fueron actualizados.\",\"Automatically translated\"\n\"Dataset validation:\",\"Validación del conjunto de datos:\",\"Automatically translated\"\n\"Date format:\",\"Formato de fecha :\",\"\"\n\"Date to use as origin to convert date/datetime:\",\"Fecha a usar como origen para convertir fecha/datetime :\",\"\"\n\"Decimal separator:\",\"Separador decimal :\",\"\"\n\"Delete\",\"Borrar\",\"\"\n\"Do you want to delete the selected row ?\",\"¿Desea eliminar la fila seleccionada?\",\"\"\n\"Encoding:\",\"Codificación :\",\"\"\n\"Enter URL to data:\",\"Ingrese la URL a los datos:\",\"Automatically translated\"\n\"Enter a shareable link to a GoogleSheet:\",\"Introduzca un enlace compartible a un archivo de GoogleSheet:\",\"\"\n\"Enter an expression to define new column:\",\"Ingrese una expresión para definir una nueva columna:\",\"Automatically translated\"\n\"Environment\",\"Entorno\",\"\"\n\"Error\",\"Error\",\"\"\n\"External file\",\"Archivo externo\",\"\"\n\"Factor variable to reorder:\",\"Variable factorial a reordenar:\",\"Automatically translated\"\n\"Failed\",\"Falló\",\"\"\n\"First five rows are shown below:\",\"Las cinco primeras filas se muestran a continuación:\",\"\"\n\"Googlesheets\",\"Archivos de GoogleSheet\",\"\"\n\"Group calculation by:\",\"Cálculo de grupo por:\",\"Automatically translated\"\n\"Help\",\"Ayuda\",\"\"\n\"How to import data?\",\"¿Cómo importar datos?\",\"\"\n\"Import\",\"Importar\",\"\"\n\"Import Google Spreadsheet\",\"Importar hoja de cálculo de Google\",\"Automatically translated\"\n\"Import Url\",\"Importar URL\",\"Automatically translated\"\n\"Import a dataset from an environment\",\"Importar un conjunto de datos desde un entorno\",\"Automatically translated\"\n\"Import a file\",\"Importar un archivo\",\"Automatically translated\"\n\"Import data\",\"Importar datos\",\"\"\n\"Imported data\",\"Datos importados\",\"Automatically translated\"\n\"Include lowest value\",\"Incluir el valor más bajo\",\"Automatically translated\"\n\"Information\",\"Información\",\"\"\n\"Item has been modified\",\"El artículo ha sido modificado\",\"\"\n\"Levels\",\"Niveles\",\"Automatically translated\"\n\"List of data.frame...\",\"Lista de data.frame...\",\"\"\n\"List of data.frame...\",\"Lista de data.frame...\",\"\"\n\"Max:\",\"Máximo:\",\"Automatically translated\"\n\"Mean:\",\"Significar:\",\"Automatically translated\"\n\"Method:\",\"Método:\",\"Automatically translated\"\n\"Min:\",\"Mínimo:\",\"Automatically translated\"\n\"Missing values characters:\",\"Caracteres de valores faltantes:\",\"Automatically translated\"\n\"Missing:\",\"Desaparecido:\",\"Automatically translated\"\n\"Most Common:\",\"Más común:\",\"Automatically translated\"\n\"New column name cannot be empty\",\"El nombre de la nueva columna no puede estar vacío\",\"Automatically translated\"\n\"New column name:\",\"Nuevo nombre de columna:\",\"Automatically translated\"\n\"No\",\"No\",\"\"\n\"No\",\"No\",\"\"\n\"No data selected!\",\"No hay datos seleccionados!\",\"\"\n\"No data to display.\",\"No hay datos para mostrar.\",\"\"\n\"No data.frame here...\",\"No hay data.frame aquí...\",\"\"\n\"No file selected\",\"No hay archivo seleccionado\",\"\"\n\"No file selected:\",\"No hay archivo seleccionado :\",\"\"\n\"Not a data.frame\",\"No es un marco de datos\",\"Automatically translated\"\n\"Nothing pasted yet!\",\"Aún no se ha pegado nada!\",\"\"\n\"Number of breaks:\",\"Número de descansos:\",\"Automatically translated\"\n\"Number of rows:\",\"Número de filas :\",\"\"\n\"OK\",\"Aceptar\",\"\"\n\"Ooops\",\"Ups\",\"\"\n\"Paste data here:\",\"Pegar datos aquí :\",\"\"\n\"Please copy and paste some data in the dialog box above.\",\"Por favor, copie y pegue algún dato en la caja de diálogo anterior.\",\"\"\n\"Please fill in the required fields\",\"Por favor llene los campos requeridos\",\"\"\n\"Please paste a valid GoogleSheet link in the dialog box above.\",\"Por favor, pegue un enlace válido a un archivo de GoogleSheet en la caja de diálogo anterior.\",\"\"\n\"Please paste a valid link in the dialog box above.\",\"Pegue un enlace válido en el cuadro de diálogo de arriba.\",\"Automatically translated\"\n\"Registered\",\"Registrado\",\"\"\n\"Required field\",\"Campo requerido\",\"\"\n\"Row has been saved\",\"Se ha guardado la fila\",\"\"\n\"Row was not deleted\",\"La fila no fue eliminada\",\"\"\n\"Rows to skip before reading data:\",\"Filas que se deben omitir antes de leer los datos:\",\"Automatically translated\"\n\"Sample data by :\",\"Datos de muestra por:\",\"Automatically translated\"\n\"Save\",\"Ahorrar\",\"\"\n\"Select\",\"Seleccione\",\"\"\n\"Select a data.frame:\",\"Seleccionar un data.frame :\",\"\"\n\"Select an environment in which to search:\",\"Seleccionar un entorno en el que buscar :\",\"\"\n\"Select environment\",\"Seleccionar entorno\",\"\"\n\"Select sheet to import:\",\"Seleccionar hoja para importar :\",\"\"\n\"Some operations are not allowed\",\"Algunas operaciones no están permitidas.\",\"Automatically translated\"\n\"Something went wrong...\",\"Algo salió mal...\",\"\"\n\"Sort count\",\"Ordenar recuento\",\"Automatically translated\"\n\"The URL that appear in your browser, in that case the current sheet will be read\",\"La URL que aparece en su navegador, en ese caso, la hoja actual se leerá\",\"\"\n\"The row has been deleted\",\"La fila ha sido eliminada\",\"\"\n\"The row wasn't added to the data\",\"La fila no se agregó a los datos.\",\"Automatically translated\"\n\"URL\",\"URL\",\"Automatically translated\"\n\"Unable to add the row, contact the platform administrator\",\"No se puede agregar la fila, comuníquese con el administrador de la plataforma\",\"\"\n\"Unable to delete the row, contact platform administrator\",\"No se puede eliminar la fila, comuníquese con el administrador de la plataforma\",\"\"\n\"Unable to modify the item, contact the platform administrator\",\"No se puede modificar el elemento, comuníquese con el administrador de la plataforma\",\"\"\n\"Unique values:\",\"Valores únicos:\",\"Automatically translated\"\n\"Unique:\",\"Único:\",\"Automatically translated\"\n\"Update\",\"Actualizar\",\"\"\n\"Update & select variables\",\"Actualizar y seleccionar variables\",\"Automatically translated\"\n\"Update factor variable\",\"Variable de factor de actualización\",\"Automatically translated\"\n\"Update levels of a factor\",\"Actualizar niveles de un factor\",\"Automatically translated\"\n\"Update row\",\"Actualizar fila\",\"\"\n\"Upload a file:\",\"Subir un archivo :\",\"\"\n\"Use a data.frame from your environment or from the environment of a package.\",\"Usar un data.frame de su entorno o del entorno de un paquete.\",\"\"\n\"Valid number of columns\",\"Número válido de columnas\",\"Automatically translated\"\n\"Valid number of rows\",\"Número válido de filas\",\"Automatically translated\"\n\"Validate\",\"Validar\",\"\"\n\"Validation:\",\"Validación:\",\"Automatically translated\"\n\"Variable to cut:\",\"Variable a cortar:\",\"Automatically translated\"\n\"View\",\"Visualizar\",\"\"\n\"Warning\",\"Advertencia\",\"Automatically translated\"\n\"Yes\",\"Sí\",\"\"\n\"Yes\",\"Sí\",\"\"\n\"You can either use:\",\"Puede usar:\",\"\"\n\"You can import %s files\",\"Puede importar %s archivos\",\"\"\n\"You can import from flat table format supported by\",\"Puede importar desde el formato de tabla plana compatible con\",\"Automatically translated\"\n\"click to see data\",\"click para ver datos\",\"Automatically translated\"\n\"data has %s obs. of %s variables.\",\"Los datos tienen %s obs. de %s variables.\",\"\"\n\"if several use a comma ',' to separate them\",\"si son varios use una coma ',' para separarlos\",\"Automatically translated\"\n\"lines, i.e.\",\"líneas, es decir\",\"Automatically translated\"\n\"number of rows\",\"número de filas\",\"Automatically translated\"\n\"proportion of rows\",\"proporción de filas\",\"Automatically translated\"\n\"rows\",\"filas\",\"Automatically translated\"\n\"then enter an expression before clicking on the button above to validate or on \",\"luego ingrese una expresión antes de hacer clic en el botón de arriba para validar o en\",\"Automatically translated\"\n\"to delete it.\",\"para borrarlo.\",\"Automatically translated\"\n\"Sort by count\",\"Ordenar por conteo\",\"Automatically translated\"\n\"Sort by levels\",\"Ordenar por niveles\",\"Automatically translated\"\n"
  },
  {
    "path": "inst/i18n/extract_labels.R",
    "content": "#' Function to extract labels\n#'\n#' @param folder file directory\n#'\n#' @return an extraction of the labels contained in the directory files\n#' @importFrom stringr str_subset str_extract_all str_remove_all\n#' @export\n#'\n#' @examples extract_labels(folder = \"R\")\nextract_labels <- function(folder = \"R\") {\n  files <- list.files(folder)\n  list_extractions <- lapply(\n    X = files,\n    FUN = function(file) {\n      read_file <- readLines(file.path(folder, file))\n      extraction <- str_extract_all(\n        string = str_subset(read_file, \"i18n\"),\n        pattern = 'i18n\\\\(\".*?\"\\\\)'\n      ) |>\n        unlist()\n      extraction\n    }\n  )\n  extract_labels <- unlist(list_extractions, recursive = TRUE)\n  str_remove_all(unique(extract_labels), paste(c(\"i18n\", \"\\\"\", \"\\\\)\", \"\\\\(\"), collapse = \"|\"))\n}\n\n\n\n#' Update all csvs that are in inst/i18n\n#'\n#' @param labels results of label extractions\n#' @param lang the language that you want to translate the text into. See polyglotr::google_supported_languages for the Table with the codes of available languages\n#' @param lang_csv the name of the csv file\n#' @param translation TRUE or FALSE if you want to translate the language\n#' @param ... other arguments passed to datamods::translate_labels\n#'\n#' @return all csvs updated\n#' @importFrom data.table merge fwrite data.table fread unique\n#' @export\n#'\n#' @examples update_csv(labels = extract_labels(folder = \"R\"))\n#' new_csv_fr <- fread(\"inst/i18n/fr.csv\")\nupdate_csv <- function(labels,\n                       lang,\n                       lang_csv,\n                       translation = TRUE,\n                       ...) {\n  old <- fread(file = sprintf(\"inst/i18n/%s.csv\", lang_csv), encoding = \"UTF-8\", fill = TRUE)\n  new <- merge(\n    x = data.table(label = unique(labels)),\n    y = old,\n    by = \"label\",\n    all.x = TRUE\n  )\n\n  if (isTRUE(translation)) {\n    final <- rbind(\n      new[!is.na(translation)],\n      translate_labels(labels = new[is.na(translation)]$label, target_language = lang, ...),\n      fill = TRUE\n    )\n  } else {\n    final <- new\n  }\n\n  fwrite(final, file = sprintf(\"inst/i18n/%s.csv\", lang_csv), row.names = FALSE, na = '', quote = TRUE)\n}\n\n\n\n#' Translate labels\n#'\n#' @param labels labels to translate\n#' @param source_language the language that you want to translate the text into. See polyglotr::google_supported_languages for the Table with the codes of available languages\n#' @param target_language the language of the text that you want to translate. See polyglotr::google_supported_languages for the Table with the codes of available languages\n#' @param encoding Name of encoding. See stringi::stri_enc_list() for a complete list\n#'\n#' @importFrom polyglotr google_translate\n#' @importFrom stringr str_conv\n#' @importFrom data.table data.table\n#'\n#' @return a data frame with translated labels\n#' @export\n#'\n#' @examples translate_labels(labels = extract_labels(folder = \"R\"))\ntranslate_labels <- function(labels,\n                             source_language = \"en\",\n                             target_language = \"fr\",\n                             encoding = \"UTF-8\") {\n\n  translation <- polyglotr::google_translate(\n    text = labels,\n    target_language = target_language,\n    source_language = source_language\n  )\n  data.table(\n    label = labels,\n    translation = translation |>\n      unlist() |>\n      str_conv(encoding),\n    comment = \"Automatically translated\"\n  )\n}\n\n"
  },
  {
    "path": "inst/i18n/fr.csv",
    "content": "\"label\",\"translation\",\"comment\"\n\"% of the total\",\"% du total\",\"Automatically translated\"\n\"% of the total, i.e.\",\"% du total, soit\",\"Automatically translated\"\n\"A shareable link, in that case first sheet will be read\",\"Un lien partageable, dans ce cas la première feuille sera lue\",\"\"\n\"Add a label to data\",\"Ajouter un libellé aux données\",\"\"\n\"Add a row\",\"Ajouter\",\"\"\n\"Apply changes\",\"Appliquer les changements\",\"\"\n\"Browse...\",\"Parcourir...\",\"\"\n\"Cancel\",\"Annuler\",\"\"\n\"Choose a name for the column to be created or modified,\",\"Choisissez un nom pour la colonne à créer ou à modifier,\",\"Automatically translated\"\n\"Choose a number of rows :\",\"Choisissez un nombre de lignes :\",\"Automatically translated\"\n\"Choose a percentage :\",\"Choisissez un pourcentage :\",\"Automatically translated\"\n\"Click on a column name to add it to the expression:\",\"Cliquez sur un nom de colonne pour l'ajouter à l'expression :\",\"Automatically translated\"\n\"Click to delete\",\"Cliquez pour supprimer\",\"\"\n\"Click to edit\",\"Cliquez pour modifier\",\"\"\n\"Close\",\"Fermer\",\"\"\n\"Close intervals on the right\",\"Intervalles rapprochés à droite\",\"Automatically translated\"\n\"Column added!\",\"Colonne ajoutée !\",\"Automatically translated\"\n\"Convert Numeric to Factor\",\"Convertir un numérique en facteur\",\"Automatically translated\"\n\"Copy & paste data\",\"Copier / coller des données\",\"\"\n\"Copy / Paste\",\"Copier / Coller\",\"\"\n\"Count\",\"Compter\",\"Automatically translated\"\n\"Create a new column\",\"Créer une nouvelle colonne\",\"Automatically translated\"\n\"Create a new variable otherwise replaces the one selected\",\"Créer une nouvelle variable sinon remplace celle sélectionnée\",\"Automatically translated\"\n\"Create column\",\"Créer une colonne\",\"Automatically translated\"\n\"Create factor variable\",\"Créer une variable de facteur\",\"Automatically translated\"\n\"Data has %s observations and %s variables.\",\"Les données ont %s observations et %s variables.\",\"\"\n\"Data ready to be imported!\",\"Données prêtes à être importées\",\"\"\n\"Data successfully imported!\",\"Données importées avec succès\",\"\"\n\"Data successfully updated!\",\"Données mises à jour avec succès !\",\"\"\n\"Data wasn't deleted\",\"Les données n'ont pas été supprimées\",\"Automatically translated\"\n\"Data wasn't updated\",\"Les données n'ont pas été mises à jour\",\"Automatically translated\"\n\"Dataset validation:\",\"Validation de l'ensemble de données :\",\"Automatically translated\"\n\"Date format:\",\"Format des dates :\",\"\"\n\"Date to use as origin to convert date/datetime:\",\"Date à utiliser comme origine pour convertir des dates au format numérique :\",\"\"\n\"Decimal separator:\",\"Séparateur de décimal :\",\"\"\n\"Delete\",\"Effacer\",\"\"\n\"Do you want to delete the selected row ?\",\"Voulez-vous supprimer la ligne sélectionnée ?\",\"\"\n\"Encoding:\",\"Encodage :\",\"\"\n\"Enter URL to data:\",\"Entrez l'URL des données :\",\"Automatically translated\"\n\"Enter a shareable link to a GoogleSheet:\",\"Entrez un lien partageable vers une GoogleSheet :\",\"\"\n\"Enter an expression to define new column:\",\"Entrez une expression pour définir une nouvelle colonne :\",\"Automatically translated\"\n\"Environment\",\"Environnement\",\"\"\n\"Error\",\"Erreur\",\"\"\n\"External file\",\"Fichier\",\"\"\n\"Factor variable to reorder:\",\"Variable de facteur à réorganiser :\",\"Automatically translated\"\n\"Failed\",\"Echec\",\"\"\n\"First five rows are shown below:\",\"Les cinq premières lignes sont affichées ci-dessous :\",\"\"\n\"Googlesheets\",\"Googlesheets\",\"\"\n\"Group calculation by:\",\"Calcul de groupe par :\",\"Automatically translated\"\n\"Help\",\"Aide\",\"\"\n\"How to import data?\",\"Comment importer des données ?\",\"\"\n\"Import\",\"Import\",\"\"\n\"Import Google Spreadsheet\",\"Importer une GoogleSheet\",\"\"\n\"Import Url\",\"URL d'importation\",\"Automatically translated\"\n\"Import a dataset from an environment\",\"Importer un jeu de données depuis l'environnement global\",\"\"\n\"Import a file\",\"Import d'un fichier\",\"\"\n\"Import data\",\"Importer les données\",\"\"\n\"Imported data\",\"Données importées\",\"Automatically translated\"\n\"Include lowest value\",\"Inclure la valeur la plus basse\",\"Automatically translated\"\n\"Information\",\"Informations\",\"\"\n\"Item has been modified\",\"L'élément a été modifié\",\"\"\n\"Levels\",\"Les niveaux\",\"Automatically translated\"\n\"List of data.frame...\",\"Liste des tableau de données\",\"\"\n\"Max:\",\"Maximale :\",\"Automatically translated\"\n\"Mean:\",\"Signifier:\",\"Automatically translated\"\n\"Method:\",\"Méthode:\",\"Automatically translated\"\n\"Min:\",\"Min :\",\"Automatically translated\"\n\"Missing values characters:\",\"Caractères de valeurs manquants :\",\"Automatically translated\"\n\"Missing:\",\"Manquant:\",\"Automatically translated\"\n\"Most Common:\",\"Le plus commun:\",\"Automatically translated\"\n\"New column name cannot be empty\",\"Le nom de la nouvelle colonne ne peut pas être vide\",\"Automatically translated\"\n\"New column name:\",\"Nouveau nom de colonne :\",\"Automatically translated\"\n\"No\",\"Non\",\"\"\n\"No data selected!\",\"Pas de données sélectionnées\",\"\"\n\"No data to display.\",\"Pas de données à afficher.\",\"\"\n\"No data.frame here...\",\"Pas de données ici...\",\"\"\n\"No file selected\",\"Pas de fichier sélectionné\",\"\"\n\"No file selected:\",\"Aucun fichier sélectionné\",\"\"\n\"Not a data.frame\",\"Pas un data.frame\",\"Automatically translated\"\n\"Nothing pasted yet!\",\"Rien n'a encore été collé !\",\"\"\n\"Number of breaks:\",\"Nombre de pauses :\",\"Automatically translated\"\n\"Number of rows:\",\"Nombre de lignes :\",\"\"\n\"OK\",\"OK\",\"\"\n\"Ooops\",\"Ooops\",\"\"\n\"Paste data here:\",\"Collez vos données ici :\",\"\"\n\"Please copy and paste some data in the dialog box above.\",\"Veuillez copier et coller certaines données dans la boîte de dialogue ci-dessus.\",\"\"\n\"Please fill in the required fields\",\"Merci de remplir les champs obligatoires\",\"\"\n\"Please paste a valid GoogleSheet link in the dialog box above.\",\"Veuillez coller un lien GoogleSheet valide dans la boîte de dialogue ci-dessus.\",\"\"\n\"Please paste a valid link in the dialog box above.\",\"Veuillez coller un lien valide dans la boîte de dialogue ci-dessus.\",\"Automatically translated\"\n\"Registered\",\"Enregistré\",\"\"\n\"Required field\",\"Champs requis\",\"\"\n\"Row has been saved\",\"La ligne a été enregistrée\",\"\"\n\"Row was not deleted\",\"La ligne n'a pas été supprimée\",\"\"\n\"Rows to skip before reading data:\",\"Lignes à ignorer avant de lire les données :\",\"Automatically translated\"\n\"Sample data by :\",\"Echantillonner les données selon :\",\"\"\n\"Save\",\"Enregistrer\",\"\"\n\"Select\",\"Sélectionner\",\"\"\n\"Select a data.frame:\",\"Sélectionner un data.frame :\",\"\"\n\"Select an environment in which to search:\",\"Sélectionner un environnement dans lequel rechercher :\",\"\"\n\"Select environment\",\"Sélectionner un environnement\",\"\"\n\"Select sheet to import:\",\"Sélectionner la feuille à importer :\",\"\"\n\"Some operations are not allowed\",\"Certaines opérations ne sont pas autorisées\",\"Automatically translated\"\n\"Something went wrong...\",\"Un problème est survenu...\",\"\"\n\"Sort count\",\"Nombre de tris\",\"Automatically translated\"\n\"The URL that appear in your browser, in that case the current sheet will be read\",\"L'URL qui apparaît dans votre navigateur, dans ce cas la feuille active sera lue\",\"\"\n\"The row has been deleted\",\"La ligne a été supprimée\",\"\"\n\"The row wasn't added to the data\",\"La ligne n'a pas été ajoutée aux données\",\"Automatically translated\"\n\"URL\",\"URL\",\"\"\n\"Unable to add the row, contact the platform administrator\",\"Impossible d'ajouter la ligne, contactez l'administrateur de la plateforme\",\"\"\n\"Unable to delete the row, contact platform administrator\",\"Impossible de supprimer la ligne, contactez l'administrateur de la plateforme\",\"\"\n\"Unable to modify the item, contact the platform administrator\",\"Impossible de modifier l'élément, contactez l'administrateur de la plateforme\",\"\"\n\"Unique values:\",\"Valeurs uniques :\",\"Automatically translated\"\n\"Unique:\",\"Unique:\",\"Automatically translated\"\n\"Update\",\"Modifier\",\"\"\n\"Update & select variables\",\"Modifier et sélectionner des variables\",\"\"\n\"Update factor variable\",\"Variable de facteur de mise à jour\",\"Automatically translated\"\n\"Update levels of a factor\",\"Mettre à jour les niveaux d'un facteur\",\"Automatically translated\"\n\"Update row\",\"Mettre à jour la ligne\",\"\"\n\"Upload a file:\",\"Charger un fichier :\",\"\"\n\"Use a data.frame from your environment or from the environment of a package.\",\"Utiliser un tableau de données de votre environnement ou de celui d'un paquet.\",\"\"\n\"Valid number of columns\",\"Nombre de colonnes valide\",\"Automatically translated\"\n\"Valid number of rows\",\"Nombre de lignes valide\",\"Automatically translated\"\n\"Validate\",\"Validation\",\"\"\n\"Validation:\",\"Validation :\",\"\"\n\"Variable to cut:\",\"Variable à couper :\",\"Automatically translated\"\n\"View\",\"Affichage\",\"\"\n\"Warning\",\"Avertissement\",\"Automatically translated\"\n\"Yes\",\"Oui\",\"\"\n\"You can either use:\",\"Vous pouvez utiliser au choix :\",\"\"\n\"You can import %s files\",\"Vous pouvez importer des fichers %s\",\"\"\n\"You can import from flat table format supported by\",\"Vous pouvez importer à partir du format de tableau plat pris en charge par\",\"Automatically translated\"\n\"click to see data\",\"cliquez pour afficher les données\",\"\"\n\"data has %s obs. of %s variables.\",\"les données ont %s observations et %s colonnes.\",\"\"\n\"if several use a comma ',' to separate them\",\"si plusieurs utilisent une virgule ',' pour les séparer\",\"Automatically translated\"\n\"lines, i.e.\",\"lignes, c'est-à-dire\",\"Automatically translated\"\n\"number of rows\",\"Nombre de lignes\",\"\"\n\"proportion of rows\",\"Proportion de lignes\",\"\"\n\"rows\",\"lignes\",\"Automatically translated\"\n\"then enter an expression before clicking on the button above to validate or on \",\"puis saisissez une expression avant de cliquer sur le bouton ci-dessus pour valider ou sur\",\"Automatically translated\"\n\"to delete it.\",\"pour le supprimer.\",\"Automatically translated\"\n\"Sort by count\",\"Trier par nombre\",\"Automatically translated\"\n\"Sort by levels\",\"Trier par niveaux\",\"Automatically translated\"\n"
  },
  {
    "path": "inst/i18n/it.csv",
    "content": "\"label\",\"translation\",\"comment\"\n\"% of the total\",\"% del totale\",\"Automatically translated\"\n\"% of the total, i.e.\",\"% del totale, cioè\",\"Automatically translated\"\n\"A shareable link, in that case first sheet will be read\",\"Un link condivisibile, in questo caso sarà letta la prima scheda\",\"\"\n\"Add a label to data\",\"Aggiungi un'etichetta ai dati\",\"\"\n\"Add a row\",\"Aggiungi una riga\",\"\"\n\"Apply changes\",\"Applica le modifiche\",\"\"\n\"Browse...\",\"Sfoglia...\",\"\"\n\"Cancel\",\"Annulla\",\"\"\n\"Choose a name for the column to be created or modified,\",\"Scegli un nome per la colonna da creare o modificare,\",\"Automatically translated\"\n\"Choose a number of rows :\",\"Scegli un numero di righe:\",\"Automatically translated\"\n\"Choose a percentage :\",\"Scegli una percentuale:\",\"Automatically translated\"\n\"Click on a column name to add it to the expression:\",\"Clicca sul nome di una colonna per aggiungerla all'espressione:\",\"Automatically translated\"\n\"Click to delete\",\"Clicca per eliminare\",\"\"\n\"Click to edit\",\"Clicca per modificare\",\"\"\n\"Close\",\"Chiudi\",\"\"\n\"Close intervals on the right\",\"Intervalli chiusi a destra\",\"Automatically translated\"\n\"Column added!\",\"Colonna aggiunta\",\"Automatically translated\"\n\"Convert Numeric to Factor\",\"Coverti una variabile numerica in una discreta\",\"Automatically translated\"\n\"Copy & paste data\",\"Copia e incolla i valori\",\"Automatically translated\"\n\"Copy / Paste\",\"Copia / Incolla\",\"\"\n\"Count\",\"Conteggio\",\"Automatically translated\"\n\"Create a new column\",\"Crea una nuova colonna\",\"Automatically translated\"\n\"Create a new variable otherwise replaces the one selected\",\"Crea una nuova variabile o sostituisci quella selezionata\",\"Automatically translated\"\n\"Create column\",\"Crea una colunna\",\"Automatically translated\"\n\"Create factor variable\",\"Crea una variabile discreta\",\"Automatically translated\"\n\"Data has %s observations and %s variables.\",\"I dati hanno %s osservazioni e %s variabili.\",\"\"\n\"Data ready to be imported!\",\"Dati pronti per l'importazione!\",\"Automatically translated\"\n\"Data successfully imported!\",\"Dati importati con successo!\",\"\"\n\"Data successfully updated!\",\"Dati aggiornati con successo!\",\"\"\n\"Data wasn't deleted\",\"I dati non sono stati eliminati\",\"Automatically translated\"\n\"Data wasn't updated\",\"I dati non sono stati aggiornati\",\"Automatically translated\"\n\"Dataset validation:\",\"Validazione del dataset:\",\"Automatically translated\"\n\"Date format:\",\"Formato della data:\",\"\"\n\"Date to use as origin to convert date/datetime:\",\"Data da usare come origine per convertire le date:\",\"\"\n\"Decimal separator:\",\"Separatore decimale:\",\"\"\n\"Delete\",\"Elimina\",\"\"\n\"Do you want to delete the selected row ?\",\"Vuoi eliminare la riga selezionata?\",\"\"\n\"Encoding:\",\"Codifica:\",\"\"\n\"Enter URL to data:\",\"Inserisci l'URL dei dati:\",\"Automatically translated\"\n\"Enter a shareable link to a GoogleSheet:\",\"Inserisci un link condivisibile di GoogleSheet:\",\"\"\n\"Enter an expression to define new column:\",\"Inserisci un'espressione per definire una nuova colonna:\",\"Automatically translated\"\n\"Environment\",\"Ambiente\",\"\"\n\"Error\",\"Errore\",\"\"\n\"External file\",\"File\",\"\"\n\"Factor variable to reorder:\",\"Variabile discreta da riordinare:\",\"Automatically translated\"\n\"Failed\",\"Fallito\",\"\"\n\"First five rows are shown below:\",\"Qui sotto sono mostrate le prime cinque righe:\",\"\"\n\"Googlesheets\",\"Googlesheets\",\"\"\n\"Group calculation by:\",\"Raggruppa per:\",\"Automatically translated\"\n\"Help\",\"Aiuto\",\"\"\n\"How to import data?\",\"Come importare i dati?\",\"\"\n\"Import\",\"Importare\",\"\"\n\"Import Google Spreadsheet\",\"Importa da Google Spreadsheet\",\"Automatically translated\"\n\"Import Url\",\"URL per l'importazione\",\"Automatically translated\"\n\"Import a dataset from an environment\",\"Importa il dataset da un'ambiente\",\"Automatically translated\"\n\"Import a file\",\"Importare un file\",\"Automatically translated\"\n\"Import data\",\"Importare dati\",\"\"\n\"Imported data\",\"Dati importati\",\"Automatically translated\"\n\"Include lowest value\",\"Includi il valore minore\",\"Automatically translated\"\n\"Information\",\"Informazione\",\"\"\n\"Item has been modified\",\"L'elemento è stato modificato\",\"\"\n\"Levels\",\"Livelli\",\"Automatically translated\"\n\"List of data.frame...\",\"Elenco dei data.frame...\",\"\"\n\"Max:\",\"Massimo:\",\"Automatically translated\"\n\"Mean:\",\"Media:\",\"Automatically translated\"\n\"Method:\",\"Metodo:\",\"Automatically translated\"\n\"Min:\",\"Minimo:\",\"Automatically translated\"\n\"Missing values characters:\",\"Identificativo per i valori mancanti:\",\"Automatically translated\"\n\"Missing:\",\"Mancante:\",\"Automatically translated\"\n\"Most Common:\",\"Il più frequente:\",\"Automatically translated\"\n\"New column name cannot be empty\",\"Il nome della nuova colonna non può essere vuoto\",\"Automatically translated\"\n\"New column name:\",\"Nuovo nome della colonna:\",\"Automatically translated\"\n\"No\",\"No\",\"\"\n\"No data selected!\",\"Nessun dato selezionato!\",\"\"\n\"No data to display.\",\"Nessun dato da mostrare.\",\"\"\n\"No data.frame here...\",\"Nessun data.frame...\",\"\"\n\"No file selected\",\"Nessun file selezionato\",\"\"\n\"No file selected:\",\"Nessun file selezionato:\",\"\"\n\"Not a data.frame\",\"Non è un data.frame\",\"Automatically translated\"\n\"Nothing pasted yet!\",\"Non è ancora stato incollato nulla!\",\"\"\n\"Number of breaks:\",\"Numero di intervalli:\",\"Automatically translated\"\n\"Number of rows:\",\"Numero di righe:\",\"\"\n\"OK\",\"OK\",\"\"\n\"Ooops\",\"Ooops\",\"\"\n\"Paste data here:\",\"Incolla i dati qui:\",\"\"\n\"Please copy and paste some data in the dialog box above.\",\"Copia e incolla i dati nel riquadro sovrastante.\",\"\"\n\"Please fill in the required fields\",\"Riempi i campi obbligatori\",\"\"\n\"Please paste a valid GoogleSheet link in the dialog box above.\",\"Incolla un link valido di GoogleSheet nel riquadro sovrastante.\",\"\"\n\"Please paste a valid link in the dialog box above.\",\"Incolla un link valido nel riquadro sovrastante.\",\"Automatically translated\"\n\"Registered\",\"Registrato\",\"\"\n\"Required field\",\"Campo obbligatorio\",\"\"\n\"Row has been saved\",\"La riga è stata salvata\",\"\"\n\"Row was not deleted\",\"La riga non è stata eliminata\",\"\"\n\"Rows to skip before reading data:\",\"Righe da ignorare prima della lettura dei dati:\",\"Automatically translated\"\n\"Sample data by :\",\"Campiona i dati per:\",\"Automatically translated\"\n\"Save\",\"Salva\",\"\"\n\"Select\",\"Seleziona\",\"\"\n\"Select a data.frame:\",\"Seleziona un data.frame :\",\"\"\n\"Select an environment in which to search:\",\"Seleziona un ambiente in cui cercare:\",\"\"\n\"Select environment\",\"Seleziona un ambiente\",\"\"\n\"Select sheet to import:\",\"Seleziona una scheda da importare:\",\"\"\n\"Some operations are not allowed\",\"Alcune operazioni non sono permesse\",\"Automatically translated\"\n\"Something went wrong...\",\"Qualcosa è andato storto...\",\"\"\n\"Sort count\",\"Ordina i conteggi\",\"Automatically translated\"\n\"The URL that appear in your browser, in that case the current sheet will be read\",\"L'URL nel tuo browser, in tal caso verrà letta la scheda corrente\",\"\"\n\"The row has been deleted\",\"La riga è stata eliminata\",\"\"\n\"The row wasn't added to the data\",\"La riga non è stata aggiunta ai dati\",\"Automatically translated\"\n\"URL\",\"URL\",\"Automatically translated\"\n\"Unable to add the row, contact the platform administrator\",\"Impossible aggiungere la riga, contatta l'amministratore del sistema\",\"\"\n\"Unable to delete the row, contact platform administrator\",\"Impossible eliminare la riga, contatta l'amministratore del sistema\",\"\"\n\"Unable to modify the item, contact the platform administrator\",\"Impossibile modificare l'elemento, contatta l'amministratore del sistema\",\"\"\n\"Unique values:\",\"Valori unici:\",\"Automatically translated\"\n\"Unique:\",\"Unico:\",\"Automatically translated\"\n\"Update\",\"Aggiorna\",\"\"\n\"Update & select variables\",\"Aggiorna e seleziona le variabili\",\"Automatically translated\"\n\"Update factor variable\",\"Aggiorna la variabile discreta\",\"Automatically translated\"\n\"Update levels of a factor\",\"Aggiorna i livelli della variabile discreta\",\"Automatically translated\"\n\"Update row\",\"Aggiorna la riga\",\"\"\n\"Upload a file:\",\"Carica un file:\",\"\"\n\"Use a data.frame from your environment or from the environment of a package.\",\"Usa un data.frame nel tuo ambiente o in un pacchetto.\",\"\"\n\"Valid number of columns\",\"Numero di colonne valido\",\"Automatically translated\"\n\"Valid number of rows\",\"Numero di righe valido\",\"Automatically translated\"\n\"Validate\",\"Validare\",\"\"\n\"Validation:\",\"Validazione:\",\"Automatically translated\"\n\"Variable to cut:\",\"Variabile da spezzare:\",\"Automatically translated\"\n\"View\",\"Visualizza\",\"\"\n\"Warning\",\"Attenzione\",\"Automatically translated\"\n\"Yes\",\"Sì\",\"\"\n\"Yes\",\"Sì\",\"\"\n\"You can either use:\",\"Puoi usare:\",\"\"\n\"You can import %s files\",\"Puoi importare %s file\",\"\"\n\"You can import from flat table format supported by\",\"Puoi importare tabelle nel formato supportato da\",\"Automatically translated\"\n\"click to see data\",\"clicca per vedere i dati\",\"Automatically translated\"\n\"data has %s obs. of %s variables.\",\"i dati hanno %s osservazioni e %s variabili.\",\"\"\n\"if several use a comma ',' to separate them\",\"se sono più d'uno separali con una virgola ','\",\"Automatically translated\"\n\"lines, i.e.\",\"righe, cioé\",\"Automatically translated\"\n\"number of rows\",\"numero di righe\",\"Automatically translated\"\n\"proportion of rows\",\"proporzione delle righe\",\"Automatically translated\"\n\"rows\",\"righe\",\"Automatically translated\"\n\"then enter an expression before clicking on the button above to validate or on \",\"quindi inserisci un'espressione prima di fare clic sul pulsante in alto per validare o su\",\"Automatically translated\"\n\"to delete it.\",\"per eliminarlo.\",\"Automatically translated\"\n\"Sort by count\",\"Ordina per conteggio\",\"Automatically translated\"\n\"Sort by levels\",\"Ordina per livello\",\"Automatically translated\""
  },
  {
    "path": "inst/i18n/ja.csv",
    "content": "label,translation,comment\n\"Import a dataset from an environment\",\"Global environment からデータセットをインポート\"\n\"Select a data.frame:\",\"データフレームを選択:\"\n\"List of data.frame...\",\"データフレームのリスト\"\n\"Select an environment in which to search:\",\"検索する environment を選択:\"\n\"Select environment\",\"environment を選択\"\n\"No data selected!\",\"データが選択されていません!\"\n\"Use a data.frame from your environment or from the environment of a package.\",\"ユーザーの環境やパッケージからデータフレームを使用\"\n\"No data.frame here...\",\"データフレームがありません\n\"Ooops\",\"おっと\"\n\"Something went wrong...\",\"問題が発生しました...\"\n\"Data successfully imported!\",\"データは正しくインポートされました!\"\n\"Data ready to be imported!\",\"データをインポートする準備ができました!\"\n\"data has %s obs. of %s variables.\",\"%s 行 %s 列のデータです。\"\n\"click to see data\",\"クリックしてデータを見る\"\n\"Import data\",\"データのインポート\"\n\"Import a file\",\"ファイルのインポート\"\n\"Upload a file:\",\"ファイルのアップロード:\"\n\"Browse...\",\"Browse...\"\n\"No file selected\",\"ファイルが選択されていません\"\n\"Number of rows to skip before reading data:\",\"データを読み込む前にスキップする行数:\"\n\"Decimal separator:\",\"小数点:\"\n\"Encoding:\",\"エンコード:\"\n\"Select sheet to import:\",\"インポートするシートを選択:\"\n\"No file selected:\",\"ファイルが選択されていません\"\n\"You can import %s files\",\"%s 個のファイルをインポートできます\"\n\"First five rows are shown below:\",\"最初の5行は以下の通り:\"\n\"Copy & paste data\",\"データをコピー/ペースト\"\n\"Paste data here:\",\"ここにデータをペースト:\"\n\"Nothing pasted yet!\",\"まだ何もペーストされていません!\"\n\"Please copy and paste some data in the dialog box above.\",\"上のダイアログボックスにデータをコピー&ペーストしてください。\"\n\"Import Google Spreadsheet\",\"Google スプレッドシートをインポート\"\n\"You can either use:\",\"こちらも利用できます:\"\n\"A shareable link, in that case first sheet will be read\",\"共有可能なリンク (先頭のシートが読み込まれます)\"\n\"The URL that appear in your browser, in that case the current sheet will be read\",\"ブラウザに表示されるリンク (現在のシートが読み込まれます)\"\n\"Enter a shareable link to a GoogleSheet:\",\"GoogleSheet への共有可能なリンクを入力 :\"\n\"Please paste a valid GoogleSheet link in the dialog box above.\",\"上記のダイアログボックスに有効な GoogleSheet のリンクをペーストしてください。\"\n\"Help\",\"ヘルプ\"\n\"Environment\",\"Environment\"\n\"External file\",\"外部データ\"\n\"Copy / Paste\",\"コピー/ペースト\"\n\"Googlesheets\",\"Googlesheets\"\n\"How to import data?\",\"データをインポートする方法?\"\n\"Import\",\"インポート\"\n\"View\",\"ビュー\"\n\"Update\",\"アップデート\"\n\"Validate\",\"検証\"\n\"Update & select variables\",\"変数の更新と選択\"\n\"Date format:\",\"日付のフォーマット:\"\n\"Date to use as origin to convert date/datetime:\",\"date/datetime への変換元として使用する Date:\"\n\"Select, rename and convert variables in table above, then apply changes by clicking button below.\",\"上の表で変数を選択、名前変更、変換し、下のボタンをクリックして変更を適用する。\"\n\"Apply changes\",\"変更を適用\"\n\"Data has %s observations and %s variables.\",\"%s 行 %s 列のデータです。\"\n\"Data successfully updated!\",\"データは正しく更新されました!\"\n\"Validation:\",\"検証:\"\n\"OK\",\"OK\"\n\"Failed\",\"失敗\"\n\"Error\",\"エラー\"\n\"Number of rows:\",\"行数:\"\n\"No data to display.\",\"表示するデータがありません\"\n\"Close\",\"閉じる\"\n\"Add a label to data\",\"データにラベルを追加\"\n\"URL\",\"URL\"\n\"Add a row\",\"行を追加\"\n\"Required field\",\"必須項目\"\n\"Please fill in the required fields\",\"必須項目を埋めてください\"\n\"Unable to add the row, contact the platform administrator\",\"行を追加できません。プラットフォームの管理者に連絡してください。\"\n\"Registered\",\"登録済み\"\n\"Row has been saved\",\"行データは保存されました\"\n\"Update row\",\"行を更新\"\n\"Unable to modify the item, contact the platform administrator\",\"項目を修正できません。プラットフォームの管理者に連絡してください。\"\n\"Item has been modified\",\"項目は修正されました\"\n\"Delete\",\"削除\"\n\"Do you want to delete the selected row ?\",\"選択した行を削除しますか?\"\n\"Unable to delete the row, contact platform administrator\",\"\"行を削除できません。プラットフォームの管理者に連絡してください。\"\n\"The row has been deleted\",\"行は削除されました\"\n\"Information\",\"情報\"\n\"Row was not deleted\",\"行は削除されませんでした\"\n\"Save\",\"保存\"\n\"Click to edit\",\"クリックして編集\"\n\"Click to delete\",\"クリックして削除\"\n\"Cancel\",\"キャンセル\"\n\"No\",\"いいえ\"\n\"Yes\",\"はい\"\n\"Edit data\",\"データを編集\"\n\"Select\", \"選択\"\n\"Missing values character(s):\",\"欠損値文字:\"\n\"if several use a comma (',') to separate them\",\"複数の場合はカンマ (「,」) を使用して区切ります\"\n"
  },
  {
    "path": "inst/i18n/kr.csv",
    "content": "\"label\",\"translation\",\"comment\"\n\"% of the total\",\"�꾩껜�� %\",\"Automatically translated\"\n\"% of the total, i.e.\",\"�꾩껜�� %, 利�\",\"Automatically translated\"\n\"A shareable link, in that case first sheet will be read\",\"공유 가능한 링크에서는 첫번째 Sheet가 사용됩니다.\",\"\"\n\"Add a label to data\",\"데이터에 레이블 추가\",\"\"\n\"Add a row\",\"행 추가\",\"\"\n\"Apply changes\",\"적용\",\"\"\n\"Browse...\",\"찾기\",\"\"\n\"Cancel\",\"취소\",\"\"\n\"Choose a name for the column to be created or modified,\",\"�앹꽦�섍굅�� �섏젙�� �댁쓽 �대쫫�� �좏깮�섍퀬,\",\"Automatically translated\"\n\"Choose a number of rows :\",\"�� �섎� �좏깮�섏떗�쒖삤.\",\"Automatically translated\"\n\"Choose a percentage :\",\"鍮꾩쑉�� �좏깮�섏꽭��:\",\"Automatically translated\"\n\"Click on a column name to add it to the expression:\",\"�� �대쫫�� �대┃�섏뿬 �쒗쁽�앹뿉 異붽��⑸땲��.\",\"Automatically translated\"\n\"Click to delete\",\"삭제하려면 클릭하세요.\",\"\"\n\"Click to edit\",\"수정하려면 클릭하세요.\",\"\"\n\"Close\",\"닫기\",\"\"\n\"Close intervals on the right\",\"�ㅻⅨ履쎌쓽 媛꾧꺽 �リ린\",\"Automatically translated\"\n\"Column added!\",\"移쇰읆�� 異붽��섏뿀�듬땲��!\",\"Automatically translated\"\n\"Convert Numeric to Factor\",\"�レ옄瑜� �몄닔濡� 蹂��\",\"Automatically translated\"\n\"Copy & paste data\",\"�곗씠�� 蹂듭궗 諛� 遺숈뿬�ｊ린\",\"Automatically translated\"\n\"Copy / Paste\",\"복사 / 붙여넣기\",\"\"\n\"Count\",\"�몃떎\",\"Automatically translated\"\n\"Create a new column\",\"�� �� 留뚮뱾湲�\",\"Automatically translated\"\n\"Create a new variable otherwise replaces the one selected\",\"�� 蹂�섎� �앹꽦�섍굅�� 洹몃젃吏 �딆쑝硫� �좏깮�� 蹂�섎� �泥댄빀�덈떎.\",\"Automatically translated\"\n\"Create column\",\"�� �앹꽦\",\"Automatically translated\"\n\"Create factor variable\",\"�붿씤蹂�� �앹꽦\",\"Automatically translated\"\n\"Data has %s observations and %s variables.\",\"%s행 %s 변수\",\"\"\n\"Data ready to be imported!\",\"�곗씠�곕� 媛�몄삱 以鍮꾧� �섏뿀�듬땲��!\",\"Automatically translated\"\n\"Data successfully imported!\",\"데이터 불러오기 성공\",\"\"\n\"Data successfully updated!\",\"데이터 업데이트 성공\",\"\"\n\"Data wasn't deleted\",\"�곗씠�곌� ��젣�섏� �딆븯�듬땲��.\",\"Automatically translated\"\n\"Data wasn't updated\",\"�곗씠�곌� �낅뜲�댄듃�섏� �딆븯�듬땲��.\",\"Automatically translated\"\n\"Dataset validation:\",\"�곗씠�곗꽭�� 寃利�:\",\"Automatically translated\"\n\"Date format:\",\"날짜 포맷:\",\"\"\n\"Date to use as origin to convert date/datetime:\",\"날짜/날짜/시간을 변환하기 위해 원 데이터로 사용할 날짜:\",\"\"\n\"Decimal separator:\",\"소수점 구분 기호:\",\"\"\n\"Delete\",\"삭제\",\"\"\n\"Do you want to delete the selected row ?\",\"선택한 행을 삭제하시겠습니까?\",\"\"\n\"Encoding:\",\"인코딩:\",\"\"\n\"Enter URL to data:\",\"데이터 URL 입력:\",\"\"\n\"Enter a shareable link to a GoogleSheet:\",\"공유 가능한 GoogleSheet 링크:\",\"\"\n\"Enter an expression to define new column:\",\"�� �댁쓣 �뺤쓽�섎뒗 �쒗쁽�앹쓣 �낅젰�섏꽭��.\",\"Automatically translated\"\n\"Environment\",\"환경 선택\",\"\"\n\"Error\",\"에러\",\"\"\n\"External file\",\"외부 파일\",\"\"\n\"Factor variable to reorder:\",\"�ъ젙�ы븷 �붿씤 蹂��:\",\"Automatically translated\"\n\"Failed\",\"실패\",\"\"\n\"First five rows are shown below:\",\"泥섏쓬 5媛� �됱� �ㅼ쓬怨� 媛숈뒿�덈떎.\",\"Automatically translated\"\n\"Googlesheets\",\"Googlesheets\",\"\"\n\"Group calculation by:\",\"洹몃９ 怨꾩궛 湲곗�:\",\"Automatically translated\"\n\"Help\",\"도움말\",\"\"\n\"How to import data?\",\"데이터 불러오기 방법\",\"\"\n\"Import\",\"불러오기\",\"\"\n\"Import Google Spreadsheet\",\"Google �ㅽ봽�덈뱶�쒗듃 媛�몄삤湲�\",\"Automatically translated\"\n\"Import Url\",\"URL 媛�몄삤湲�\",\"Automatically translated\"\n\"Import a dataset from an environment\",\"�섍꼍�먯꽌 �곗씠�곗꽭�� 媛�몄삤湲�\",\"Automatically translated\"\n\"Import a file\",\"�뚯씪 媛�몄삤湲�\",\"Automatically translated\"\n\"Import data\",\"데이터 불러오기\",\"\"\n\"Imported data\",\"媛�몄삩 �곗씠��\",\"Automatically translated\"\n\"Include lowest value\",\"媛�� ��� 媛� �ы븿\",\"Automatically translated\"\n\"Information\",\"정보\",\"\"\n\"Item has been modified\",\"항목이 수정되었습니다\",\"\"\n\"Levels\",\"�덈꺼\",\"Automatically translated\"\n\"List of data.frame...\",\"data.frame 리스트\",\"\"\n\"Max:\",\"理쒕�:\",\"Automatically translated\"\n\"Mean:\",\"�됯퇏:\",\"Automatically translated\"\n\"Method:\",\"諛⑸쾿:\",\"Automatically translated\"\n\"Min:\",\"理쒖냼:\",\"Automatically translated\"\n\"Missing values characters:\",\"�꾨씫�� 媛� 臾몄옄:\",\"Automatically translated\"\n\"Missing:\",\"�놁뼱吏�:\",\"Automatically translated\"\n\"Most Common:\",\"媛�� �뷀븳:\",\"Automatically translated\"\n\"New column name cannot be empty\",\"�� �� �대쫫� 鍮꾩썙�� �� �놁뒿�덈떎.\",\"Automatically translated\"\n\"New column name:\",\"�� �� �대쫫:\",\"Automatically translated\"\n\"No\",\"아니\",\"\"\n\"No data selected!\",\"데이터 선택되지 않음!\",\"\"\n\"No data to display.\",\"화면에 나타낼 데이터 없음.\",\"\"\n\"No data.frame here...\",\"여기에 data.frame이 없습니다...\",\"\"\n\"No file selected\",\"파일 선택되지 않음:\",\"\"\n\"No file selected:\",\"파일 선택되지 않음:\",\"\"\n\"Not a data.frame\",\"data.frame�� �꾨떃�덈떎.\",\"Automatically translated\"\n\"Nothing pasted yet!\",\"아무것도 붙여넣기되지 않음!\",\"\"\n\"Number of breaks:\",\"�댁떇 �잛닔:\",\"Automatically translated\"\n\"Number of rows:\",\"열 수\",\"\"\n\"OK\",\"OK\",\"\"\n\"Ooops\",\"에러\",\"\"\n\"Paste data here:\",\"여기에 데이터 붙여넣기:\",\"\"\n\"Please copy and paste some data in the dialog box above.\",\"위의 상자에 데이터를 붙여넣으세요.\",\"\"\n\"Please fill in the required fields\",\"필수 필드를 작성하십시오\",\"\"\n\"Please paste a valid GoogleSheet link in the dialog box above.\",\"위의 상자에 유효한 GoogleSheet 링크를 붙여넣으세요.\",\"\"\n\"Please paste a valid link in the dialog box above.\",\"위의 대화 상자에 유효한 링크를 붙여넣으십시오.\",\"\"\n\"Registered\",\"등기\",\"\"\n\"Required field\",\"필수 입력란\",\"\"\n\"Row has been saved\",\"행이 저장되었습니다.\",\"\"\n\"Row was not deleted\",\"행이 삭제되지 않았습니다.\",\"\"\n\"Rows to skip before reading data:\",\"�곗씠�곕� �쎄린 �꾩뿉 嫄대꼫�� ��:\",\"Automatically translated\"\n\"Sample data by :\",\"�섑뵆 �곗씠�� 湲곗�:\",\"Automatically translated\"\n\"Save\",\"구하다\",\"\"\n\"Select\",\"고르다\",\"\"\n\"Select a data.frame:\",\"Data Frame 선택:\",\"\"\n\"Select an environment in which to search:\",\"찾을 환경 선택\",\"\"\n\"Select environment\",\"환경 선택\",\"\"\n\"Select sheet to import:\",\"불러올 Sheet 선택:\",\"\"\n\"Some operations are not allowed\",\"�쇰� �묒뾽� �덉슜�섏� �딆뒿�덈떎\",\"Automatically translated\"\n\"Something went wrong...\",\"臾몄젣媛 諛쒖깮�덉뒿�덈떎.\",\"Automatically translated\"\n\"Sort count\",\"�뺣젹 �잛닔\",\"Automatically translated\"\n\"The URL that appear in your browser, in that case the current sheet will be read\",\"브라우저에 나타난 URL을 붙여넣으면 현재 보고 있는 Sheet가 사용됩니다.\",\"\"\n\"The row has been deleted\",\"행이 삭제되었습니다.\",\"\"\n\"The row wasn't added to the data\",\"�됱씠 �곗씠�곗뿉 異붽��섏� �딆븯�듬땲��.\",\"Automatically translated\"\n\"URL\",\"URL\",\"\"\n\"Unable to add the row, contact the platform administrator\",\"행을 추가할 수 없습니다. 플랫폼 관리자에게 문의하세요.\",\"\"\n\"Unable to delete the row, contact platform administrator\",\"행을 삭제할 수 없습니다. 플랫폼 관리자에게 문의하세요.\",\"\"\n\"Unable to modify the item, contact the platform administrator\",\"항목을 수정할 수 없습니다. 플랫폼 관리자에게 문의하세요.\",\"\"\n\"Unique values:\",\"怨좎쑀�� 媛�:\",\"Automatically translated\"\n\"Unique:\",\"怨좎쑀��:\",\"Automatically translated\"\n\"Update\",\"업데이트\",\"\"\n\"Update & select variables\",\"蹂�� �낅뜲�댄듃 諛� �좏깮\",\"Automatically translated\"\n\"Update factor variable\",\"�붿씤 蹂�� �낅뜲�댄듃\",\"Automatically translated\"\n\"Update levels of a factor\",\"�붿씤 �섏� �낅뜲�댄듃\",\"Automatically translated\"\n\"Update row\",\"행 업데이트\",\"\"\n\"Upload a file:\",\"파일 업로드:\",\"\"\n\"Use a data.frame from your environment or from the environment of a package.\",\"사용자 환경이나 패키지로부터 data.frame을 불러와 사용하세요.\",\"\"\n\"Valid number of columns\",\"�좏슚�� �� ��\",\"Automatically translated\"\n\"Valid number of rows\",\"�좏슚�� �� ��\",\"Automatically translated\"\n\"Validate\",\"검증\",\"\"\n\"Validation:\",\"�뺤씤:\",\"Automatically translated\"\n\"Variable to cut:\",\"�섎씪�� 蹂��:\",\"Automatically translated\"\n\"View\",\"보기\",\"\"\n\"Warning\",\"寃쎄퀬\",\"Automatically translated\"\n\"Yes\",\"예\",\"\"\n\"You can either use:\",\"다음 중 선택:\",\"\"\n\"You can import %s files\",\"%s 파일 불러오기 가능\",\"\"\n\"You can import from flat table format supported by\",\"에서 지원하는 플랫 테이블 형식에서 가져올 수 있습니다.\",\"\"\n\"click to see data\",\"�곗씠�곕� 蹂대젮硫� �대┃�섏꽭��\",\"Automatically translated\"\n\"data has %s obs. of %s variables.\",\"%s행 변수 %s\",\"\"\n\"if several use a comma ',' to separate them\",\"�щ윭 紐낆씠 �쇳몴 ','瑜� �ъ슜�섏뿬 援щ텇�섎뒗 寃쎌슦\",\"Automatically translated\"\n\"lines, i.e.\",\"�쇱씤, 利�\",\"Automatically translated\"\n\"number of rows\",\"�� ��\",\"Automatically translated\"\n\"proportion of rows\",\"�됱쓽 鍮꾩쑉\",\"Automatically translated\"\n\"rows\",\"��\",\"Automatically translated\"\n\"then enter an expression before clicking on the button above to validate or on \",\"洹몃윴 �ㅼ쓬 �꾩쓽 踰꾪듉�� �대┃�섍린 �꾩뿉 �쒗쁽�앹쓣 �낅젰�섏뿬 �좏슚�깆쓣 寃�ы븯嫄곕굹\",\"Automatically translated\"\n\"to delete it.\",\"��젣�섎젮硫�\",\"Automatically translated\"\n\"Sort by count\",\"媛쒖닔蹂꾨줈 �뺣젹\",\"Automatically translated\"\n\"Sort by levels\",\"�덈꺼蹂꾨줈 �뺣젹\",\"Automatically translated\"\n"
  },
  {
    "path": "inst/i18n/maj_csv.R",
    "content": "\nlibrary(data.table)\nlibrary(stringr)\nlibrary(utils)\nlibrary(polyglotr)\n\nsource(\"inst/i18n/extract_labels.R\")\n\n\n# Extraction of labels contained in the “/R” subdirectory\n\nextraction_labels <- c(extract_labels(folder = \"R\"))\n\n\n# Updating csv with previously extracted labels WITHOUT translation\n\nupdate_csv(labels = extraction_labels, lang = \"fr\", lang_csv = \"fr\", translation = FALSE)\nupdate_csv(labels = extraction_labels, lang = \"es\", lang_csv = \"es\", translation = FALSE)\nupdate_csv(labels = extraction_labels, lang = \"de\", lang_csv = \"de\", translation = FALSE)\nupdate_csv(labels = extraction_labels, lang = \"sq\", lang_csv = \"al\", translation = FALSE)\nupdate_csv(labels = extraction_labels, lang = \"pl\", lang_csv = \"pl\", translation = FALSE)\nupdate_csv(labels = extraction_labels, lang = \"pt\", lang_csv = \"pt\", translation = FALSE)\nupdate_csv(labels = extraction_labels, lang = \"tr\", lang_csv = \"tr\", translation = FALSE)\nupdate_csv(labels = extraction_labels, lang = \"mk\", lang_csv = \"mk\", translation = FALSE)\n# update_csv(labels = extraction_labels, lang = \"ja\", lang_csv = \"ja\", translation = FALSE, encoding = \"ISO_2022,locale=ja,version=4\")  # review encoding\nupdate_csv(labels = extraction_labels, lang = \"zh-CN\", lang_csv = \"cn\", translation = FALSE, encoding = \"GBK\") #\"UTF16_BigEndian\" or \"GB18030\"\nupdate_csv(labels = extraction_labels, lang = \"ko\", lang_csv = \"kr\", translation = FALSE, encoding = \"korean\") # \"GBK\", \"korean\"\n\n\n# Updating csv with labels extracted previously WITH translation\n\nupdate_csv(labels = extraction_labels, lang = \"fr\", lang_csv = \"fr\")\nupdate_csv(labels = extraction_labels, lang = \"es\", lang_csv = \"es\")\nupdate_csv(labels = extraction_labels, lang = \"de\", lang_csv = \"de\")\nupdate_csv(labels = extraction_labels, lang = \"sq\", lang_csv = \"al\")\nupdate_csv(labels = extraction_labels, lang = \"pl\", lang_csv = \"pl\")\nupdate_csv(labels = extraction_labels, lang = \"pt\", lang_csv = \"pt\")\nupdate_csv(labels = extraction_labels, lang = \"tr\", lang_csv = \"tr\")\nupdate_csv(labels = extraction_labels, lang = \"mk\", lang_csv = \"mk\")\n# update_csv(labels = extraction_labels, lang = \"ja\", lang_csv = \"ja\", encoding = \"ISO_2022,locale=ja,version=4\")  # review encoding\nupdate_csv(labels = extraction_labels, lang = \"zh-CN\", lang_csv = \"cn\", encoding = \"GBK\") #\"UTF16_BigEndian\" or \"GB18030\"\nupdate_csv(labels = extraction_labels, lang = \"ko\", lang_csv = \"kr\", encoding = \"korean\") # \"GBK\", \"korean\"\n"
  },
  {
    "path": "inst/i18n/mk.csv",
    "content": "\"label\",\"translation\",\"comment\"\n\"% of the total\",\"% од вкупниот број\",\"Automatically translated\"\n\"% of the total, i.e.\",\"% од вкупниот број, т.е.\",\"Automatically translated\"\n\"A shareable link, in that case first sheet will be read\",\"Врска којашто може да се сподели, во овој случај првата страна ќе биде прочитана\",\"\"\n\"Add a label to data\",\"Додадете етикета на податоците\",\"#TODO #CHECK\"\n\"Add a row\",\"Додадете ред\",\"\"\n\"Apply changes\",\"Применете ги промените\",\"\"\n\"Browse...\",\"Пребарувајте...\",\"\"\n\"Cancel\",\"Откажи\",\"\"\n\"Choose a name for the column to be created or modified,\",\"Изберете име за колоната што треба да се креира или измени,\",\"Automatically translated\"\n\"Choose a number of rows :\",\"Изберете голем број редови:\",\"Automatically translated\"\n\"Choose a percentage :\",\"Изберете процент:\",\"Automatically translated\"\n\"Click on a column name to add it to the expression:\",\"Кликнете на името на колоната за да го додадете во изразот:\",\"Automatically translated\"\n\"Click to delete\",\"Кликнете за да избришете\",\"\"\n\"Click to edit\",\"Кликнете за уредување\",\"\"\n\"Close\",\"Затвори\",\"\"\n\"Close intervals on the right\",\"Затворете ги интервалите од десната страна\",\"Automatically translated\"\n\"Column added!\",\"Колона е додадена!\",\"Automatically translated\"\n\"Convert Numeric to Factor\",\"Конвертирај нумерички во фактор\",\"Automatically translated\"\n\"Copy & paste data\",\"Копирајте и залепете податоци\",\"\"\n\"Copy / Paste\",\"Копирај / залепи\",\"\"\n\"Count\",\"брои\",\"Automatically translated\"\n\"Create a new column\",\"Направете нова колона\",\"Automatically translated\"\n\"Create a new variable otherwise replaces the one selected\",\"Креирајте нова променлива инаку ја заменува избраната\",\"Automatically translated\"\n\"Create column\",\"Креирај колона\",\"Automatically translated\"\n\"Create factor variable\",\"Креирај променлива на фактор\",\"Automatically translated\"\n\"Data has %s observations and %s variables.\",\"Податоците имаат %s опсервации и %s варијабли.\",\"\"\n\"Data ready to be imported!\",\"Податоци коишто се спремни за да бидат увезени\",\"\"\n\"Data successfully imported!\",\"Успешно увезени податоци\",\"\"\n\"Data successfully updated!\",\"Податоците се успешно ажурирани!\",\"\"\n\"Data wasn't deleted\",\"Податоците не се избришани\",\"Automatically translated\"\n\"Data wasn't updated\",\"Податоците не беа ажурирани\",\"Automatically translated\"\n\"Dataset validation:\",\"Потврда на сет на податоци:\",\"Automatically translated\"\n\"Date format:\",\"Формат на датум:\",\"\"\n\"Date to use as origin to convert date/datetime:\",\"Датум што треба да се користи за конвертирање на date/datetime променлива\",\"\"\n\"Decimal separator:\",\"Децимален раздвојник:\",\"\"\n\"Delete\",\"Избриши\",\"\"\n\"Do you want to delete the selected row ?\",\"Дали сакате да го избришете избраниот ред?\",\"\"\n\"Encoding:\",\"Енкодинг:\",\"\"\n\"Enter URL to data:\",\"Внесете URL на податоците:\",\"Automatically translated\"\n\"Enter a shareable link to a GoogleSheet:\",\"Внесете врска којшто може да се сподели во GoogleSheet:\",\"\"\n\"Enter an expression to define new column:\",\"Внесете израз за да дефинирате нова колона:\",\"Automatically translated\"\n\"Environment\",\"Околина\",\"\"\n\"Error\",\"Грешка\",\"\"\n\"External file\",\"Надворешна датотека\",\"\"\n\"Factor variable to reorder:\",\"Факторска променлива за прередување:\",\"Automatically translated\"\n\"Failed\",\"Неуспех\",\"\"\n\"First five rows are shown below:\",\"Првите пет реда се прикажани подолу:\",\"\"\n\"Googlesheets\",\"Googlesheets\",\"\"\n\"Group calculation by:\",\"Групна пресметка според:\",\"Automatically translated\"\n\"Help\",\"Помош\",\"\"\n\"How to import data?\",\"Како да се увезат податоците?\",\"\"\n\"Import\",\"Увези\",\"\"\n\"Import Google Spreadsheet\",\"Увезете GoogleSheet\",\"\"\n\"Import Url\",\"Увезете УРЛ\",\"Automatically translated\"\n\"Import a dataset from an environment\",\"Увезете податочен сет од околината\",\"\"\n\"Import a file\",\"Внесете документ\",\"\"\n\"Import data\",\"Внесете податоци\",\"\"\n\"Imported data\",\"Увезени податоци\",\"Automatically translated\"\n\"Include lowest value\",\"Вклучете ја најниската вредност\",\"Automatically translated\"\n\"Information\",\"Информации\",\"\"\n\"Item has been modified\",\"Ставката е изменета\",\"\"\n\"Levels\",\"Нивоа\",\"Automatically translated\"\n\"List of data.frame...\",\"Список на табели со податоци\",\"\"\n\"Max:\",\"Макс:\",\"Automatically translated\"\n\"Mean:\",\"Средно:\",\"Automatically translated\"\n\"Method:\",\"Метод:\",\"Automatically translated\"\n\"Min:\",\"Мин:\",\"Automatically translated\"\n\"Missing values characters:\",\"Недостасуваат знаци на вредности:\",\"Automatically translated\"\n\"Missing:\",\"Недостасува:\",\"Automatically translated\"\n\"Most Common:\",\"Најчесто:\",\"Automatically translated\"\n\"New column name cannot be empty\",\"Името на новата колона не може да биде празно\",\"Automatically translated\"\n\"New column name:\",\"Ново име на колона:\",\"Automatically translated\"\n\"No\",\"бр\",\"\"\n\"No data selected!\",\"Нема ниту еден избран податок\",\"\"\n\"No data to display.\",\"Нема податоци за приказ.\",\"\"\n\"No data.frame here...\",\"Тука нема податоци...\",\"\"\n\"No file selected\",\"Ниту еден документ не е избран\",\"\"\n\"No file selected:\",\"Ниту еден документ не е избран\",\"\"\n\"Not a data.frame\",\"Не е податок.рамка\",\"Automatically translated\"\n\"Nothing pasted yet!\",\"Ништо до сега не е залепено!\",\"\"\n\"Number of breaks:\",\"Број на паузи:\",\"Automatically translated\"\n\"Number of rows:\",\"Број на редови:\",\"\"\n\"OK\",\"Во ред\",\"\"\n\"Ooops\",\"Упс\",\"\"\n\"Paste data here:\",\"Залепете ги вашите податоци тука:\",\"\"\n\"Please copy and paste some data in the dialog box above.\",\"Ве молиме копирајте и залепете некои податоци во прозорчето за дијалог подолу\",\"\"\n\"Please fill in the required fields\",\"Ве молиме пополнете ги бараните полиња\",\"\"\n\"Please paste a valid GoogleSheet link in the dialog box above.\",\"Ве молиме залепете валидна врска до GoogleSheet во прозорчето подолу.\",\"\"\n\"Please paste a valid link in the dialog box above.\",\"Ве молиме залепете валидна врска во полето за дијалог погоре.\",\"Automatically translated\"\n\"Registered\",\"Регистриран\",\"\"\n\"Required field\",\"задолжително поле\",\"\"\n\"Row has been saved\",\"Редот е зачуван\",\"\"\n\"Row was not deleted\",\"Редот не беше избришан\",\"\"\n\"Rows to skip before reading data:\",\"Редови што треба да се прескокнат пред да се прочитаат податоците:\",\"Automatically translated\"\n\"Sample data by :\",\"Примерок на податоци од:\",\"Automatically translated\"\n\"Save\",\"Зачувај\",\"\"\n\"Select\",\"изберете\",\"\"\n\"Select a data.frame:\",\"Изберете data.frame\",\"\"\n\"Select an environment in which to search:\",\"Изберете околина за пребарување\",\"\"\n\"Select environment\",\"Изберете околина\",\"\"\n\"Select sheet to import:\",\"Изберете лист за да увезете\",\"\"\n\"Some operations are not allowed\",\"Некои операции не се дозволени\",\"Automatically translated\"\n\"Something went wrong...\",\"Тука нема податоци...\",\"\"\n\"Sort count\",\"Броење сортирање\",\"Automatically translated\"\n\"The URL that appear in your browser, in that case the current sheet will be read\",\"URL коешто се појавува во вашиот пребарарувач, во овој случај првата страна ќе биде прочитана\",\"\"\n\"The row has been deleted\",\"Редот е избришан\",\"\"\n\"The row wasn't added to the data\",\"Редот не беше додаден на податоците\",\"Automatically translated\"\n\"URL\",\"URL\",\"Automatically translated\"\n\"Unable to add the row, contact the platform administrator\",\"Не може да се додаде редот, контактирајте со администраторот на платформата\",\"\"\n\"Unable to delete the row, contact platform administrator\",\"Не може да се избрише редот, контактирајте со администраторот на платформата\",\"\"\n\"Unable to modify the item, contact the platform administrator\",\"Не може да се измени ставката, контактирајте со администраторот на платформата\",\"\"\n\"Unique values:\",\"Единствени вредности:\",\"Automatically translated\"\n\"Unique:\",\"Уникатно:\",\"Automatically translated\"\n\"Update\",\"Ажурирај\",\"\"\n\"Update & select variables\",\"Ажурирај и одбери променливи\",\"\"\n\"Update factor variable\",\"Ажурирајте ја променливата на факторот\",\"Automatically translated\"\n\"Update levels of a factor\",\"Ажурирајте ги нивоата на фактор\",\"Automatically translated\"\n\"Update row\",\"Ажурирајте го редот\",\"\"\n\"Upload a file:\",\"Прикачете документ\",\"\"\n\"Use a data.frame from your environment or from the environment of a package.\",\"Користете data.frame од твојата околина или од пакет\",\"\"\n\"Valid number of columns\",\"Валиден број на колони\",\"Automatically translated\"\n\"Valid number of rows\",\"Валиден број на редови\",\"Automatically translated\"\n\"Validate\",\"Провери\",\"\"\n\"Validation:\",\"Проверка:\",\"\"\n\"Variable to cut:\",\"Променлива за сечење:\",\"Automatically translated\"\n\"View\",\"Прегледај\",\"\"\n\"Warning\",\"Предупредување\",\"Automatically translated\"\n\"Yes\",\"Да\",\"\"\n\"You can either use:\",\"Можете да користите нешто од ова:\",\"\"\n\"You can import %s files\",\"Можете да увезувате документи %s\",\"\"\n\"You can import from flat table format supported by\",\"Можете да увезете од формат на рамна табела поддржан од\",\"Automatically translated\"\n\"click to see data\",\"Притиснете тука за да прикачите податоци\",\"\"\n\"data has %s obs. of %s variables.\",\"Податоците имаат % обсерваци и % променливи\",\"\"\n\"if several use a comma ',' to separate them\",\"ако неколку користат запирка ',' за да ги разделат\",\"Automatically translated\"\n\"lines, i.e.\",\"линии, т.е.\",\"Automatically translated\"\n\"number of rows\",\"број на редови\",\"Automatically translated\"\n\"proportion of rows\",\"пропорција на редови\",\"Automatically translated\"\n\"rows\",\"редови\",\"Automatically translated\"\n\"then enter an expression before clicking on the button above to validate or on \",\"потоа внесете израз пред да кликнете на копчето погоре за да потврдите или да го вклучите\",\"Automatically translated\"\n\"to delete it.\",\"да го избришете.\",\"Automatically translated\"\n\"Sort by count\",\"Подреди по број\",\"Automatically translated\"\n\"Sort by levels\",\"Подреди по нивоа\",\"Automatically translated\"\n"
  },
  {
    "path": "inst/i18n/pl.csv",
    "content": "\"label\",\"translation\",\"comment\"\n\"% of the total\",\"% całkowitej\",\"Automatically translated\"\n\"% of the total, i.e.\",\"% całości, tj.\",\"Automatically translated\"\n\"A shareable link, in that case first sheet will be read\",\"Linku do udostępniania (zostanie odczytany pierwszy arkusz)\",\"\"\n\"Add a label to data\",\"Dodaj etykietę do danych\",\"\"\n\"Add a row\",\"Dodaj wiersz\",\"\"\n\"Apply changes\",\"Zastosuj zmiany\",\"\"\n\"Browse...\",\"Przeglądaj...\",\"\"\n\"Cancel\",\"Anuluj\",\"\"\n\"Choose a name for the column to be created or modified,\",\"Wybierz nazwę kolumny, która ma zostać utworzona lub zmodyfikowana,\",\"Automatically translated\"\n\"Choose a number of rows :\",\"Wybierz liczbę wierszy:\",\"Automatically translated\"\n\"Choose a percentage :\",\"Wybierz procent:\",\"Automatically translated\"\n\"Click on a column name to add it to the expression:\",\"Kliknij nazwę kolumny, aby dodać ją do wyrażenia:\",\"Automatically translated\"\n\"Click to delete\",\"Naciśnij by usunąć\",\"\"\n\"Click to edit\",\"Naciśnij by edytować\",\"\"\n\"Close\",\"Zamknij.\",\"\"\n\"Close intervals on the right\",\"Zamknij odstępy po prawej stronie\",\"Automatically translated\"\n\"Column added!\",\"Dodano kolumnę!\",\"Automatically translated\"\n\"Convert Numeric to Factor\",\"Zamień liczbę na współczynnik\",\"Automatically translated\"\n\"Copy & paste data\",\"Kopiuj i wklej dane\",\"\"\n\"Copy / Paste\",\"Kopiuj / wklej\",\"\"\n\"Count\",\"Liczyć\",\"Automatically translated\"\n\"Create a new column\",\"Utwórz nową kolumnę\",\"Automatically translated\"\n\"Create a new variable otherwise replaces the one selected\",\"Utwórz nową zmienną, w przeciwnym razie zastępuje wybraną\",\"Automatically translated\"\n\"Create column\",\"Utwórz kolumnę\",\"Automatically translated\"\n\"Create factor variable\",\"Utwórz zmienną czynnikową\",\"Automatically translated\"\n\"Data has %s observations and %s variables.\",\"dane zawierają %s obserwacji i %s zmiennych.\",\"\"\n\"Data ready to be imported!\",\"Dane gotowe do importu!\",\"\"\n\"Data successfully imported!\",\"Dane zaimportowano pomyślnie!\",\"\"\n\"Data successfully updated!\",\"Dane pomyślnie zaktualizowano\",\"\"\n\"Data wasn't deleted\",\"Dane nie zostały usunięte\",\"Automatically translated\"\n\"Data wasn't updated\",\"Dane nie zostały zaktualizowane\",\"Automatically translated\"\n\"Dataset validation:\",\"Walidacja zbioru danych:\",\"Automatically translated\"\n\"Date format:\",\"Format dat:\",\"\"\n\"Date to use as origin to convert date/datetime:\",\"Data do użycia jako początkowa do konwersji dat/dat i czasu\",\"\"\n\"Decimal separator:\",\"Separator dziesiętny:\",\"\"\n\"Delete\",\"Usuń\",\"\"\n\"Do you want to delete the selected row ?\",\"Czy na pewo chcesz usunąć ten wiersz?\",\"\"\n\"Encoding:\",\"Kodowanie:\",\"\"\n\"Enter URL to data:\",\"Wpisz adres URL do danych:\",\"Automatically translated\"\n\"Enter a shareable link to a GoogleSheet:\",\"Wprowadź link do udostępniania Arkusza Google:\",\"\"\n\"Enter an expression to define new column:\",\"Wprowadź wyrażenie definiujące nową kolumnę:\",\"Automatically translated\"\n\"Environment\",\"Środowisko\",\"\"\n\"Error\",\"Błąd\",\"\"\n\"External file\",\"Plik zewnętrzny\",\"\"\n\"Factor variable to reorder:\",\"Zmienna czynnikowa do zmiany kolejności:\",\"Automatically translated\"\n\"Failed\",\"Nie udało się\",\"\"\n\"First five rows are shown below:\",\"Poniżej pokazano pięć pierwszych wierszy:\",\"\"\n\"Googlesheets\",\"Arkusze Google\",\"\"\n\"Group calculation by:\",\"Obliczenia grupowe według:\",\"Automatically translated\"\n\"Help\",\"Pomoc\",\"\"\n\"How to import data?\",\"Jak zaimportować dane?\",\"\"\n\"Import\",\"Importuj\",\"\"\n\"Import Google Spreadsheet\",\"Importuj z Arkuszy Google\",\"\"\n\"Import Url\",\"Importuj adres URL\",\"Automatically translated\"\n\"Import a dataset from an environment\",\"Importuj dane ze środowiska\",\"\"\n\"Import a file\",\"Importuj plik\",\"\"\n\"Import data\",\"Importuj dane\",\"\"\n\"Imported data\",\"Zaimportowane dane\",\"Automatically translated\"\n\"Include lowest value\",\"Uwzględnij najniższą wartość\",\"Automatically translated\"\n\"Information\",\"Informacje\",\"\"\n\"Item has been modified\",\"Obiekt został zmieniony\",\"\"\n\"Levels\",\"Poziomy\",\"Automatically translated\"\n\"List of data.frame...\",\"Lista obiektów data.frame...\",\"\"\n\"Max:\",\"Maks:\",\"Automatically translated\"\n\"Mean:\",\"Mieć na myśli:\",\"Automatically translated\"\n\"Method:\",\"Metoda:\",\"Automatically translated\"\n\"Min:\",\"Min.:\",\"Automatically translated\"\n\"Missing values characters:\",\"Brakujące znaki wartości:\",\"Automatically translated\"\n\"Missing:\",\"Zaginiony:\",\"Automatically translated\"\n\"Most Common:\",\"Najczęściej:\",\"Automatically translated\"\n\"New column name cannot be empty\",\"Nazwa nowej kolumny nie może być pusta\",\"Automatically translated\"\n\"New column name:\",\"Nowa nazwa kolumny:\",\"Automatically translated\"\n\"No\",\"Nie\",\"\"\n\"No data selected!\",\"Nie wybrano danych!\",\"\"\n\"No data to display.\",\"Brak danych do wyświetlenia.\",\"\"\n\"No data.frame here...\",\"Brak obiektów data.frame\",\"\"\n\"No file selected\",\"Nie wybrano żadnego pliku\",\"\"\n\"No file selected:\",\"Nie wybrano pliku:\",\"\"\n\"Not a data.frame\",\"Nie ramka danych\",\"Automatically translated\"\n\"Nothing pasted yet!\",\"Jeszcze nic nie wklejono!\",\"\"\n\"Number of breaks:\",\"Liczba przerw:\",\"Automatically translated\"\n\"Number of rows:\",\"Liczba wierszy:\",\"\"\n\"OK\",\"OK\",\"\"\n\"Ooops\",\"Upsss\",\"\"\n\"Paste data here:\",\"Wklej dane tutaj:\",\"\"\n\"Please copy and paste some data in the dialog box above.\",\"Proszę skopiować i wkleić dane do okienka powyżej.\",\"\"\n\"Please fill in the required fields\",\"Proszę wypełnić wymagane pola\",\"\"\n\"Please paste a valid GoogleSheet link in the dialog box above.\",\"Proszę wprowadzić popeawny link do Arkusza Google w okienku powyżej.\",\"\"\n\"Please paste a valid link in the dialog box above.\",\"Wklej prawidłowy link w powyższym oknie dialogowym.\",\"Automatically translated\"\n\"Registered\",\"Zarejestrowano\",\"\"\n\"Required field\",\"Pole wymagane\",\"\"\n\"Row has been saved\",\"Wiersz został zapisany\",\"\"\n\"Row was not deleted\",\"Wiersz nie został usunięty\",\"\"\n\"Rows to skip before reading data:\",\"Wiersze do pominięcia przed odczytaniem danych:\",\"Automatically translated\"\n\"Sample data by :\",\"Przykładowe dane według:\",\"Automatically translated\"\n\"Save\",\"Ratować\",\"\"\n\"Select\",\"Wybierz\",\"\"\n\"Select a data.frame:\",\"Wybierz data.frame:\",\"\"\n\"Select an environment in which to search:\",\"Wybierz środowisko, w którym chcesz szukać:\",\"\"\n\"Select environment\",\"Wybierz środowisko\",\"\"\n\"Select sheet to import:\",\"Wybierz arkusz:\",\"\"\n\"Some operations are not allowed\",\"Niektóre operacje są niedozwolone\",\"Automatically translated\"\n\"Something went wrong...\",\"Coś poszło nie tak...\",\"\"\n\"Sort count\",\"Liczba sortowań\",\"Automatically translated\"\n\"The URL that appear in your browser, in that case the current sheet will be read\",\"Linku z przeglądarki (zostanie odczytany aktualny arkusz)\",\"\"\n\"The row has been deleted\",\"Wiersz został usunięty\",\"\"\n\"The row wasn't added to the data\",\"Wiersz nie został dodany do danych\",\"Automatically translated\"\n\"URL\",\"URL\",\"\"\n\"Unable to add the row, contact the platform administrator\",\"Brak możliwości dodania wiersza, skontaktuj się z administratorem\",\"\"\n\"Unable to delete the row, contact platform administrator\",\"Brak możliwości usunięcia wiersza, skontaktuj się z administratorem\",\"\"\n\"Unable to modify the item, contact the platform administrator\",\"Brak możliwości modyfikacji obiektu, skontaktuj się z administratorem\",\"\"\n\"Unique values:\",\"Unikalne wartości:\",\"Automatically translated\"\n\"Unique:\",\"Unikalny:\",\"Automatically translated\"\n\"Update\",\"Zaktualizuj\",\"\"\n\"Update & select variables\",\"Zaktualizuj i wybierz zmienne\",\"\"\n\"Update factor variable\",\"Aktualizuj zmienną współczynnika\",\"Automatically translated\"\n\"Update levels of a factor\",\"Aktualizuj poziomy czynnika\",\"Automatically translated\"\n\"Update row\",\"Zaktualizuj wiersz\",\"\"\n\"Upload a file:\",\"Wgraj plik:\",\"\"\n\"Use a data.frame from your environment or from the environment of a package.\",\"Użyj obiektu data.frame ze swojego środowiska lub ze środowiska pakietu.\",\"\"\n\"Valid number of columns\",\"Prawidłowa liczba kolumn\",\"Automatically translated\"\n\"Valid number of rows\",\"Prawidłowa liczba wierszy\",\"Automatically translated\"\n\"Validate\",\"Sprawdź\",\"\"\n\"Validation:\",\"Sprawdzenie:\",\"\"\n\"Variable to cut:\",\"Zmienna do cięcia:\",\"Automatically translated\"\n\"View\",\"Pokaż\",\"\"\n\"Warning\",\"Ostrzeżenie\",\"Automatically translated\"\n\"Yes\",\"Tak\",\"\"\n\"You can either use:\",\"Możesz użyć:\",\"\"\n\"You can import %s files\",\"Możesz zaimportować %s plików\",\"\"\n\"You can import from flat table format supported by\",\"Możesz importować z formatu płaskiej tabeli obsługiwanego przez\",\"Automatically translated\"\n\"click to see data\",\"kliknij by zobaczyć dane\",\"\"\n\"data has %s obs. of %s variables.\",\"dane zawierają %s obserwacji %s zmiennych.\",\"\"\n\"if several use a comma ',' to separate them\",\"jeśli kilka z nich użyje przecinka „,” aby je oddzielić\",\"Automatically translated\"\n\"lines, i.e.\",\"linie, tj.\",\"Automatically translated\"\n\"number of rows\",\"Liczba rzędów\",\"Automatically translated\"\n\"proportion of rows\",\"proporcja rzędów\",\"Automatically translated\"\n\"rows\",\"wydziwianie\",\"Automatically translated\"\n\"then enter an expression before clicking on the button above to validate or on \",\"następnie wprowadź wyrażenie przed kliknięciem przycisku powyżej, aby zatwierdzić lub włączyć\",\"Automatically translated\"\n\"to delete it.\",\"aby go usunąć.\",\"Automatically translated\"\n\"Sort by count\",\"Sortuj według liczby\",\"Automatically translated\"\n\"Sort by levels\",\"Sortuj według poziomów\",\"Automatically translated\"\n"
  },
  {
    "path": "inst/i18n/pt.csv",
    "content": "\"label\",\"translation\",\"comment\"\n\"% of the total\",\"% do total\",\"Automatically translated\"\n\"% of the total, i.e.\",\"% do total, ou seja,\",\"Automatically translated\"\n\"A shareable link, in that case first sheet will be read\",\"Um link compartilhável, nesse caso a primeira aba será lida\",\"\"\n\"Add a label to data\",\"Adicionar uma etiqueta aos dados\",\"#TODO #CHECK\"\n\"Add a row\",\"Adicionar uma linha\",\"\"\n\"Apply changes\",\"Aplique as mudanças\",\"\"\n\"Browse...\",\"Buscar...\",\"\"\n\"Cancel\",\"Cancelar\",\"\"\n\"Choose a name for the column to be created or modified,\",\"Escolha um nome para a coluna a ser criada ou modificada,\",\"Automatically translated\"\n\"Choose a number of rows :\",\"Escolha um número de linhas:\",\"Automatically translated\"\n\"Choose a percentage :\",\"Escolha uma porcentagem:\",\"Automatically translated\"\n\"Click on a column name to add it to the expression:\",\"Clique no nome de uma coluna para adicioná-la à expressão:\",\"Automatically translated\"\n\"Click to delete\",\"Clique para deletar\",\"\"\n\"Click to edit\",\"Clique para editar\",\"\"\n\"Close\",\"Fechar\",\"\"\n\"Close intervals on the right\",\"Intervalos próximos à direita\",\"Automatically translated\"\n\"Column added!\",\"Coluna adicionada!\",\"Automatically translated\"\n\"Convert Numeric to Factor\",\"Converter numérico em fator\",\"Automatically translated\"\n\"Copy & paste data\",\"Copie & cole os dados\",\"\"\n\"Copy / Paste\",\"Copie / Cole\",\"\"\n\"Count\",\"Contar\",\"Automatically translated\"\n\"Create a new column\",\"Crie uma nova coluna\",\"Automatically translated\"\n\"Create a new variable otherwise replaces the one selected\",\"Crie uma nova variável, caso contrário substituirá a selecionada\",\"Automatically translated\"\n\"Create column\",\"Criar coluna\",\"Automatically translated\"\n\"Create factor variable\",\"Criar variável de fator\",\"Automatically translated\"\n\"Data has %s observations and %s variables.\",\"Os dados possuem %s observações de %s variáveis.\",\"\"\n\"Data ready to be imported!\",\"Dados prontos para serem importados!\",\"\"\n\"Data successfully imported!\",\"Dados importados com sucesso!\",\"\"\n\"Data successfully updated!\",\"Os dados foram modificados com sucesso!\",\"\"\n\"Data wasn't deleted\",\"Os dados não foram excluídos\",\"Automatically translated\"\n\"Data wasn't updated\",\"Os dados não foram atualizados\",\"Automatically translated\"\n\"Dataset validation:\",\"Validação do conjunto de dados:\",\"Automatically translated\"\n\"Date format:\",\"Formato dos dados:\",\"\"\n\"Date to use as origin to convert date/datetime:\",\"Data para usar como origem para converter date/datetime:\",\"\"\n\"Decimal separator:\",\"Separador decimal:\",\"\"\n\"Delete\",\"Excluir\",\"\"\n\"Do you want to delete the selected row ?\",\"Deseja excluir a linha selecionada?\",\"\"\n\"Encoding:\",\"Encoding:\",\"\"\n\"Enter URL to data:\",\"Insira o URL para os dados:\",\"Automatically translated\"\n\"Enter a shareable link to a GoogleSheet:\",\"Coloque um link compartilhável para o GoogleSheet:\",\"\"\n\"Enter an expression to define new column:\",\"Insira uma expressão para definir a nova coluna:\",\"Automatically translated\"\n\"Environment\",\"Ambiente local\",\"\"\n\"Error\",\"Erro\",\"\"\n\"External file\",\"Arquivo externo\",\"\"\n\"Factor variable to reorder:\",\"Variável de fator para reordenar:\",\"Automatically translated\"\n\"Failed\",\"Falha\",\"\"\n\"First five rows are shown below:\",\"As cinco primeiras linhas são mostradas abaixo:\",\"\"\n\"Googlesheets\",\"Googlesheets\",\"\"\n\"Group calculation by:\",\"Cálculo do grupo por:\",\"Automatically translated\"\n\"Help\",\"Ajuda\",\"\"\n\"How to import data?\",\"Como importar os dados?\",\"\"\n\"Import\",\"Importar\",\"\"\n\"Import Google Spreadsheet\",\"Importe um Spreadsheet do Google\",\"\"\n\"Import Url\",\"Url de importação\",\"Automatically translated\"\n\"Import a dataset from an environment\",\"Importe um conjunto de dados do ambiente local\",\"\"\n\"Import a file\",\"Importe um arquivo\",\"\"\n\"Import data\",\"Importe os dados\",\"\"\n\"Imported data\",\"Dados importados\",\"Automatically translated\"\n\"Include lowest value\",\"Incluir o valor mais baixo\",\"Automatically translated\"\n\"Information\",\"Em formação\",\"\"\n\"Item has been modified\",\"O item foi modificado\",\"\"\n\"Levels\",\"Níveis\",\"Automatically translated\"\n\"List of data.frame...\",\"Lista de data.frame...\",\"\"\n\"Max:\",\"Máx.:\",\"Automatically translated\"\n\"Mean:\",\"Significar:\",\"Automatically translated\"\n\"Method:\",\"Método:\",\"Automatically translated\"\n\"Min:\",\"Mínimo:\",\"Automatically translated\"\n\"Missing values characters:\",\"Caracteres de valores ausentes:\",\"Automatically translated\"\n\"Missing:\",\"Ausente:\",\"Automatically translated\"\n\"Most Common:\",\"Mais comum:\",\"Automatically translated\"\n\"New column name cannot be empty\",\"O novo nome da coluna não pode ficar vazio\",\"Automatically translated\"\n\"New column name:\",\"Novo nome de coluna:\",\"Automatically translated\"\n\"No\",\"Não\",\"\"\n\"No data selected!\",\"Nenhum dado foi selecionado!\",\"\"\n\"No data to display.\",\"Nenhum dado para mostrar.\",\"\"\n\"No data.frame here...\",\"Nenhum data.frame aqui...\",\"\"\n\"No file selected\",\"Nenhum arquivo selecionado\",\"\"\n\"No file selected:\",\"Nenhum arquivo selecionado:\",\"\"\n\"Not a data.frame\",\"Não é um data.frame\",\"Automatically translated\"\n\"Nothing pasted yet!\",\"Nada foi colado ainda!\",\"\"\n\"Number of breaks:\",\"Número de pausas:\",\"Automatically translated\"\n\"Number of rows:\",\"Número de linhas:\",\"\"\n\"OK\",\"OK\",\"\"\n\"Ooops\",\"Ooops\",\"\"\n\"Paste data here:\",\"Cole os dados aqui:\",\"\"\n\"Please copy and paste some data in the dialog box above.\",\"Por favor, copie e cole algum dado na caixa de diálogo acima.\",\"\"\n\"Please fill in the required fields\",\"Por favor, preencha os campos obrigatórios\",\"\"\n\"Please paste a valid GoogleSheet link in the dialog box above.\",\"Por favor, cole um link válido para o GoogleSheet na caixa de diálogo acima.\",\"\"\n\"Please paste a valid link in the dialog box above.\",\"Cole um link válido na caixa de diálogo acima.\",\"Automatically translated\"\n\"Registered\",\"Registrado\",\"\"\n\"Required field\",\"Campo obrigatório\",\"\"\n\"Row has been saved\",\"A linha foi salva\",\"\"\n\"Row was not deleted\",\"A linha não foi excluída\",\"\"\n\"Rows to skip before reading data:\",\"Linhas a serem ignoradas antes da leitura dos dados:\",\"Automatically translated\"\n\"Sample data by :\",\"Dados de amostra por:\",\"Automatically translated\"\n\"Save\",\"Salvar\",\"\"\n\"Select\",\"Selecionar\",\"\"\n\"Select a data.frame:\",\"Selecione um data.frame :\",\"\"\n\"Select an environment in which to search:\",\"Selecione um ambiente local para a busca:\",\"\"\n\"Select environment\",\"Selecione um ambiente local\",\"\"\n\"Select sheet to import:\",\"Selecione uma aba para importar:\",\"\"\n\"Some operations are not allowed\",\"Algumas operações não são permitidas\",\"Automatically translated\"\n\"Something went wrong...\",\"Algo deu errado...\",\"\"\n\"Sort count\",\"Contagem de classificação\",\"Automatically translated\"\n\"The URL that appear in your browser, in that case the current sheet will be read\",\"A URL que aparece no seu navegador, nesse caso a aba atual será lida\",\"\"\n\"The row has been deleted\",\"A linha foi excluída\",\"\"\n\"The row wasn't added to the data\",\"A linha não foi adicionada aos dados\",\"Automatically translated\"\n\"URL\",\"URL\",\"Automatically translated\"\n\"Unable to add the row, contact the platform administrator\",\"Não é possível adicionar a linha, entre em contato com o administrador da plataforma\",\"\"\n\"Unable to delete the row, contact platform administrator\",\"Não é possível excluir a linha, entre em contato com o administrador da plataforma\",\"\"\n\"Unable to modify the item, contact the platform administrator\",\"Não é possível modificar o item, entre em contato com o administrador da plataforma\",\"\"\n\"Unique values:\",\"Valores únicos:\",\"Automatically translated\"\n\"Unique:\",\"Exclusivo:\",\"Automatically translated\"\n\"Update\",\"Modifique\",\"\"\n\"Update & select variables\",\"Carregue & selecione variáveis\",\"\"\n\"Update factor variable\",\"Variável de fator de atualização\",\"Automatically translated\"\n\"Update levels of a factor\",\"Atualizar níveis de um fator\",\"Automatically translated\"\n\"Update row\",\"Atualizar linha\",\"\"\n\"Upload a file:\",\"Carregue um arquivo:\",\"\"\n\"Use a data.frame from your environment or from the environment of a package.\",\"Use um data.frame do seu ambiente local ou do ambiente de um pacote.\",\"\"\n\"Valid number of columns\",\"Número válido de colunas\",\"Automatically translated\"\n\"Valid number of rows\",\"Número válido de linhas\",\"Automatically translated\"\n\"Validate\",\"Validação\",\"\"\n\"Validation:\",\"Validação:\",\"\"\n\"Variable to cut:\",\"Variável para cortar:\",\"Automatically translated\"\n\"View\",\"Visualizar\",\"\"\n\"Warning\",\"Aviso\",\"Automatically translated\"\n\"Yes\",\"Sim\",\"\"\n\"You can either use:\",\"Você pode usar:\",\"\"\n\"You can import %s files\",\"Você pode importar %s\",\"\"\n\"You can import from flat table format supported by\",\"Você pode importar do formato de tabela plana suportado por\",\"Automatically translated\"\n\"click to see data\",\"clique para visualizar os dados\",\"\"\n\"data has %s obs. of %s variables.\",\"dados possuem %s observações de %s variáveis.\",\"\"\n\"if several use a comma ',' to separate them\",\"se vários usarem uma vírgula ',' para separá-los\",\"Automatically translated\"\n\"lines, i.e.\",\"linhas, ou seja,\",\"Automatically translated\"\n\"number of rows\",\"numero de linhas\",\"Automatically translated\"\n\"proportion of rows\",\"proporção de linhas\",\"Automatically translated\"\n\"rows\",\"linhas\",\"Automatically translated\"\n\"then enter an expression before clicking on the button above to validate or on \",\"em seguida, insira uma expressão antes de clicar no botão acima para validar ou em\",\"Automatically translated\"\n\"to delete it.\",\"para excluí-lo.\",\"Automatically translated\"\n\"Sort by count\",\"Classificar por contagem\",\"Automatically translated\"\n\"Sort by levels\",\"Classificar por níveis\",\"Automatically translated\"\n"
  },
  {
    "path": "inst/i18n/tr.csv",
    "content": "\"label\",\"translation\",\"comment\"\n\"% of the total\",\"toplamın yüzdesi\",\"Automatically translated\"\n\"% of the total, i.e.\",\"Toplamın yüzdesi, yani\",\"Automatically translated\"\n\"A shareable link, in that case first sheet will be read\",\"Paylaşılabilir bir bağlantı, bu durumda ilk sayfa okunacak\",\"\"\n\"Add a label to data\",\"Veriyi etiketle\",\"\"\n\"Add a row\",\"satır ekle\",\"\"\n\"Apply changes\",\"Değişiklikleri uygula\",\"\"\n\"Browse...\",\"Gözat...\",\"\"\n\"Cancel\",\"İptal\",\"\"\n\"Choose a name for the column to be created or modified,\",\"Oluşturulacak veya değiştirilecek sütun için bir ad seçin,\",\"Automatically translated\"\n\"Choose a number of rows :\",\"Bir dizi satır seçin:\",\"Automatically translated\"\n\"Choose a percentage :\",\"Bir yüzde seçin:\",\"Automatically translated\"\n\"Click on a column name to add it to the expression:\",\"İfadeye eklemek için bir sütun adına tıklayın:\",\"Automatically translated\"\n\"Click to delete\",\"silmek için tıklayın\",\"\"\n\"Click to edit\",\"Düzenlemek için tıkla\",\"\"\n\"Close\",\"Kapat\",\"\"\n\"Close intervals on the right\",\"Sağdaki yakın aralıklar\",\"Automatically translated\"\n\"Column added!\",\"Sütun eklendi!\",\"Automatically translated\"\n\"Convert Numeric to Factor\",\"Sayıyı Faktöre Dönüştür\",\"Automatically translated\"\n\"Copy & paste data\",\"Veriyi kopyala & yapıştır\",\"\"\n\"Copy / Paste\",\"Kopyala / Yapıştır\",\"\"\n\"Count\",\"Saymak\",\"Automatically translated\"\n\"Create a new column\",\"Yeni bir sütun oluştur\",\"Automatically translated\"\n\"Create a new variable otherwise replaces the one selected\",\"Yeni bir değişken oluşturun, aksi halde seçilen değişkenin yerine geçer\",\"Automatically translated\"\n\"Create column\",\"Sütun oluştur\",\"Automatically translated\"\n\"Create factor variable\",\"Faktör değişkeni oluştur\",\"Automatically translated\"\n\"Data has %s observations and %s variables.\",\"Veri %s gözlem ve %s değişken içeriyor.\",\"\"\n\"Data ready to be imported!\",\"Veri içeri alınmak için hazır!\",\"\"\n\"Data successfully imported!\",\"Veri başarıyla içeri alındı!\",\"\"\n\"Data successfully updated!\",\"Veri başarıyla güncellendi!\",\"\"\n\"Data wasn't deleted\",\"Veriler silinmedi\",\"Automatically translated\"\n\"Data wasn't updated\",\"Veriler güncellenmedi\",\"Automatically translated\"\n\"Dataset validation:\",\"Veri kümesi doğrulaması:\",\"Automatically translated\"\n\"Date format:\",\"Tarih formatı:\",\"\"\n\"Date to use as origin to convert date/datetime:\",\"Tarih/tarihsaat için başlangıç olarak kullanılacak tarih:\",\"\"\n\"Decimal separator:\",\"Ondalık ayıracı:\",\"\"\n\"Delete\",\"Silmek\",\"\"\n\"Do you want to delete the selected row ?\",\"Seçilen satırı silmek istiyor musunuz?\",\"\"\n\"Encoding:\",\"Kodlama:\",\"\"\n\"Enter URL to data:\",\"Verilerin URL'sini girin:\",\"Automatically translated\"\n\"Enter a shareable link to a GoogleSheet:\",\"GoogleSheet için paylaşılabilir bir bağlantı girin:\",\"\"\n\"Enter an expression to define new column:\",\"Yeni sütunu tanımlamak için bir ifade girin:\",\"Automatically translated\"\n\"Environment\",\"Ortam\",\"\"\n\"Error\",\"Hata\",\"\"\n\"External file\",\"Dış dosya\",\"\"\n\"Factor variable to reorder:\",\"Yeniden sıralanacak faktör değişkeni:\",\"Automatically translated\"\n\"Failed\",\"Başarısız\",\"\"\n\"First five rows are shown below:\",\"İlk beş satır aşağıda gösterilmektedir:\",\"\"\n\"Googlesheets\",\"Googlesheets\",\"\"\n\"Group calculation by:\",\"Grup hesaplaması:\",\"Automatically translated\"\n\"Help\",\"Yardım\",\"\"\n\"How to import data?\",\"Veri alma nasıl yapılır?\",\"\"\n\"Import\",\"İçeri al\",\"\"\n\"Import Google Spreadsheet\",\"GoogleSheet verisi al\",\"\"\n\"Import Url\",\"URL'yi içe aktar\",\"Automatically translated\"\n\"Import a dataset from an environment\",\"Bir veri setini bir ortamdan al\",\"\"\n\"Import a file\",\"Dosya al\",\"\"\n\"Import data\",\"Veri al\",\"\"\n\"Imported data\",\"İçe aktarılan veriler\",\"Automatically translated\"\n\"Include lowest value\",\"En düşük değeri dahil et\",\"Automatically translated\"\n\"Information\",\"Bilgi\",\"\"\n\"Item has been modified\",\"Öğe değiştirildi\",\"\"\n\"Levels\",\"Seviyeler\",\"Automatically translated\"\n\"List of data.frame...\",\"Veri tablo listesi...\",\"\"\n\"Max:\",\"Maksimum:\",\"Automatically translated\"\n\"Mean:\",\"Anlam:\",\"Automatically translated\"\n\"Method:\",\"Yöntem:\",\"Automatically translated\"\n\"Min:\",\"Min:\",\"Automatically translated\"\n\"Missing values characters:\",\"Eksik değer karakterleri:\",\"Automatically translated\"\n\"Missing:\",\"Eksik:\",\"Automatically translated\"\n\"Most Common:\",\"En Yaygın:\",\"Automatically translated\"\n\"New column name cannot be empty\",\"Yeni sütun adı boş olamaz\",\"Automatically translated\"\n\"New column name:\",\"Yeni sütun adı:\",\"Automatically translated\"\n\"No\",\"Numara\",\"\"\n\"No data selected!\",\"Veri seçilmedi!\",\"\"\n\"No data to display.\",\"Gösterilecek veri yok.\",\"\"\n\"No data.frame here...\",\"Burada veri tablosu yok...\",\"\"\n\"No file selected\",\"Dosya seçilmedi\",\"\"\n\"No file selected:\",\"Dosya seçilmedi:\",\"\"\n\"Not a data.frame\",\"Bir data.frame değil\",\"Automatically translated\"\n\"Nothing pasted yet!\",\"Henüz hiçbir şey yapıştırılmadı!\",\"\"\n\"Number of breaks:\",\"Mola sayısı:\",\"Automatically translated\"\n\"Number of rows:\",\"Satır sayısı:\",\"\"\n\"OK\",\"Tamam\",\"\"\n\"Ooops\",\"Ooops\",\"\"\n\"Paste data here:\",\"Veriyi buraya yapıştır:\",\"\"\n\"Please copy and paste some data in the dialog box above.\",\"Yukarıdaki pencereye birkaç veri kopyalayıp yapıştırın.\",\"\"\n\"Please fill in the required fields\",\"Lütfen gerekli alanları doldurunuz\",\"\"\n\"Please paste a valid GoogleSheet link in the dialog box above.\",\"Yukarıdaki pencereye geçerli bir GoogleSheet bağlantısı yapıştırın.\",\"\"\n\"Please paste a valid link in the dialog box above.\",\"Lütfen yukarıdaki iletişim kutusuna geçerli bir bağlantı yapıştırın.\",\"Automatically translated\"\n\"Registered\",\"Kayıtlı\",\"\"\n\"Required field\",\"gerekli alan\",\"\"\n\"Row has been saved\",\"Satır kaydedildi\",\"\"\n\"Row was not deleted\",\"Satır silinmedi\",\"\"\n\"Rows to skip before reading data:\",\"Verileri okumadan önce atlanacak satırlar:\",\"Automatically translated\"\n\"Sample data by :\",\"Örnek veriler:\",\"Automatically translated\"\n\"Save\",\"Kaydetmek\",\"\"\n\"Select\",\"Seçme\",\"\"\n\"Select a data.frame:\",\"Veri tablosu seçin:\",\"\"\n\"Select an environment in which to search:\",\"Arama yapılacak ortamı seçin:\",\"\"\n\"Select environment\",\"Ortam seç\",\"\"\n\"Select sheet to import:\",\"İçeri almak için sayfa seçin:\",\"\"\n\"Some operations are not allowed\",\"Bazı işlemlere izin verilmiyor\",\"Automatically translated\"\n\"Something went wrong...\",\"Bir şeyler ters gitti...\",\"\"\n\"Sort count\",\"Sıralama sayısı\",\"Automatically translated\"\n\"The URL that appear in your browser, in that case the current sheet will be read\",\"Tarayıcınızda görünen URL, bu durumda geçerli sayfa okunacak\",\"\"\n\"The row has been deleted\",\"Satır silinemiyor, platform yöneticisiyle iletişime geçin\",\"\"\n\"The row wasn't added to the data\",\"Satır verilere eklenmedi\",\"Automatically translated\"\n\"URL\",\"URL'si\",\"Automatically translated\"\n\"Unable to add the row, contact the platform administrator\",\"Satır eklenemiyor, platform yöneticisiyle iletişime geçin\",\"\"\n\"Unable to delete the row, contact platform administrator\",\"\",\"\"\n\"Unable to modify the item, contact the platform administrator\",\"Öğe değiştirilemiyor, platform yöneticisiyle iletişime geçin\",\"\"\n\"Unique values:\",\"Benzersiz değerler:\",\"Automatically translated\"\n\"Unique:\",\"Eşsiz:\",\"Automatically translated\"\n\"Update\",\"Güncelle\",\"\"\n\"Update & select variables\",\"Güncelle & değişkenleri seç\",\"\"\n\"Update factor variable\",\"Faktör değişkenini güncelle\",\"Automatically translated\"\n\"Update levels of a factor\",\"Bir faktörün düzeylerini güncelleme\",\"Automatically translated\"\n\"Update row\",\"Satırı güncelle\",\"\"\n\"Upload a file:\",\"Dosya yükle:\",\"\"\n\"Use a data.frame from your environment or from the environment of a package.\",\"Kendi ortamanızdan ya da bir paket ortamanından bir veri tablosu kullanın.\",\"\"\n\"Valid number of columns\",\"Geçerli sütun sayısı\",\"Automatically translated\"\n\"Valid number of rows\",\"Geçerli satır sayısı\",\"Automatically translated\"\n\"Validate\",\"Doğrula\",\"\"\n\"Validation:\",\"Doğrulama:\",\"\"\n\"Variable to cut:\",\"Kesilecek değişken:\",\"Automatically translated\"\n\"View\",\"Görüntüle\",\"\"\n\"Warning\",\"Uyarı\",\"Automatically translated\"\n\"Yes\",\"Evet\",\"\"\n\"You can either use:\",\"Ya da şunu kullanın:\",\"\"\n\"You can import %s files\",\"%s dosya içeri alabilirsiniz\",\"\"\n\"You can import from flat table format supported by\",\"tarafından desteklenen düz tablo formatından içe aktarabilirsiniz.\",\"Automatically translated\"\n\"click to see data\",\"veriyi görmek için tıklayın\",\"\"\n\"data has %s obs. of %s variables.\",\"veri %s gözlem %s değişken içeriyor.\",\"\"\n\"if several use a comma ',' to separate them\",\"birkaç kişi onları ayırmak için ',' virgülünü kullanıyorsa\",\"Automatically translated\"\n\"lines, i.e.\",\"çizgiler, yani\",\"Automatically translated\"\n\"number of rows\",\"satır sayısı\",\"Automatically translated\"\n\"proportion of rows\",\"satırların oranı\",\"Automatically translated\"\n\"rows\",\"satırlar\",\"Automatically translated\"\n\"then enter an expression before clicking on the button above to validate or on \",\"ardından doğrulamak için yukarıdaki düğmeye tıklamadan önce bir ifade girin veya\",\"Automatically translated\"\n\"to delete it.\",\"silmek için.\",\"Automatically translated\"\n\"Sort by count\",\"Sayıya göre sırala\",\"Automatically translated\"\n\"Sort by levels\",\"Düzeylere göre sırala\",\"Automatically translated\"\n"
  },
  {
    "path": "man/create-column.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/create-column.R, R/update-factor.R\n\\name{create-column}\n\\alias{create-column}\n\\alias{create_column_ui}\n\\alias{create_column_server}\n\\alias{list_allowed_operations}\n\\alias{modal_create_column}\n\\alias{winbox_create_column}\n\\alias{winbox_update_factor}\n\\title{Create new column}\n\\usage{\ncreate_column_ui(id)\n\ncreate_column_server(\n  id,\n  data_r = reactive(NULL),\n  allowed_operations = list_allowed_operations()\n)\n\nlist_allowed_operations()\n\nmodal_create_column(\n  id,\n  title = i18n(\"Create a new column\"),\n  easyClose = TRUE,\n  size = \"l\",\n  footer = NULL\n)\n\nwinbox_create_column(\n  id,\n  title = i18n(\"Create a new column\"),\n  options = shinyWidgets::wbOptions(),\n  controls = shinyWidgets::wbControls()\n)\n\nwinbox_update_factor(\n  id,\n  title = i18n(\"Update levels of a factor\"),\n  options = shinyWidgets::wbOptions(),\n  controls = shinyWidgets::wbControls()\n)\n}\n\\arguments{\n\\item{id}{Module's ID.}\n\n\\item{data_r}{A \\code{\\link[shiny:reactive]{shiny::reactive()}} function returning a \\code{data.frame}.}\n\n\\item{allowed_operations}{A \\code{list} of allowed operations, see below for details.}\n\n\\item{title}{An optional title for the dialog.}\n\n\\item{easyClose}{If \\code{TRUE}, the modal dialog can be dismissed by\nclicking outside the dialog box, or be pressing the Escape key. If\n\\code{FALSE} (the default), the modal dialog can't be dismissed in those\nways; instead it must be dismissed by clicking on a \\code{modalButton()}, or\nfrom a call to \\code{\\link[shiny:removeModal]{removeModal()}} on the server.}\n\n\\item{size}{One of \\code{\"s\"} for small, \\code{\"m\"} (the default) for medium,\n\\code{\"l\"} for large, or \\code{\"xl\"} for extra large. Note that \\code{\"xl\"} only\nworks with Bootstrap 4 and above (to opt-in to Bootstrap 4+,\npass \\code{\\link[bslib:bs_theme]{bslib::bs_theme()}} to the \\code{theme} argument of a page container\nlike \\code{\\link[shiny:fluidPage]{fluidPage()}}).}\n\n\\item{footer}{UI for footer. Use \\code{NULL} for no footer.}\n\n\\item{options}{List of options, see \\code{\\link[shinyWidgets:wbOptions]{wbOptions()}}.}\n\n\\item{controls}{List of controls, see \\code{\\link[shinyWidgets:wbControls]{wbControls()}}.}\n}\n\\value{\nA \\code{\\link[shiny:reactive]{shiny::reactive()}} function returning the data.\n}\n\\description{\nThis module allow to enter an expression to create a new column in a \\code{data.frame}.\n}\n\\note{\nUser can only use a subset of function: (, c, +, -, *, ^, \\%\\%, \\%/\\%, /, ==, >, <, !=, <=, >=, &, |, abs, sign, sqrt, ceiling, floor, trunc, cummax, cummin, cumprod, cumsum, exp, expm1, log, log10, log2, log1p, cos, cosh, sin, sinh, tan, tanh, acos, acosh, asin, asinh, atan, atanh, cospi, sinpi, tanpi, gamma, lgamma, digamma, trigamma, round, signif, max, min, range, prod, sum, any, all, pmin, pmax, mean, paste, paste0, substr, nchar, trimws, gsub, sub, grepl, ifelse, length, as.numeric, as.character, as.integer, as.Date, as.POSIXct, as.factor, factor.\nYou can add more operations using the \\code{allowed_operations} argument, for  example if you want to allow to use package lubridate, you can do:\n\n\\if{html}{\\out{<div class=\"sourceCode r\">}}\\preformatted{c(list_allowed_operations(), getNamespaceExports(\"lubridate\"))\n}\\if{html}{\\out{</div>}}\n}\n\\examples{\n\nlibrary(shiny)\nlibrary(datamods)\nlibrary(reactable)\n\nui <- fluidPage(\n  theme = bslib::bs_theme(version = 5L, preset = \"bootstrap\"),\n  shinyWidgets::html_dependency_winbox(),\n  tags$h2(\"Create new column\"),\n  fluidRow(\n    column(\n      width = 4,\n      create_column_ui(\"inline\"),\n      actionButton(\"modal\", \"Or click here to open a modal to create a column\"),\n      tags$br(), tags$br(),\n      actionButton(\"winbox\", \"Or click here to open a WinBox to create a column\")\n    ),\n    column(\n      width = 8,\n      reactableOutput(outputId = \"table\"),\n      verbatimTextOutput(\"code\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  rv <- reactiveValues(data = MASS::Cars93[, c(1, 3, 4, 5, 6, 10)])\n\n  # inline mode\n  data_inline_r <- create_column_server(\n    id = \"inline\",\n    data_r = reactive(rv$data)\n  )\n  observeEvent(data_inline_r(), rv$data <- data_inline_r())\n\n  # modal window mode\n  observeEvent(input$modal, modal_create_column(\"modal\"))\n  data_modal_r <- create_column_server(\n    id = \"modal\",\n    data_r = reactive(rv$data)\n  )\n  observeEvent(data_modal_r(), rv$data <- data_modal_r())\n\n  # WinBox window mode\n  observeEvent(input$winbox, winbox_create_column(\"winbox\"))\n  data_winbox_r <- create_column_server(\n    id = \"winbox\",\n    data_r = reactive(rv$data)\n  )\n  observeEvent(data_winbox_r(), rv$data <- data_winbox_r())\n\n  # Show result\n  output$table <- renderReactable({\n    data <- req(rv$data)\n    reactable(\n      data = data,\n      bordered = TRUE,\n      compact = TRUE,\n      striped = TRUE\n    )\n  })\n\n  output$code <- renderPrint({\n    attr(rv$data, \"code\")\n  })\n}\n\nif (interactive())\n  shinyApp(ui, server)\n}\n"
  },
  {
    "path": "man/cut-variable.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/cut-variable.R\n\\name{cut-variable}\n\\alias{cut-variable}\n\\alias{cut_variable_ui}\n\\alias{cut_variable_server}\n\\alias{modal_cut_variable}\n\\alias{winbox_cut_variable}\n\\title{Module to Convert Numeric to Factor}\n\\usage{\ncut_variable_ui(id)\n\ncut_variable_server(id, data_r = reactive(NULL))\n\nmodal_cut_variable(\n  id,\n  title = i18n(\"Convert Numeric to Factor\"),\n  easyClose = TRUE,\n  size = \"l\",\n  footer = NULL\n)\n\nwinbox_cut_variable(\n  id,\n  title = i18n(\"Convert Numeric to Factor\"),\n  options = shinyWidgets::wbOptions(),\n  controls = shinyWidgets::wbControls()\n)\n}\n\\arguments{\n\\item{id}{Module ID.}\n\n\\item{data_r}{A \\code{\\link[shiny:reactive]{shiny::reactive()}} function returning a \\code{data.frame}.}\n\n\\item{title}{An optional title for the dialog.}\n\n\\item{easyClose}{If \\code{TRUE}, the modal dialog can be dismissed by\nclicking outside the dialog box, or be pressing the Escape key. If\n\\code{FALSE} (the default), the modal dialog can't be dismissed in those\nways; instead it must be dismissed by clicking on a \\code{modalButton()}, or\nfrom a call to \\code{\\link[shiny:removeModal]{removeModal()}} on the server.}\n\n\\item{size}{One of \\code{\"s\"} for small, \\code{\"m\"} (the default) for medium,\n\\code{\"l\"} for large, or \\code{\"xl\"} for extra large. Note that \\code{\"xl\"} only\nworks with Bootstrap 4 and above (to opt-in to Bootstrap 4+,\npass \\code{\\link[bslib:bs_theme]{bslib::bs_theme()}} to the \\code{theme} argument of a page container\nlike \\code{\\link[shiny:fluidPage]{fluidPage()}}).}\n\n\\item{footer}{UI for footer. Use \\code{NULL} for no footer.}\n\n\\item{options}{List of options, see \\code{\\link[shinyWidgets:wbOptions]{wbOptions()}}.}\n\n\\item{controls}{List of controls, see \\code{\\link[shinyWidgets:wbControls]{wbControls()}}.}\n}\n\\value{\nA \\code{\\link[shiny:reactive]{shiny::reactive()}} function returning the data.\n}\n\\description{\nThis module contain an interface to cut a numeric into several intervals.\n}\n\\examples{\n\nlibrary(shiny)\nlibrary(datamods)\nlibrary(reactable)\n\nui <- fluidPage(\n  theme = bslib::bs_theme(version = 5L, preset = \"bootstrap\"),\n  shinyWidgets::html_dependency_winbox(),\n  tags$h2(\"Convert Numeric to Factor\"),\n  fluidRow(\n    column(\n      width = 6,\n      cut_variable_ui(\"inline\"),\n      actionButton(\"modal\", \"Or click here to open a modal to cut a variable\"),\n      tags$br(), tags$br(),\n      actionButton(\"winbox\", \"Or click here to open a WinBox to cut a variable\")\n    ),\n    column(\n      width = 6,\n      reactableOutput(outputId = \"table\"),\n      verbatimTextOutput(\"code\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  rv <- reactiveValues(data = MASS::Cars93[, c(1, 3, 4, 5, 6, 10)])\n\n  # inline mode\n  data_inline_r <- cut_variable_server(\n    id = \"inline\",\n    data_r = reactive(rv$data)\n  )\n  observeEvent(data_inline_r(), rv$data <- data_inline_r())\n\n  # modal window mode\n  observeEvent(input$modal, modal_cut_variable(\"modal\"))\n  data_modal_r <- cut_variable_server(\n    id = \"modal\",\n    data_r = reactive(rv$data)\n  )\n  observeEvent(data_modal_r(), rv$data <- data_modal_r())\n\n  # WinBox window mode\n  observeEvent(input$winbox, winbox_cut_variable(\"winbox\"))\n  data_winbox_r <- cut_variable_server(\n    id = \"winbox\",\n    data_r = reactive(rv$data)\n  )\n  observeEvent(data_winbox_r(), rv$data <- data_winbox_r())\n\n  # Show result\n  output$table <- renderReactable({\n    data <- req(rv$data)\n    reactable(\n      data = data,\n      bordered = TRUE,\n      compact = TRUE,\n      striped = TRUE\n    )\n  })\n\n  output$code <- renderPrint({\n    attr(rv$data, \"code\")\n  })\n}\n\nif (interactive())\n  shinyApp(ui, server)\n}\n"
  },
  {
    "path": "man/demo_edit.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/data.R\n\\docType{data}\n\\name{demo_edit}\n\\alias{demo_edit}\n\\title{Customer Credit Card Information}\n\\format{\n\\subsection{\\code{demo_edit}}{\n\nA data frame with 20 rows and 6 columns:\n\\describe{\n\\item{name}{Customer name}\n\\item{job}{Customer job}\n\\item{credit_card_provider}{Credit card provider}\n\\item{credit_card_security_code}{Credit card security code}\n\\item{date_obtained}{Date of obtaining the credit card}\n\\item{contactless_card}{Contactless card}\n}\n}\n}\n\\source{\n\\url{https://CRAN.R-project.org/package=charlatan}\n}\n\\usage{\ndemo_edit\n}\n\\description{\nA subset of fake customer credit card information inspired by the \\code{{charlatan}} package.\n}\n\\keyword{datasets}\n"
  },
  {
    "path": "man/edit-data.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/edit-data.R\n\\name{edit-data}\n\\alias{edit-data}\n\\alias{edit_data_ui}\n\\alias{edit_data_server}\n\\title{Shiny module to interactively edit a \\code{data.frame}}\n\\usage{\nedit_data_ui(id)\n\nedit_data_server(\n  id,\n  data_r = reactive(NULL),\n  add = TRUE,\n  update = TRUE,\n  delete = TRUE,\n  download_csv = TRUE,\n  download_excel = TRUE,\n  file_name_export = \"data\",\n  var_edit = NULL,\n  var_mandatory = NULL,\n  var_labels = NULL,\n  add_default_values = list(),\n  n_column = 1,\n  return_class = c(\"data.frame\", \"data.table\", \"tbl_df\", \"raw\"),\n  reactable_options = NULL,\n  modal_size = c(\"m\", \"s\", \"l\", \"xl\"),\n  modal_easy_close = TRUE,\n  callback_add = NULL,\n  callback_update = NULL,\n  callback_delete = NULL,\n  only_callback = FALSE,\n  use_notify = TRUE\n)\n}\n\\arguments{\n\\item{id}{Module ID}\n\n\\item{data_r}{data_r \\code{reactive} function containing a \\code{data.frame} to use in the module.}\n\n\\item{add}{\\code{boolean}, if \\code{TRUE}, allows you to add a row in the table via a button at the top right.}\n\n\\item{update}{\\code{boolean}, if \\code{TRUE}, allows you to modify a row of the table via a button located in the table on the row you want to edit.}\n\n\\item{delete}{\\code{boolean}, if \\code{TRUE}, allows a row to be deleted from the table via a button in the table.}\n\n\\item{download_csv}{if \\code{TRUE}, allows to export the table in csv format via a download button.}\n\n\\item{download_excel}{if \\code{TRUE}, allows to export the table in excel format via a download button.}\n\n\\item{file_name_export}{\\code{character} that allows you to choose the export name of the downloaded file.}\n\n\\item{var_edit}{vector of \\code{character} which allows to choose the names of the editable columns.}\n\n\\item{var_mandatory}{vector of \\code{character} which allows to choose obligatory fields to fill.}\n\n\\item{var_labels}{named list, where names are colnames and values are labels to be used in edit modal.}\n\n\\item{add_default_values}{Default values to use for input control when adding new data, e.g. \\code{list(my_var_text = \"Default text to display\")}.}\n\n\\item{n_column}{Number of column in the edit modal window, must be a number that divide 12 since it use Bootstrap grid system with \\code{\\link[shiny:column]{shiny::column()}}.}\n\n\\item{return_class}{Class of returned data: \\code{data.frame}, \\code{data.table}, \\code{tbl_df} (tibble) or \\code{raw}.}\n\n\\item{reactable_options}{Options passed to \\code{\\link[reactable:reactable]{reactable::reactable()}}.}\n\n\\item{modal_size}{\\code{character} which allows to choose the size of the modalDialog. One of \"s\" for small, \"m\" (the default) for medium, \"l\" for large, or \"xl\" for extra large.}\n\n\\item{modal_easy_close}{\\code{boolean} If TRUE, modalDialog can be dismissed by clicking outside the dialog box, or be pressing the Escape key. If FALSE (the default), modalDialog can't be dismissed in those ways; instead it must be dismissed by clicking on a modalButton(), or from a call to removeModal() on the server.}\n\n\\item{callback_add, callback_update, callback_delete}{Functions to be executed just before an action (add, update or delete) is performed on the data.\nFunctions used must be like \\code{function(data, row) {...}} where :\n\\itemize{\n\\item \\code{data} will be the data in the table at the moment the function is called\n\\item \\code{row} will contain either a new row of data (add), an updated row (update) or the row that will be deleted (delete).\n}\n\nIf the return value of a callback function is not truthy (see \\code{\\link[shiny:isTruthy]{shiny::isTruthy()}}) then the action is cancelled.}\n\n\\item{only_callback}{Only use callbacks, don't alter data within the module.}\n\n\\item{use_notify}{Display information or not to user through \\code{\\link[shinybusy:notify]{shinybusy::notify()}}.}\n}\n\\value{\nthe edited \\code{data.frame} in reactable format with the user modifications\n}\n\\description{\nThe module generates different options to edit a \\code{data.frame}: adding, deleting and modifying rows, exporting data (csv and excel), choosing editable columns, choosing mandatory columns.\nThis module returns the edited table with the user modifications.\n}\n\\examples{\nlibrary(shiny)\nlibrary(datamods)\nlibrary(bslib)\nlibrary(reactable)\n\nui <- fluidPage(\n  theme = bs_theme(\n    version = 5\n  ),\n  tags$h2(\"Edit data\", align = \"center\"),\n  edit_data_ui(id = \"id\"),\n  verbatimTextOutput(\"result\")\n)\n\n\nserver <- function(input, output, session) {\n\n  edited_r <- edit_data_server(\n    id = \"id\",\n    data_r = reactive(demo_edit),\n    add = TRUE,\n    update = TRUE,\n    delete = TRUE,\n    download_csv = TRUE,\n    download_excel = TRUE,\n    file_name_export = \"datas\",\n    # var_edit = c(\"name\", \"job\", \"credit_card_provider\", \"credit_card_security_code\"),\n    var_mandatory = c(\"name\", \"job\"),\n    var_labels = list(\n      name = \"Name\",\n      credit_card_security_code = \"Credit card security code\",\n      date_obtained = \"Date obtained\",\n      contactless_card = \"Contactless Card\",\n      credit_card_provider = \"Credit card provider\"\n    ),\n    add_default_values = list(\n      name = \"Please enter your name here\",\n      date_obtained = Sys.Date()\n    ),\n    n_column = 2,\n    modal_size = \"l\",\n    modal_easy_close = TRUE,\n    reactable_options = list(\n      defaultColDef = colDef(filterable = TRUE),\n      selection = \"single\",\n      columns = list(\n        name = colDef(name = \"Name\", style = list(fontWeight = \"bold\")),\n        credit_card_security_code = colDef(name = \"Credit card security code\"),\n        date_obtained = colDef(name = \"Date obtained\", format = colFormat(date = TRUE)),\n        contactless_card = colDef(\n          name = \"Contactless Card\",\n          cell = htmlwidgets::JS(\n            \"function(cellInfo) {\n              return cellInfo.value ? '\\u2714\\ufe0f Yes' : '\\u274c No';\n            }\"\n          )\n        ),\n        credit_card_provider = colDef(\n          name = \"Credit card provider\",\n          style = htmlwidgets::JS(\n            \"function(rowInfo) {\n              console.log(rowInfo);\n              var value = rowInfo.values['credit_card_provider'];\n              var color;\n              if (value == 'Mastercard') {\n                color = '#e06631';\n              } else if (value == 'VISA 16 digit') {\n                color = '#0c13cf';\n              } else if (value == 'American Express') {\n                color = '#4d8be8';\n              } else if (value == 'JCB 16 digit') {\n                color = '#23c45e';\n              } else {\n                color = '#777'\n              }\n              return {color: color, fontWeight: 'bold'}\n            }\"\n          )\n        )\n      ),\n      bordered = TRUE,\n      compact = TRUE,\n      searchable = TRUE,\n      highlight = TRUE\n    )\n  )\n\n  output$result <- renderPrint({\n    str(edited_r())\n  })\n\n}\n\nif (interactive())\n  shinyApp(ui, server)\n}\n"
  },
  {
    "path": "man/filter-data.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/filter-data.R\n\\name{filter-data}\n\\alias{filter-data}\n\\alias{filter_data_ui}\n\\alias{filter_data_server}\n\\title{Shiny module to interactively filter a \\code{data.frame}}\n\\usage{\nfilter_data_ui(id, show_nrow = TRUE, max_height = NULL)\n\nfilter_data_server(\n  id,\n  data = reactive(NULL),\n  vars = reactive(NULL),\n  name = reactive(\"data\"),\n  defaults = reactive(NULL),\n  drop_ids = getOption(\"datamods.filter.drop_ids\", default = TRUE),\n  widget_char = c(\"virtualSelect\", \"select\", \"picker\"),\n  widget_num = c(\"slider\", \"range\"),\n  widget_date = c(\"slider\", \"range\"),\n  label_na = \"NA\",\n  value_na = TRUE\n)\n}\n\\arguments{\n\\item{id}{Module id. See \\code{\\link[shiny:moduleServer]{shiny::moduleServer()}}.}\n\n\\item{show_nrow}{Show number of filtered rows and total.}\n\n\\item{max_height}{Maximum height for filters panel, useful\nif you have many variables to filter and limited space.}\n\n\\item{data}{\\code{\\link[shiny:reactive]{shiny::reactive()}} function returning a\n\\code{data.frame} to filter.}\n\n\\item{vars}{\\code{\\link[shiny:reactive]{shiny::reactive()}} function returning a\n\\code{character} vector of variables for which to add a filter.\nIf a named \\code{list}, names are used as labels.}\n\n\\item{name}{\\code{\\link[shiny:reactive]{shiny::reactive()}} function returning a\n\\code{character} string representing \\code{data} name, only used for code generated.}\n\n\\item{defaults}{\\code{\\link[shiny:reactive]{shiny::reactive()}} function returning a\nnamed \\code{list} of variable:value pairs which will be used to set the filters.}\n\n\\item{drop_ids}{Drop columns containing more than 90\\% of unique values, or than 50 distinct values.\nUse \\code{FALSE} to disable or use \\code{list(p = 0.9, n = 50)} to customize threshold values.}\n\n\\item{widget_char}{Widget to use for \\code{character} variables: \\code{\\link[shinyWidgets:pickerInput]{shinyWidgets::pickerInput()}}\nor \\code{\\link[shiny:selectInput]{shiny::selectInput()}} (default).}\n\n\\item{widget_num}{Widget to use for \\code{numeric} variables: \\code{\\link[shinyWidgets:numericRangeInput]{shinyWidgets::numericRangeInput()}}\nor \\code{\\link[shiny:sliderInput]{shiny::sliderInput()}} (default).}\n\n\\item{widget_date}{Widget to use for \\code{date/time} variables: \\code{\\link[shiny:dateRangeInput]{shiny::dateRangeInput()}}\nor \\code{\\link[shiny:sliderInput]{shiny::sliderInput()}} (default).}\n\n\\item{label_na}{Label for missing value widget.}\n\n\\item{value_na}{Default value for all NA's filters.}\n}\n\\value{\n\\itemize{\n\\item UI: HTML tags that can be included in shiny's UI\n\\item Server: a \\code{list} with four slots:\n\\itemize{\n\\item \\strong{filtered}: a \\code{reactive} function returning the data filtered.\n\\item \\strong{code}: a \\code{reactive} function returning the dplyr pipeline to filter data.\n\\item \\strong{expr}: a \\code{reactive} function returning an expression to filter data.\n\\item \\strong{values}: a \\code{reactive} function returning a named list of variables and filter values.\n}\n}\n}\n\\description{\nModule generate inputs to filter \\code{data.frame} according column's type.\nCode to reproduce the filter is returned as an expression with filtered data.\n}\n\\examples{\nlibrary(shiny)\nlibrary(shinyWidgets)\nlibrary(datamods)\nlibrary(MASS)\n\n# Add some NAs to mpg\nmtcars_na <- mtcars\nmtcars_na[] <- lapply(\n  X = mtcars_na,\n  FUN = function(x) {\n    x[sample.int(n = length(x), size = sample(5:10, 1))] <- NA\n    x\n  }\n)\n\ndatetime <- data.frame(\n  date = seq(Sys.Date(), by = \"day\", length.out = 300),\n  datetime = seq(Sys.time(), by = \"hour\", length.out = 300),\n  num = sample.int(1e5, 300)\n)\n\none_column_numeric <- data.frame(\n  var1 = rnorm(100)\n)\n\nui <- fluidPage(\n  tags$h2(\"Filter data.frame\"),\n  actionButton(\"saveFilterButton\",\"Save Filter Values\"),\n  actionButton(\"loadFilterButton\",\"Load Filter Values\"),\n  radioButtons(\n    inputId = \"dataset\",\n    label = \"Data:\",\n    choices = c(\n      \"iris\",\n      \"mtcars\",\n      \"mtcars_na\",\n      \"Cars93\",\n      \"datetime\",\n      \"one_column_numeric\"\n    ),\n    inline = TRUE\n  ),\n\n  fluidRow(\n    column(\n      width = 3,\n      filter_data_ui(\"filtering\", max_height = \"500px\")\n    ),\n    column(\n      width = 9,\n      progressBar(\n        id = \"pbar\", value = 100,\n        total = 100, display_pct = TRUE\n      ),\n      reactable::reactableOutput(outputId = \"table\"),\n      tags$b(\"Code dplyr:\"),\n      verbatimTextOutput(outputId = \"code_dplyr\"),\n      tags$b(\"Expression:\"),\n      verbatimTextOutput(outputId = \"code\"),\n      tags$b(\"Filtered data:\"),\n      verbatimTextOutput(outputId = \"res_str\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n  savedFilterValues <- reactiveVal()\n  data <- reactive({\n    get(input$dataset)\n  })\n\n  vars <- reactive({\n    if (identical(input$dataset, \"mtcars\")) {\n      setNames(as.list(names(mtcars)[1:5]), c(\n        \"Miles/(US) gallon\",\n        \"Number of cylinders\",\n        \"Displacement (cu.in.)\",\n        \"Gross horsepower\",\n        \"Rear axle ratio\"\n      ))\n    } else {\n      NULL\n    }\n  })\n  \n  observeEvent(input$saveFilterButton,{\n    savedFilterValues <<- res_filter$values()\n  },ignoreInit = T)\n  \n  defaults <- reactive({\n    input$loadFilterButton\n    savedFilterValues\n  })\n\n  res_filter <- filter_data_server(\n    id = \"filtering\",\n    data = data,\n    name = reactive(input$dataset),\n    vars = vars,\n    defaults = defaults,\n    widget_num = \"slider\",\n    widget_date = \"slider\",\n    label_na = \"Missing\"\n  )\n\n  observeEvent(res_filter$filtered(), {\n    updateProgressBar(\n      session = session, id = \"pbar\",\n      value = nrow(res_filter$filtered()), total = nrow(data())\n    )\n  })\n\n  output$table <- reactable::renderReactable({\n    reactable::reactable(res_filter$filtered())\n  })\n\n\n  output$code_dplyr <- renderPrint({\n    res_filter$code()\n  })\n  output$code <- renderPrint({\n    res_filter$expr()\n  })\n\n  output$res_str <- renderPrint({\n    str(res_filter$filtered())\n  })\n\n}\n\nif (interactive())\n  shinyApp(ui, server)\n}\n"
  },
  {
    "path": "man/get_data_packages.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/import-globalenv.R\n\\name{get_data_packages}\n\\alias{get_data_packages}\n\\title{Get packages containing datasets}\n\\usage{\nget_data_packages()\n}\n\\value{\na character vector of packages names\n}\n\\description{\nGet packages containing datasets\n}\n\\examples{\nif (interactive()) {\n\n  get_data_packages()\n\n}\n}\n"
  },
  {
    "path": "man/i18n.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/i18n.R\n\\name{i18n}\n\\alias{i18n}\n\\alias{i18n_translations}\n\\alias{set_i18n}\n\\title{Internationalization}\n\\usage{\ni18n(x, translations = i18n_translations())\n\ni18n_translations(package = packageName(parent.frame(2)))\n\nset_i18n(value, packages = c(\"datamods\", \"esquisse\"))\n}\n\\arguments{\n\\item{x}{Label to translate.}\n\n\\item{translations}{Either a \\code{list} or a \\code{data.frame} with translations.}\n\n\\item{package}{Name of the package where the function is called, use \\code{NULL} outside a package.\nIt will retrieve option \\code{\"i18n.<PACKAGE>\"} (or \\code{\"i18n\"} if no package) to returns appropriate labels.}\n\n\\item{value}{Value to set for translation. Can be:\n\\itemize{\n\\item single \\code{character} to use a supported language (\\code{\"fr\"}, \\code{\"mk\"}, \\code{\"al\"}, \\code{\"pt\"} for esquisse and datamods packages).\n\\item a \\code{list} with labels as names and translations as values.\n\\item a \\code{data.frame} with 2 column: \\code{label} & \\code{translation}.\n\\item path to a CSV file with same structure as for \\code{data.frame} above.\n}}\n\n\\item{packages}{Name of packages for which to set i18n, default to esquisse and datamods}\n}\n\\value{\n\\code{i18n()} returns a \\code{character}, \\code{i18n_translations()} returns a \\code{list} or a \\code{data.frame}.\n}\n\\description{\nSimple mechanism to translate labels in a Shiny application.\n}\n\\examples{\nlibrary(datamods)\n\n# Use with an objet\nmy.translations <- list(\n  \"Hello\" = \"Bonjour\"\n)\ni18n(\"Hello\", my.translations)\n\n# Use with options()\noptions(\"i18n\" = list(\n  \"Hello\" = \"Bonjour\"\n))\ni18n(\"Hello\")\n\n# With a package\noptions(\"datamods.i18n\" = \"fr\")\ni18n(\"Browse...\", translations = i18n_translations(\"datamods\"))\n# If you call i18n() from within a function of your package\n# you don't need second argument, e.g.:\n# i18n(\"Browse...\")\n}\n"
  },
  {
    "path": "man/import-copypaste.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/import-copypaste.R\n\\name{import-copypaste}\n\\alias{import-copypaste}\n\\alias{import_copypaste_ui}\n\\alias{import_copypaste_server}\n\\title{Import data with copy & paste}\n\\usage{\nimport_copypaste_ui(id, title = TRUE, name_field = TRUE)\n\nimport_copypaste_server(\n  id,\n  btn_show_data = TRUE,\n  show_data_in = c(\"popup\", \"modal\"),\n  trigger_return = c(\"button\", \"change\"),\n  return_class = c(\"data.frame\", \"data.table\", \"tbl_df\", \"raw\"),\n  reset = reactive(NULL),\n  fread_args = list()\n)\n}\n\\arguments{\n\\item{id}{Module's ID.}\n\n\\item{title}{Module's title, if \\code{TRUE} use the default title,\nuse \\code{NULL} for no title or a \\code{shiny.tag} for a custom one.}\n\n\\item{name_field}{Show or not a field to add a name to data (that is returned server-side).}\n\n\\item{btn_show_data}{Display or not a button to display data in a modal window if import is successful.}\n\n\\item{show_data_in}{Where to display data: in a \\code{\"popup\"} or in a \\code{\"modal\"} window.}\n\n\\item{trigger_return}{When to update selected data:\n\\code{\"button\"} (when user click on button) or\n\\code{\"change\"} (each time user select a dataset in the list).}\n\n\\item{return_class}{Class of returned data: \\code{data.frame}, \\code{data.table}, \\code{tbl_df} (tibble) or \\code{raw}.}\n\n\\item{reset}{A \\code{reactive} function that when triggered resets the data.}\n\n\\item{fread_args}{\\code{list} of additional arguments to pass to \\code{\\link[data.table:fread]{data.table::fread()}} when reading data.}\n}\n\\value{\n\\itemize{\n\\item UI: HTML tags that can be included in shiny's UI\n\\item Server: a \\code{list} with three slots:\n\\itemize{\n\\item \\strong{status}: a \\code{reactive} function returning the status: \\code{NULL}, \\code{error} or \\code{success}.\n\\item \\strong{name}: a \\code{reactive} function returning the name of the imported data as \\code{character}.\n\\item \\strong{data}: a \\code{reactive} function returning the imported \\code{data.frame}.\n}\n}\n}\n\\description{\nLet the user copy data from Excel or text file then paste it into a text area to import it.\n}\n\\examples{\n\nlibrary(shiny)\nlibrary(datamods)\n\nui <- fluidPage(\n  tags$h3(\"Import data with copy & paste\"),\n  fluidRow(\n    column(\n      width = 4,\n      import_copypaste_ui(\"myid\")\n    ),\n    column(\n      width = 8,\n      tags$b(\"Import status:\"),\n      verbatimTextOutput(outputId = \"status\"),\n      tags$b(\"Name:\"),\n      verbatimTextOutput(outputId = \"name\"),\n      tags$b(\"Data:\"),\n      verbatimTextOutput(outputId = \"data\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  imported <- import_copypaste_server(\"myid\")\n\n  output$status <- renderPrint({\n    imported$status()\n  })\n  output$name <- renderPrint({\n    imported$name()\n  })\n  output$data <- renderPrint({\n    imported$data()\n  })\n\n}\n\nif (interactive())\n  shinyApp(ui, server)\n}\n"
  },
  {
    "path": "man/import-file.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/import-file.R\n\\name{import-file}\n\\alias{import-file}\n\\alias{import_file_ui}\n\\alias{import_file_server}\n\\title{Import data from a file}\n\\usage{\nimport_file_ui(\n  id,\n  title = TRUE,\n  preview_data = TRUE,\n  file_extensions = c(\".csv\", \".txt\", \".xls\", \".xlsx\", \".rds\", \".fst\", \".sas7bdat\",\n    \".sav\"),\n  layout_params = c(\"dropdown\", \"inline\")\n)\n\nimport_file_server(\n  id,\n  btn_show_data = TRUE,\n  show_data_in = \"winbox\",\n  trigger_return = c(\"button\", \"change\"),\n  return_class = c(\"data.frame\", \"data.table\", \"tbl_df\", \"raw\"),\n  reset = reactive(NULL),\n  read_fns = list()\n)\n}\n\\arguments{\n\\item{id}{Module's ID.}\n\n\\item{title}{Module's title, if \\code{TRUE} use the default title,\nuse \\code{NULL} for no title or a \\code{shiny.tag} for a custom one.}\n\n\\item{preview_data}{Show or not a preview of the data under the file input.}\n\n\\item{file_extensions}{File extensions accepted by \\code{\\link[shiny:fileInput]{shiny::fileInput()}}, can also be MIME type.}\n\n\\item{layout_params}{How to display import parameters : in a dropdown button or inline below file input.}\n\n\\item{btn_show_data}{Display or not a button to display data in a modal window if import is successful.}\n\n\\item{show_data_in}{Where to display data: in a \\code{\"popup\"} or in a \\code{\"modal\"} window.}\n\n\\item{trigger_return}{When to update selected data:\n\\code{\"button\"} (when user click on button) or\n\\code{\"change\"} (each time user select a dataset in the list).}\n\n\\item{return_class}{Class of returned data: \\code{data.frame}, \\code{data.table}, \\code{tbl_df} (tibble) or \\code{raw}.}\n\n\\item{reset}{A \\code{reactive} function that when triggered resets the data.}\n\n\\item{read_fns}{Named list with custom function(s) to read data:\n\\itemize{\n\\item the name must be the extension of the files to which the function will be applied\n\\item the value must be a function that can have 5 arguments (you can ignore some of them, but you have to use the same names),\npassed by user through the interface:\n\\itemize{\n\\item \\code{file}: path to the file\n\\item \\code{sheet}: for Excel files, sheet to read\n\\item \\code{skip}: number of row to skip\n\\item \\code{dec}: decimal separator\n\\item \\code{encoding}: file encoding\n\\item \\code{na.strings}: character(s) to interpret as missing values.\n}\n}}\n}\n\\value{\n\\itemize{\n\\item UI: HTML tags that can be included in shiny's UI\n\\item Server: a \\code{list} with three slots:\n\\itemize{\n\\item \\strong{status}: a \\code{reactive} function returning the status: \\code{NULL}, \\code{error} or \\code{success}.\n\\item \\strong{name}: a \\code{reactive} function returning the name of the imported data as \\code{character}.\n\\item \\strong{data}: a \\code{reactive} function returning the imported \\code{data.frame}.\n}\n}\n}\n\\description{\nLet user upload a file and import data\n}\n\\examples{\n\n\nlibrary(shiny)\nlibrary(datamods)\n\nui <- fluidPage(\n  # theme = bslib::bs_theme(version = 5L),\n  # theme = bslib::bs_theme(version = 5L, preset = \"bootstrap\"),\n  tags$h3(\"Import data from a file\"),\n  fluidRow(\n    column(\n      width = 4,\n      import_file_ui(\n        id = \"myid\",\n        file_extensions = c(\".csv\", \".txt\", \".xls\", \".xlsx\", \".json\"),\n        layout_params = \"inline\" # or \"dropdown\"\n      )\n    ),\n    column(\n      width = 8,\n      tags$b(\"Import status:\"),\n      verbatimTextOutput(outputId = \"status\"),\n      tags$b(\"Name:\"),\n      verbatimTextOutput(outputId = \"name\"),\n      tags$b(\"Code:\"),\n      verbatimTextOutput(outputId = \"code\"),\n      tags$b(\"Data:\"),\n      verbatimTextOutput(outputId = \"data\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  imported <- import_file_server(\n    id = \"myid\",\n    # Custom functions to read data\n    read_fns = list(\n      xls = function(file, sheet, skip, encoding) {\n        readxl::read_xls(path = file, sheet = sheet, skip = skip)\n      },\n      json = function(file) {\n        jsonlite::read_json(file, simplifyVector = TRUE)\n      }\n    ),\n    show_data_in = \"modal\"\n  )\n\n  output$status <- renderPrint({\n    imported$status()\n  })\n  output$name <- renderPrint({\n    imported$name()\n  })\n  output$code <- renderPrint({\n    imported$code()\n  })\n  output$data <- renderPrint({\n    imported$data()\n  })\n\n}\n\nif (interactive())\n  shinyApp(ui, server)\n}\n"
  },
  {
    "path": "man/import-globalenv.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/import-globalenv.R\n\\name{import-globalenv}\n\\alias{import-globalenv}\n\\alias{import_globalenv_ui}\n\\alias{import_globalenv_server}\n\\title{Import data from an Environment}\n\\usage{\nimport_globalenv_ui(\n  id,\n  globalenv = TRUE,\n  packages = get_data_packages(),\n  title = TRUE\n)\n\nimport_globalenv_server(\n  id,\n  btn_show_data = TRUE,\n  show_data_in = c(\"popup\", \"modal\"),\n  trigger_return = c(\"button\", \"change\"),\n  return_class = c(\"data.frame\", \"data.table\", \"tbl_df\", \"raw\"),\n  reset = reactive(NULL)\n)\n}\n\\arguments{\n\\item{id}{Module's ID.}\n\n\\item{globalenv}{Search for data in Global environment.}\n\n\\item{packages}{Name of packages in which to search data.}\n\n\\item{title}{Module's title, if \\code{TRUE} use the default title,\nuse \\code{NULL} for no title or a \\code{shiny.tag} for a custom one.}\n\n\\item{btn_show_data}{Display or not a button to display data in a modal window if import is successful.}\n\n\\item{show_data_in}{Where to display data: in a \\code{\"popup\"} or in a \\code{\"modal\"} window.}\n\n\\item{trigger_return}{When to update selected data:\n\\code{\"button\"} (when user click on button) or\n\\code{\"change\"} (each time user select a dataset in the list).}\n\n\\item{return_class}{Class of returned data: \\code{data.frame}, \\code{data.table}, \\code{tbl_df} (tibble) or \\code{raw}.}\n\n\\item{reset}{A \\code{reactive} function that when triggered resets the data.}\n}\n\\value{\n\\itemize{\n\\item UI: HTML tags that can be included in shiny's UI\n\\item Server: a \\code{list} with three slots:\n\\itemize{\n\\item \\strong{status}: a \\code{reactive} function returning the status: \\code{NULL}, \\code{error} or \\code{success}.\n\\item \\strong{name}: a \\code{reactive} function returning the name of the imported data as \\code{character}.\n\\item \\strong{data}: a \\code{reactive} function returning the imported \\code{data.frame}.\n}\n}\n}\n\\description{\nLet the user select a dataset from its own environment or from a package's environment.\n}\n\\examples{\nif (interactive()) {\n  library(shiny)\n  library(datamods)\n\n  # Create some data.frames\n\n  my_df <- data.frame(\n    variable1 = sample(letters, 20, TRUE),\n    variable2 = sample(1:100, 20, TRUE)\n  )\n\n  results_analysis <- data.frame(\n    id = sample(letters, 20, TRUE),\n    measure = sample(1:100, 20, TRUE),\n    response = sample(1:100, 20, TRUE)\n  )\n\n\n  # Application\n\n  ui <- fluidPage(\n    fluidRow(\n      column(\n        width = 4,\n        import_globalenv_ui(\"myid\")\n      ),\n      column(\n        width = 8,\n        tags$b(\"Import status:\"),\n        verbatimTextOutput(outputId = \"status\"),\n        tags$b(\"Name:\"),\n        verbatimTextOutput(outputId = \"name\"),\n        tags$b(\"Data:\"),\n        verbatimTextOutput(outputId = \"data\")\n      )\n    )\n  )\n\n  server <- function(input, output, session) {\n\n    imported <- import_globalenv_server(\"myid\")\n\n    output$status <- renderPrint({\n      imported$status()\n    })\n    output$name <- renderPrint({\n      imported$name()\n    })\n    output$data <- renderPrint({\n      imported$data()\n    })\n\n  }\n\n  shinyApp(ui, server)\n}\n}\n"
  },
  {
    "path": "man/import-googlesheets.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/import-googlesheets.R\n\\name{import-googlesheets}\n\\alias{import-googlesheets}\n\\alias{import_googlesheets_ui}\n\\alias{import_googlesheets_server}\n\\title{Import data from Googlesheet}\n\\usage{\nimport_googlesheets_ui(id, title = TRUE)\n\nimport_googlesheets_server(\n  id,\n  btn_show_data = TRUE,\n  show_data_in = c(\"popup\", \"modal\"),\n  trigger_return = c(\"button\", \"change\"),\n  return_class = c(\"data.frame\", \"data.table\", \"tbl_df\", \"raw\"),\n  reset = reactive(NULL)\n)\n}\n\\arguments{\n\\item{id}{Module's ID.}\n\n\\item{title}{Module's title, if \\code{TRUE} use the default title,\nuse \\code{NULL} for no title or a \\code{shiny.tag} for a custom one.}\n\n\\item{btn_show_data}{Display or not a button to display data in a modal window if import is successful.}\n\n\\item{show_data_in}{Where to display data: in a \\code{\"popup\"} or in a \\code{\"modal\"} window.}\n\n\\item{trigger_return}{When to update selected data:\n\\code{\"button\"} (when user click on button) or\n\\code{\"change\"} (each time user select a dataset in the list).}\n\n\\item{return_class}{Class of returned data: \\code{data.frame}, \\code{data.table}, \\code{tbl_df} (tibble) or \\code{raw}.}\n\n\\item{reset}{A \\code{reactive} function that when triggered resets the data.}\n}\n\\value{\n\\itemize{\n\\item UI: HTML tags that can be included in shiny's UI\n\\item Server: a \\code{list} with three slots:\n\\itemize{\n\\item \\strong{status}: a \\code{reactive} function returning the status: \\code{NULL}, \\code{error} or \\code{success}.\n\\item \\strong{name}: a \\code{reactive} function returning the name of the imported data as \\code{character}.\n\\item \\strong{data}: a \\code{reactive} function returning the imported \\code{data.frame}.\n}\n}\n}\n\\description{\nLet user paste link to a Google sheet then import the data.\n}\n\\examples{\n\nlibrary(shiny)\nlibrary(datamods)\n\nui <- fluidPage(\n  tags$h3(\"Import data from Googlesheets\"),\n  fluidRow(\n    column(\n      width = 4,\n      import_googlesheets_ui(\"myid\")\n    ),\n    column(\n      width = 8,\n      tags$b(\"Import status:\"),\n      verbatimTextOutput(outputId = \"status\"),\n      tags$b(\"Name:\"),\n      verbatimTextOutput(outputId = \"name\"),\n      tags$b(\"Data:\"),\n      verbatimTextOutput(outputId = \"data\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  imported <- import_googlesheets_server(\"myid\")\n\n  output$status <- renderPrint({\n    imported$status()\n  })\n  output$name <- renderPrint({\n    imported$name()\n  })\n  output$data <- renderPrint({\n    imported$data()\n  })\n\n}\n\nif (interactive())\n  shinyApp(ui, server)\n}\n"
  },
  {
    "path": "man/import-modal.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/import-modal.R\n\\name{import-modal}\n\\alias{import-modal}\n\\alias{import_ui}\n\\alias{import_server}\n\\alias{import_modal}\n\\title{Import from all sources}\n\\usage{\nimport_ui(\n  id,\n  from = c(\"env\", \"file\", \"copypaste\", \"googlesheets\", \"url\"),\n  file_extensions = c(\".csv\", \".txt\", \".xls\", \".xlsx\", \".rds\", \".fst\", \".sas7bdat\",\n    \".sav\")\n)\n\nimport_server(\n  id,\n  validation_opts = NULL,\n  allowed_status = c(\"OK\", \"Failed\", \"Error\"),\n  return_class = c(\"data.frame\", \"data.table\", \"tbl_df\", \"raw\"),\n  read_fns = list()\n)\n\nimport_modal(\n  id,\n  from,\n  title = i18n(\"Import data\"),\n  size = \"l\",\n  file_extensions = c(\".csv\", \".txt\", \".xls\", \".xlsx\", \".rds\", \".fst\", \".sas7bdat\",\n    \".sav\")\n)\n}\n\\arguments{\n\\item{id}{Module's id}\n\n\\item{from}{The import_ui & server to use, i.e. the method.\nThere are 5 options to choose from. (\"env\", \"file\", \"copypaste\", \"googlesheets\", \"url\")}\n\n\\item{file_extensions}{File extensions accepted by \\code{\\link[shiny:fileInput]{shiny::fileInput()}}, can also be MIME type.}\n\n\\item{validation_opts}{\\code{list} of arguments passed to [validation_server().}\n\n\\item{allowed_status}{Vector of statuses allowed to confirm dataset imported,\nif you want that all validation rules are successful before importing data use \\code{allowed_status = \"OK\"}.}\n\n\\item{return_class}{Class of returned data: \\code{data.frame}, \\code{data.table}, \\code{tbl_df} (tibble) or \\code{raw}.}\n\n\\item{read_fns}{Named list with custom function(s) to read data:\n\\itemize{\n\\item the name must be the extension of the files to which the function will be applied\n\\item the value must be a function that can have 5 arguments (you can ignore some of them, but you have to use the same names),\npassed by user through the interface:\n\\itemize{\n\\item \\code{file}: path to the file\n\\item \\code{sheet}: for Excel files, sheet to read\n\\item \\code{skip}: number of row to skip\n\\item \\code{dec}: decimal separator\n\\item \\code{encoding}: file encoding\n\\item \\code{na.strings}: character(s) to interpret as missing values.\n}\n}}\n\n\\item{title}{Modal window title.}\n\n\\item{size}{Modal window size, default to \\code{\"l\"} (large).}\n}\n\\value{\n\\itemize{\n\\item UI: HTML tags that can be included in shiny's UI\n\\item Server: a \\code{list} with three slots:\n\\itemize{\n\\item \\strong{status}: a \\code{reactive} function returning the status: \\code{NULL}, \\code{error} or \\code{success}.\n\\item \\strong{name}: a \\code{reactive} function returning the name of the imported data as \\code{character}.\n\\item \\strong{data}: a \\code{reactive} function returning the imported \\code{data.frame}.\n}\n}\n}\n\\description{\nWrap all import modules into one, can be displayed inline or in a modal window..\n}\n\\examples{\n\nlibrary(shiny)\nlibrary(datamods)\n\nui <- fluidPage(\n  # Try with different Bootstrap version\n  theme = bslib::bs_theme(version = 5, preset = \"bootstrap\"),\n  fluidRow(\n    column(\n      width = 4,\n      checkboxGroupInput(\n        inputId = \"from\",\n        label = \"From\",\n        choices = c(\"env\", \"file\", \"copypaste\", \"googlesheets\", \"url\"),\n        selected = c(\"file\", \"copypaste\")\n      ),\n      actionButton(\"launch_modal\", \"Launch modal window\")\n    ),\n    column(\n      width = 8,\n      tags$b(\"Imported data:\"),\n      verbatimTextOutput(outputId = \"name\"),\n      verbatimTextOutput(outputId = \"data\"),\n      verbatimTextOutput(outputId = \"str_data\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  observeEvent(input$launch_modal, {\n    req(input$from)\n    import_modal(\n      id = \"myid\",\n      from = input$from,\n      title = \"Import data to be used in application\"\n    )\n  })\n\n  imported <- import_server(\"myid\", return_class = \"tbl_df\")\n\n  output$name <- renderPrint({\n    req(imported$name())\n    imported$name()\n  })\n\n  output$data <- renderPrint({\n    req(imported$data())\n    imported$data()\n  })\n\n  output$str_data <- renderPrint({\n    req(imported$data())\n    str(imported$data())\n  })\n\n}\n\nif (interactive())\n  shinyApp(ui, server)\n}\n"
  },
  {
    "path": "man/import-url.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/import-url.R\n\\name{import-url}\n\\alias{import-url}\n\\alias{import_url_ui}\n\\alias{import_url_server}\n\\title{Import data from a URL}\n\\usage{\nimport_url_ui(id, title = TRUE)\n\nimport_url_server(\n  id,\n  btn_show_data = TRUE,\n  show_data_in = c(\"popup\", \"modal\"),\n  trigger_return = c(\"button\", \"change\"),\n  return_class = c(\"data.frame\", \"data.table\", \"tbl_df\", \"raw\"),\n  reset = reactive(NULL)\n)\n}\n\\arguments{\n\\item{id}{Module's ID.}\n\n\\item{title}{Module's title, if \\code{TRUE} use the default title,\nuse \\code{NULL} for no title or a \\code{shiny.tag} for a custom one.}\n\n\\item{btn_show_data}{Display or not a button to display data in a modal window if import is successful.}\n\n\\item{show_data_in}{Where to display data: in a \\code{\"popup\"} or in a \\code{\"modal\"} window.}\n\n\\item{trigger_return}{When to update selected data:\n\\code{\"button\"} (when user click on button) or\n\\code{\"change\"} (each time user select a dataset in the list).}\n\n\\item{return_class}{Class of returned data: \\code{data.frame}, \\code{data.table}, \\code{tbl_df} (tibble) or \\code{raw}.}\n\n\\item{reset}{A \\code{reactive} function that when triggered resets the data.}\n}\n\\value{\n\\itemize{\n\\item UI: HTML tags that can be included in shiny's UI\n\\item Server: a \\code{list} with three slots:\n\\itemize{\n\\item \\strong{status}: a \\code{reactive} function returning the status: \\code{NULL}, \\code{error} or \\code{success}.\n\\item \\strong{name}: a \\code{reactive} function returning the name of the imported data as \\code{character}.\n\\item \\strong{data}: a \\code{reactive} function returning the imported \\code{data.frame}.\n}\n}\n}\n\\description{\nLet user paste link to a JSON then import the data.\n}\n\\examples{\n\nlibrary(shiny)\nlibrary(datamods)\n\nui <- fluidPage(\n  tags$h3(\"Import data from URL\"),\n  fluidRow(\n    column(\n      width = 4,\n      import_url_ui(\"myid\")\n    ),\n    column(\n      width = 8,\n      tags$b(\"Import status:\"),\n      verbatimTextOutput(outputId = \"status\"),\n      tags$b(\"Name:\"),\n      verbatimTextOutput(outputId = \"name\"),\n      tags$b(\"Data:\"),\n      verbatimTextOutput(outputId = \"data\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  imported <- import_url_server(\n    \"myid\",\n    btn_show_data = FALSE,\n    return_class = \"raw\"\n  )\n\n  output$status <- renderPrint({\n    imported$status()\n  })\n  output$name <- renderPrint({\n    imported$name()\n  })\n  output$data <- renderPrint({\n    imported$data()\n  })\n\n}\n\nif (interactive())\n  shinyApp(ui, server)\n}\n"
  },
  {
    "path": "man/list_pkg_data.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/import-globalenv.R\n\\name{list_pkg_data}\n\\alias{list_pkg_data}\n\\title{List dataset contained in a package}\n\\usage{\nlist_pkg_data(pkg)\n}\n\\arguments{\n\\item{pkg}{Name of the package, must be installed.}\n}\n\\value{\na \\code{character} vector or \\code{NULL}.\n}\n\\description{\nList dataset contained in a package\n}\n\\examples{\n\nlist_pkg_data(\"ggplot2\")\n}\n"
  },
  {
    "path": "man/module-sample.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/sample-data.R\n\\name{module-sample}\n\\alias{module-sample}\n\\alias{sample_ui}\n\\alias{sample_server}\n\\title{Shiny module to interactively sample a \\code{data.frame}}\n\\usage{\nsample_ui(id)\n\nsample_server(id, data_r = reactive(NULL))\n}\n\\arguments{\n\\item{id}{Module id. See \\code{\\link[shiny:moduleServer]{shiny::moduleServer()}}.}\n\n\\item{data_r}{\\code{reactive} containing a \\code{data.frame} to use in the module.}\n}\n\\value{\n\\itemize{\n\\item UI: HTML tags that can be included in shiny's UI\n\\item Server: a \\code{reactive} fgunction with the sampled data.\n}\n}\n\\description{\nAllow to take a sample of \\code{data.frame} for a given number or proportion of rows to keep.\n}\n\\examples{\nlibrary(shiny)\nlibrary(datamods)\nlibrary(reactable)\n\n\nui <- fluidPage(\n\n  tags$h2(\"Sampling\"),\n\n  fluidRow(\n    column(\n      width = 3,\n      sample_ui(\"myID\")\n    ),\n    column(\n      width = 9,\n      reactableOutput(\"table\")\n    )\n  )\n)\n\n\nserver <- function(input, output, session) {\n\n  result_sample <- sample_server(\"myID\", reactive(iris))\n\n  output$table <- renderReactable({\n    table_sample <- reactable(\n      data = result_sample(),\n      defaultColDef = colDef(\n        align = \"center\"\n      ),\n      borderless = TRUE,\n      highlight = TRUE,\n      striped = TRUE\n    )\n    return(table_sample)\n  })\n}\n\nif (interactive())\n  shinyApp(ui, server)\n\n}\n"
  },
  {
    "path": "man/select-group.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/select-group.R\n\\name{select-group}\n\\alias{select-group}\n\\alias{select_group_ui}\n\\alias{select_group_server}\n\\title{Select Group Input Module}\n\\usage{\nselect_group_ui(\n  id,\n  params,\n  label = NULL,\n  btn_reset_label = \"Reset filters\",\n  inline = TRUE,\n  vs_args = list()\n)\n\nselect_group_server(id, data_r, vars_r, selected_r = reactive(list()))\n}\n\\arguments{\n\\item{id}{Module's id.}\n\n\\item{params}{A list of parameters passed to each \\code{\\link[shinyWidgets:virtualSelectInput]{shinyWidgets::virtualSelectInput()}},\nyou can use :\n\\itemize{\n\\item \\code{inputId}: mandatory, must correspond to variable name.\n\\item \\code{label}: Display label for the control.\n\\item \\code{placeholder}: Text to show when no options selected.\n}}\n\n\\item{label}{Character, global label on top of all labels.}\n\n\\item{btn_reset_label}{Character, reset button label. If \\code{NULL} no button is added.}\n\n\\item{inline}{If \\code{TRUE} (the default),\nselect menus are horizontally positioned, otherwise vertically.}\n\n\\item{vs_args}{Arguments passed to all \\code{\\link[shinyWidgets:virtualSelectInput]{shinyWidgets::virtualSelectInput()}} created.}\n\n\\item{data_r}{Either a \\code{\\link[=data.frame]{data.frame()}} or a \\code{\\link[shiny:reactive]{shiny::reactive()}}\nfunction returning a \\code{data.frame} (do not use parentheses).}\n\n\\item{vars_r}{character, columns to use to create filters,\nmust correspond to variables listed in \\code{params}. Can be a\n\\code{\\link[shiny:reactive]{shiny::reactive()}} function, but values must be included in the initial ones (in \\code{params}).}\n\n\\item{selected_r}{\\code{\\link[shiny:reactive]{shiny::reactive()}} function returning a named list with selected values to set.}\n}\n\\value{\nA \\code{\\link[shiny:reactive]{shiny::reactive()}} function containing data filtered with an attribute \\code{inputs} containing a named list of selected inputs.\n}\n\\description{\nGroup of mutually dependent select menus for filtering \\code{data.frame}'s columns (like in Excel).\n}\n\\examples{\n# Default -----------------------------------------------------------------\n\nlibrary(shiny)\nlibrary(datamods)\nlibrary(shinyWidgets)\n\n\nui <- fluidPage(\n  # theme = bslib::bs_theme(version = 5L),\n  fluidRow(\n    column(\n      width = 10, offset = 1,\n      tags$h3(\"Filter data with select group module\"),\n      shinyWidgets::panel(\n        select_group_ui(\n          id = \"my-filters\",\n          params = list(\n            list(inputId = \"Manufacturer\", label = \"Manufacturer:\"),\n            list(inputId = \"Type\", label = \"Type:\"),\n            list(inputId = \"AirBags\", label = \"AirBags:\"),\n            list(inputId = \"DriveTrain\", label = \"DriveTrain:\")\n          ), vs_args = list(disableSelectAll = FALSE)\n        ),\n        status = \"primary\"\n      ),\n      reactable::reactableOutput(outputId = \"table\"),\n      tags$b(\"Inputs values:\"),\n      verbatimTextOutput(\"inputs\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n  res_mod <- select_group_server(\n    id = \"my-filters\",\n    data = reactive(MASS::Cars93),\n    vars = reactive(c(\"Manufacturer\", \"Type\", \"AirBags\", \"DriveTrain\"))\n  )\n\n  output$table <- reactable::renderReactable({\n    reactable::reactable(res_mod())\n  })\n\n  output$inputs <- renderPrint({\n    attr(res_mod(), \"inputs\")\n  })\n}\n\nif (interactive())\n  shinyApp(ui, server)\n\n\n# Selected value --------------------------------------------------------------------\n\nlibrary(shiny)\nlibrary(datamods)\n\nui <- fluidPage(\n  select_group_ui(\n    id = \"my-filters\",\n    params = list(\n      list(inputId = \"Manufacturer\", label = \"Manufacturer:\"),\n      list(inputId = \"Type\", label = \"Type:\")\n    ),\n    vs_args = list(\n      disableSelectAll = FALSE\n    )\n  ),\n  actionButton(\"set_sel\", \"Set Manufacturer=Acura\"),\n  verbatimTextOutput(\"res\")\n)\n\nserver <- function(input, output, session) {\n  # We use a reactiveValue so that it can be updated\n  rv <- reactiveValues(selected = list(Manufacturer = \"Audi\")) # for init\n  res_r <- select_group_server(\n    id = \"my-filters\",\n    data = reactive(MASS::Cars93),\n    vars = reactive(c(\"Manufacturer\", \"Type\")),\n    selected_r = reactive(rv$selected)\n  )\n  output$res <- renderPrint({\n    res_r()\n  })\n  observeEvent(input$set_sel, {\n    rv$selected <- list(Manufacturer = \"Acura\")\n  })\n}\n\nif (interactive())\n  shinyApp(ui, server)\n}\n"
  },
  {
    "path": "man/show_data.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/show_data.R\n\\name{show_data}\n\\alias{show_data}\n\\title{Display a table in a window}\n\\usage{\nshow_data(\n  data,\n  title = NULL,\n  options = NULL,\n  show_classes = TRUE,\n  type = c(\"popup\", \"modal\", \"winbox\"),\n  width = \"65\\%\",\n  ...,\n  session = shiny::getDefaultReactiveDomain()\n)\n}\n\\arguments{\n\\item{data}{a data object (either a \\code{matrix} or a \\code{data.frame}).}\n\n\\item{title}{Title to be displayed in window.}\n\n\\item{options}{Arguments passed to \\code{\\link[toastui:datagrid]{toastui::datagrid()}}.}\n\n\\item{show_classes}{Show variables classes under variables names in table header.}\n\n\\item{type}{Display table in a pop-up with \\code{\\link[shinyWidgets:sweetalert]{shinyWidgets::show_alert()}},\nin modal window with \\code{\\link[shiny:showModal]{shiny::showModal()}} or in a WinBox window with \\code{\\link[shinyWidgets:WinBox]{shinyWidgets::WinBox()}}.}\n\n\\item{width}{Width of the window, only used if \\code{type = \"popup\"} or \\code{type = \"winbox\"}.}\n\n\\item{...}{Additional options, such as \\code{wbOptions = wbOptions()} or \\code{wbControls = wbControls()}.}\n\n\\item{session}{The \\code{session} object passed to function given to\n\\code{shinyServer}.}\n}\n\\value{\nNo value.\n}\n\\description{\nDisplay a table in a window\n}\n\\note{\nIf you use \\code{type = \"winbox\"}, you'll need to use \\code{shinyWidgets::html_dependency_winbox()} somewhere in your UI.\n}\n\\examples{\n\nlibrary(shiny)\nlibrary(datamods)\n\nui <- fluidPage(\n  theme = bslib::bs_theme(version = 5L),\n  shinyWidgets::html_dependency_winbox(),\n  actionButton(\n    inputId = \"show1\",\n    label = \"Show data in popup\",\n    icon = icon(\"eye\")\n  ),\n  actionButton(\n    inputId = \"show2\",\n    label = \"Show data in modal\",\n    icon = icon(\"eye\")\n  ),\n  actionButton(\n    inputId = \"show3\",\n    label = \"Show data without classes\",\n    icon = icon(\"eye\")\n  ),\n  actionButton(\n    inputId = \"show4\",\n    label = \"Show data in Winbox\",\n    icon = icon(\"eye\")\n  )\n)\n\nserver <- function(input, output, session) {\n  observeEvent(input$show1, {\n    show_data(MASS::Cars93, title = \"MASS::Cars93 dataset\", type = \"popup\")\n  })\n  observeEvent(input$show2, {\n    show_data(MASS::Cars93, title = \"MASS::Cars93 dataset\", type = \"modal\")\n  })\n  observeEvent(input$show3, {\n    show_data(\n      data = MASS::Cars93,\n      title = \"MASS::Cars93 dataset\",\n      show_classes = FALSE,\n      options = list(pagination = 10),\n      type = \"modal\"\n    )\n  })\n  observeEvent(input$show4, {\n    show_data(\n      MASS::Cars93,\n      title = \"MASS::Cars93 dataset\",\n      type = \"winbox\",\n      wbOptions = shinyWidgets::wbOptions(background = \"forestgreen\")\n    )\n  })\n}\n\nif (interactive())\n  shinyApp(ui, server)\n}\n"
  },
  {
    "path": "man/update-factor.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/update-factor.R\n\\name{update-factor}\n\\alias{update-factor}\n\\alias{update_factor_ui}\n\\alias{update_factor_server}\n\\alias{modal_update_factor}\n\\title{Module to Reorder the Levels of a Factor Variable}\n\\usage{\nupdate_factor_ui(id)\n\nupdate_factor_server(id, data_r = reactive(NULL))\n\nmodal_update_factor(\n  id,\n  title = i18n(\"Update levels of a factor\"),\n  easyClose = TRUE,\n  size = \"l\",\n  footer = NULL\n)\n}\n\\arguments{\n\\item{id}{Module ID.}\n\n\\item{data_r}{A \\code{\\link[shiny:reactive]{shiny::reactive()}} function returning a \\code{data.frame}.}\n\n\\item{title}{An optional title for the dialog.}\n\n\\item{easyClose}{If \\code{TRUE}, the modal dialog can be dismissed by\nclicking outside the dialog box, or be pressing the Escape key. If\n\\code{FALSE} (the default), the modal dialog can't be dismissed in those\nways; instead it must be dismissed by clicking on a \\code{modalButton()}, or\nfrom a call to \\code{\\link[shiny:removeModal]{removeModal()}} on the server.}\n\n\\item{size}{One of \\code{\"s\"} for small, \\code{\"m\"} (the default) for medium,\n\\code{\"l\"} for large, or \\code{\"xl\"} for extra large. Note that \\code{\"xl\"} only\nworks with Bootstrap 4 and above (to opt-in to Bootstrap 4+,\npass \\code{\\link[bslib:bs_theme]{bslib::bs_theme()}} to the \\code{theme} argument of a page container\nlike \\code{\\link[shiny:fluidPage]{fluidPage()}}).}\n\n\\item{footer}{UI for footer. Use \\code{NULL} for no footer.}\n}\n\\value{\nA \\code{\\link[shiny:reactive]{shiny::reactive()}} function returning the data.\n}\n\\description{\nThis module contain an interface to reorder the levels of a factor variable.\n}\n\\examples{\n\nlibrary(shiny)\nlibrary(datamods)\nlibrary(ggplot2)\n\nui <- fluidPage(\n  theme = bslib::bs_theme(version = 5L, preset = \"bootstrap\"),\n  shinyWidgets::html_dependency_winbox(),\n  tags$h2(\"Reorder the Levels of a Factor\"),\n  fluidRow(\n    column(\n      width = 6,\n      update_factor_ui(\"id\"),\n      actionButton(\"modal\", \"Or click here to open a modal to update factor's level\"),\n      tags$br(), tags$br(),\n      actionButton(\"winbox\", \"Or click here to open a WinBox to create a column\")\n    ),\n    column(\n      width = 6,\n      selectInput(\n        \"var\",\n        label = \"Variable to plot:\",\n        choices = NULL\n      ),\n      plotOutput(\"plot\"),\n      verbatimTextOutput(\"res\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  rv <- reactiveValues(data = MASS::Cars93[c(1, 2, 3, 9, 10, 11, 16, 26, 27)])\n  observe(\n    updateSelectInput(inputId = \"var\", choices = names(rv$data))\n  )\n\n  # Inline mode\n  data_inline_r <- update_factor_server(\n    id = \"id\",\n    data_r = reactive(rv$data)\n  )\n  observeEvent(data_inline_r(), rv$data <- data_inline_r())\n\n  # modal window mode\n  observeEvent(input$modal, modal_update_factor(\"modal\"))\n  data_modal_r <- update_factor_server(\n    id = \"modal\",\n    data_r = reactive(rv$data)\n  )\n  observeEvent(data_modal_r(), {\n    shiny::removeModal()\n    rv$data <- data_modal_r()\n  })\n\n  # winbox mode\n  observeEvent(input$winbox, winbox_update_factor(\"winbox\"))\n  data_winbox_r <- update_factor_server(\n    id = \"winbox\",\n    data_r = reactive(rv$data)\n  )\n  observeEvent(data_winbox_r(), rv$data <- data_winbox_r())\n\n  # Plot results\n  output$plot <- renderPlot({\n    req(input$var, rv$data)\n    ggplot(rv$data) +\n      aes(x = !!sym(input$var)) +\n      geom_bar()\n  })\n  # Show results\n  output$res <- renderPrint({\n    data <- req(rv$data)\n    str(data)\n  })\n}\n\nif (interactive())\n  shinyApp(ui, server)\n}\n"
  },
  {
    "path": "man/update-variables.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/update-variables.R\n\\name{update-variables}\n\\alias{update-variables}\n\\alias{update_variables_ui}\n\\alias{update_variables_server}\n\\title{Select, rename and convert variables}\n\\usage{\nupdate_variables_ui(id, title = TRUE)\n\nupdate_variables_server(\n  id,\n  data,\n  height = NULL,\n  return_data_on_init = FALSE,\n  try_silent = FALSE\n)\n}\n\\arguments{\n\\item{id}{Module's ID}\n\n\\item{title}{Module's title, if \\code{TRUE} use the default title,\nuse \\code{NULL} for no title or a \\code{shiny.tag} for a custom one.}\n\n\\item{data}{a \\code{data.frame} or a \\code{reactive} function returning a \\code{data.frame}.}\n\n\\item{height}{Height for the table.}\n\n\\item{return_data_on_init}{Return initial data when module is called.}\n\n\\item{try_silent}{logical: should the report of error messages be suppressed?}\n}\n\\value{\nA \\code{\\link[shiny:reactive]{shiny::reactive()}} function returning the updated data.\n}\n\\description{\nSelect, rename and convert variables\n}\n\\examples{\n\nlibrary(shiny)\nlibrary(datamods)\n\ntestdata <- data.frame(\n  date_as_char = as.character(Sys.Date() + 0:9),\n  date_as_num = as.numeric(Sys.Date() + 0:9),\n  datetime_as_char = as.character(Sys.time() + 0:9 * 3600*24),\n  datetime_as_num = as.numeric(Sys.time() + 0:9 * 3600*24),\n  num_as_char = as.character(1:10),\n  char = month.name[1:10],\n  char_na = c(\"A\", \"A\", \"B\", NA, \"B\", \"A\", NA, \"B\", \"A\", \"B\"),\n  stringsAsFactors = FALSE\n)\n\nui <- fluidPage(\n  theme = bslib::bs_theme(version = 5L, preset = \"bootstrap\"),\n  tags$h3(\"Select, rename and convert variables\"),\n  fluidRow(\n    column(\n      width = 6,\n      # radioButtons()\n      update_variables_ui(\"vars\")\n    ),\n    column(\n      width = 6,\n      tags$b(\"original data:\"),\n      verbatimTextOutput(\"original\"),\n      verbatimTextOutput(\"original_str\"),\n      tags$b(\"Modified data:\"),\n      verbatimTextOutput(\"modified\"),\n      verbatimTextOutput(\"modified_str\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  updated_data <- update_variables_server(\n    id = \"vars\",\n    data = reactive(testdata),\n    return_data_on_init = FALSE\n  )\n\n  output$original <- renderPrint({\n    testdata\n  })\n  output$original_str <- renderPrint({\n    str(testdata)\n  })\n\n  output$modified <- renderPrint({\n    updated_data()\n  })\n  output$modified_str <- renderPrint({\n    str(updated_data())\n  })\n}\n\nif (interactive())\n  shinyApp(ui, server)\n}\n"
  },
  {
    "path": "man/validation.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/validation.R\n\\name{validation_ui}\n\\alias{validation_ui}\n\\alias{validation_server}\n\\title{Validation module}\n\\usage{\nvalidation_ui(id, display = c(\"dropdown\", \"inline\"), max_height = NULL, ...)\n\nvalidation_server(\n  id,\n  data,\n  n_row = NULL,\n  n_col = NULL,\n  n_row_label = i18n(\"Valid number of rows\"),\n  n_col_label = i18n(\"Valid number of columns\"),\n  btn_label = i18n(\"Dataset validation:\"),\n  rules = NULL,\n  bs_version = 3\n)\n}\n\\arguments{\n\\item{id}{Module's ID.}\n\n\\item{display}{Display validation results in a dropdown menu\nby clicking on a button or display results directly in interface.}\n\n\\item{max_height}{Maximum height for validation results element, useful if you have many rules.}\n\n\\item{...}{Arguments passed to \\code{actionButton} or \\code{uiOutput} depending on display mode,\nyou cannot use \\code{inputId}/\\code{outputId}, \\code{label} or \\code{icon} (button only).}\n\n\\item{data}{a \\code{reactive} function returning a \\code{data.frame}.}\n\n\\item{n_row, n_col}{A one-sided formula to check number of rows and columns respectively, see below for examples.}\n\n\\item{n_row_label, n_col_label}{Text to be displayed with the result of the check for number of rows/columns.}\n\n\\item{btn_label}{Label for the dropdown button, will be followed by validation result.}\n\n\\item{rules}{An object of class \\code{validator} created with \\code{validate::validator}.}\n\n\\item{bs_version}{Bootstrap version used, it may affect rendering, especially status badges.}\n}\n\\value{\n\\itemize{\n\\item UI: HTML tags that can be included in shiny's UI\n\\item Server: a \\code{list} with two slots:\n\\itemize{\n\\item \\strong{status}: a \\code{reactive} function returning the best status available between \\code{\"OK\"}, \\code{\"Failed\"} or \\code{\"Error\"}.\n\\item \\strong{details}: a \\code{reactive} function returning a \\code{list} with validation details.\n}\n}\n}\n\\description{\nCheck that a dataset respect some validation expectations.\n}\n\\examples{\nlibrary(datamods)\nlibrary(shiny)\n\nif (requireNamespace(\"validate\")) {\n  library(validate)\n\n  # Define some rules to be applied to data\n  myrules <- validator(\n    is.character(Manufacturer) | is.factor(Manufacturer),\n    is.numeric(Price),\n    Price > 12, # we should use 0 for testing positivity, but that's for the example\n    !is.na(Luggage.room),\n    in_range(Cylinders, min = 4, max = 8),\n    Man.trans.avail \\%in\\% c(\"Yes\", \"No\")\n  )\n  # Add some labels\n  label(myrules) <- c(\n    \"Variable Manufacturer must be character\",\n    \"Variable Price must be numeric\",\n    \"Variable Price must be strictly positive\",\n    \"Luggage.room must not contain any missing values\",\n    \"Cylinders must be between 4 and 8\",\n    \"Man.trans.avail must be 'Yes' or 'No'\"\n  )\n  # you can also add a description()\n\n  ui <- fluidPage(\n    tags$h2(\"Validation\"),\n    fluidRow(\n      column(\n        width = 4,\n        radioButtons(\n          inputId = \"dataset\",\n          label = \"Choose dataset:\",\n          choices = c(\"mtcars\", \"MASS::Cars93\")\n        ),\n        tags$p(\"Dropdown example:\"),\n        validation_ui(\"validation1\"),\n\n        tags$br(),\n\n        tags$p(\"Inline example:\"),\n        validation_ui(\"validation2\", display = \"inline\")\n      ),\n      column(\n        width = 8,\n        tags$b(\"Status:\"),\n        verbatimTextOutput(\"status\"),\n        tags$b(\"Details:\"),\n        verbatimTextOutput(\"details\")\n      )\n    )\n  )\n\n  server <- function(input, output, session) {\n\n    dataset <- reactive({\n      if (input$dataset == \"mtcars\") {\n        mtcars\n      } else {\n        MASS::Cars93\n      }\n    })\n\n    results <- validation_server(\n      id = \"validation1\",\n      data = dataset,\n      n_row = ~ . > 20, # more than 20 rows\n      n_col = ~ . >= 3, # at least 3 columns\n      rules = myrules\n    )\n\n    validation_server(\n      id = \"validation2\",\n      data = dataset,\n      n_row = ~ . > 20, # more than 20 rows\n      n_col = ~ . >= 3, # at least 3 columns\n      rules = myrules\n    )\n\n    output$status <- renderPrint(results$status())\n    output$details <- renderPrint(results$details())\n\n  }\n\n  if (interactive())\n    shinyApp(ui, server)\n}\n}\n"
  },
  {
    "path": "man-roxygen/module-import.R",
    "content": "#' @return\n#' * UI: HTML tags that can be included in shiny's UI\n#' * Server: a `list` with three slots:\n#'   + **status**: a `reactive` function returning the status: `NULL`, `error` or `success`.\n#'   + **name**: a `reactive` function returning the name of the imported data as `character`.\n#'   + **data**: a `reactive` function returning the imported `data.frame`.\n"
  },
  {
    "path": "tests/testthat/test-edit-data.R",
    "content": "\ntest_that(\"edit_data_ui works\", {\n  expect_is(edit_data_ui(\"ID\"), \"shiny.tag.list\")\n})\n\n\ntest_that(\"table_display works\", {\n  mydata <- iris\n  mydata <- as.data.table(mydata)\n\n  mydata[, .datamods_edit_update := as.character(seq_len(.N))]\n  mydata[, .datamods_edit_delete := as.character(seq_len(.N))]\n  mydata[, .datamods_id := seq_len(.N)]\n  mydata <- table_display(mydata, colnames = NULL)\n\n  expect_is(mydata, \"reactable\")\n  expect_is(mydata, \"htmlwidget\")\n  expect_length(mydata$x$tag$attribs$columns, 8)\n  expect_equal(length(mydata$x$tag$attribs$columns), 8)\n})\n\n\ntest_that(\"col_def_update works\", {\n  col_def_update <- col_def_update()\n  expect_is(col_def_update, \"colDef\")\n  expect_equal(col_def_update$name, \"Update\")\n  expect_named(col_def_update, c('name', 'sortable', 'filterable', 'html', 'width'))\n})\n\n\ntest_that(\"col_def_delete works\", {\n  col_def_delete <- col_def_delete()\n  expect_is(col_def_delete, \"colDef\")\n  expect_equal(col_def_delete$name, \"Delete\")\n  expect_named(col_def_delete, c('name', 'sortable', 'filterable', 'html', 'width'))\n})\n\n\ntest_that(\"btn_update works\", {\n  expect_is(btn_update(\"input\"), \"function\")\n  expect_is(btn_update(\"input\")(1), \"html\")\n  expect_is(btn_update(\"input\")(1), \"character\")\n})\n\n\ntest_that(\"btn_delete works\", {\n  expect_is(btn_delete(\"input\"), \"function\")\n  expect_is(btn_delete(\"input\")(1), \"html\")\n  expect_is(btn_delete(\"input\")(1), \"character\")\n})\n\n\ntest_that(\"confirmation_window works\", {\n  expect_is(confirmation_window(inputId = \"input\", title = \"titre\"), \"shiny.tag\")\n})\n\n\n\n\n"
  },
  {
    "path": "tests/testthat/test-filter-data.R",
    "content": "\ntest_that(\"filter_data_ui works\", {\n  expect_is(filter_data_ui(\"ID\"), \"shiny.tag.list\")\n})\n\n\ntest_that(\"create_filters works\", {\n\n  filters <- create_filters(iris, session = list(ns = identity))\n\n  expect_length(filters, 3)\n  expect_named(filters, c(\"ui\", \"filters_id\", \"filters_na_id\"))\n\n  expect_is(filters$ui, \"shiny.tag\")\n\n  expect_length(filters$filters_id, ncol(iris))\n  expect_equal(length(filters$ui$children[[1]]), length(filters$filters_id))\n  expect_equal(length(filters$filters_id), length(filters$filters_na_id))\n})\n\n\ntest_that(\"create_filters with options works\", {\n\n  filters <- create_filters(iris, vars = names(iris)[1:3], widget_num = \"range\", session = list(ns = identity))\n\n  expect_length(filters, 3)\n  expect_named(filters, c(\"ui\", \"filters_id\", \"filters_na_id\"))\n\n  expect_is(filters$ui, \"shiny.tag\")\n\n  expect_length(filters$filters_id, 3)\n  expect_equal(length(filters$ui$children[[1]]), length(filters$filters_id))\n  expect_equal(length(filters$filters_id), length(filters$filters_na_id))\n})\n\n\ntest_that(\"create_filters with dates and ids works\", {\n\n  mydata <- data.frame(\n    date = seq(as.Date(\"2021-01-01\"), by = \"1 month\", length.out = 12),\n    name = month.name,\n    num = rep(c(1, 2), each = 6)\n  )\n\n  filters <- create_filters(mydata, session = list(ns = identity))\n\n  expect_length(filters, 3)\n  expect_named(filters, c(\"ui\", \"filters_id\", \"filters_na_id\"))\n\n  expect_is(filters$ui, \"shiny.tag\")\n\n  expect_length(filters$filters_id, 2)\n  expect_equal(length(filters$ui$children[[1]]), length(filters$filters_id))\n  expect_equal(length(filters$filters_id), length(filters$filters_na_id))\n})\n\n\ntest_that(\"create_filters with dates and ids works (bis)\", {\n\n  mydata <- data.frame(\n    date = seq(as.Date(\"2021-01-01\"), by = \"1 month\", length.out = 12),\n    name = month.name,\n    num = rep(c(1, 2), each = 6)\n  )\n\n  filters <- create_filters(mydata, widget_date = \"range\", session = list(ns = identity))\n\n  expect_length(filters, 3)\n  expect_named(filters, c(\"ui\", \"filters_id\", \"filters_na_id\"))\n\n  expect_is(filters$ui, \"shiny.tag\")\n\n  expect_length(filters$filters_id, 2)\n  expect_equal(length(filters$ui$children[[1]]), length(filters$filters_id))\n  expect_equal(length(filters$filters_id), length(filters$filters_na_id))\n})\n\n\ntest_that(\"make_expr_filter works\", {\n\n  filter_inputs <- lapply(\n    X = iris,\n    FUN = function(x) {\n      sort(sample(unique(x), 2))\n    }\n  )\n  filter_nas <- lapply(\n    X = iris,\n    FUN = function(x) {\n      sample(c(TRUE, FALSE), 2)\n    }\n  )\n\n  filters <- make_expr_filter(\n    filters = filter_inputs,\n    filters_na = filter_nas,\n    data = iris,\n    data_name = \"iris\"\n  )\n\n  expect_length(filters, 2)\n  expect_named(filters, c(\"expr_dplyr\", \"expr\"))\n\n  expect_is(filters$expr_dplyr, \"call\")\n  expect_is(filters$expr, \"call\")\n})\n\n\ntest_that(\"make_expr_filter with dates works\", {\n\n  mydata <- data.frame(\n    date = seq(as.Date(\"2021-01-01\"), by = \"1 month\", length.out = 12),\n    name = month.name,\n    num = rep(c(1, 2), each = 6)\n  )\n\n  filter_inputs <- lapply(\n    X = mydata,\n    FUN = function(x) {\n      sort(sample(unique(x), 2))\n    }\n  )\n  filter_nas <- lapply(\n    X = mydata,\n    FUN = function(x) {\n      sample(c(TRUE, FALSE), 2)\n    }\n  )\n\n  filters <- make_expr_filter(\n    filters = filter_inputs,\n    filters_na = filter_nas,\n    data = mydata,\n    data_name = \"mydata\"\n  )\n\n  expect_length(filters, 2)\n  expect_named(filters, c(\"expr_dplyr\", \"expr\"))\n\n  expect_is(filters$expr_dplyr, \"call\")\n  expect_is(filters$expr, \"call\")\n})\n"
  },
  {
    "path": "tests/testthat/test-i18n.R",
    "content": "test_that(\"i18n works if option not set\", {\n  options(\"datamods.i18n\" = NULL)\n  label <- \"something\"\n  expect_identical(i18n(label), label)\n})\n\n\ntest_that(\"i18n works with translation argument\", {\n  options(\"datamods.i18n\" = NULL)\n  label <- \"something\"\n  translation <- \"quelque chose\"\n  l <- list(translation)\n  names(l) <- label\n  expect_identical(i18n(label, l), translation)\n})\n\n\ntest_that(\"i18n works with option set\", {\n  options(\"datamods.i18n\" = NULL)\n  label <- \"something\"\n  translation <- \"quelque chose\"\n  l <- list(translation)\n  names(l) <- label\n  options(\"i18n\" = l)\n  expect_identical(i18n(label, i18n_translations(NULL)), translation)\n})\n\n\ntest_that(\"i18n works with list\", {\n  label <- \"something\"\n  translation <- \"quelque chose\"\n  l <- list(translation)\n  names(l) <- label\n  options(\"datamods.i18n\" = l)\n  expect_identical(i18n_test(label), translation)\n  expect_warning(i18n_test(\"label\"))\n})\n\n\ntest_that(\"i18n works with data.frame\", {\n  label <- \"something\"\n  translation <- \"quelque chose\"\n  options(\"datamods.i18n\" = data.frame(\n    label = label,\n    translation = translation,\n    stringsAsFactors = FALSE\n  ))\n  expect_identical(i18n_test(label), translation)\n  expect_warning(i18n_test(\"label\"))\n})\n\n\ntest_that(\"i18n works with file\", {\n  options(\"datamods.i18n\" = system.file(\n    \"i18n\", \"fr.csv\", package = \"datamods\"\n  ))\n  expect_identical(i18n_test(\"Help\"), \"Aide\")\n})\n\n\ntest_that(\"i18n works with supported language\", {\n  options(\"datamods.i18n\" = \"fr\")\n  expect_identical(i18n_test(\"Help\"), \"Aide\")\n\n  options(\"datamods.i18n\" = \"mk\")\n  expect_type(i18n_test(\"Help\"), \"character\")\n\n  options(\"datamods.i18n\" = \"pt\")\n  expect_type(i18n_test(\"Help\"), \"character\")\n\n  options(\"datamods.i18n\" = \"al\")\n  expect_type(i18n_test(\"Help\"), \"character\")\n})\n\n\ntest_that(\"i18n dont work if no list, no data.frame, no file\", {\n  options(\"datamods.i18n\" = Sys.Date())\n  on.exit(options(\"datamods.i18n\" = NULL))\n  label <- \"something\"\n  expect_error(i18n_test(label))\n})\n"
  },
  {
    "path": "tests/testthat/test-import-copypaste.R",
    "content": "test_that(\"import_copypaste_ui works\", {\n  expect_is(import_copypaste_ui(\"ID\"), \"shiny.tag\")\n})\n\ntest_that(\"import_copypaste_server works\", {\n  shiny::testServer(import_copypaste_server, {\n    session$setInputs(data_pasted = 0) #to bypass ignoreInit = TRUE\n    session$setInputs(\n      data_pasted =\n      \"x y z\n      1 2 3\",\n      confirm = 0\n    )\n    expect_is(imported_rv$data, \"data.frame\")\n    expect_is(session$getReturned()$data(), \"data.frame\")\n  })\n})\n"
  },
  {
    "path": "tests/testthat/test-import-file.R",
    "content": "test_that(\"import_file_ui works\", {\n  expect_is(import_file_ui(\"ID\"), \"shiny.tag\")\n})\n\ntest_that(\"import_file_server works\", {\n  shiny::testServer(import_file_server, {\n    session$setInputs(sheet = 0) #to bypass ignoreInit = TRUE\n    session$setInputs(\n      file = data.frame(\n        datapath = system.file(\"extdata\", \"mtcars.csv\", package = \"datamods\"),\n        stringsAsFactors = FALSE\n      ),\n      sheet = 0,\n      skip_rows = 0,\n      confirm = 0,\n      dec = \".\",\n      encoding = \"UTF-8\",\n      na_label = \",NA\"\n    )\n    expect_is(imported_rv$data, \"data.frame\")\n    expect_is(session$getReturned()$data(), \"data.frame\")\n  })\n})\n\n"
  },
  {
    "path": "tests/testthat/test-import-globalenv.R",
    "content": "test_that(\"import_globalenv_ui works\", {\n  expect_is(import_globalenv_ui(\"ID\"), \"shiny.tag\")\n})\n\ntest_that(\"import_globalenv_server works\", {\n  data(mtcars)\n  shiny::testServer(import_globalenv_server, {\n    session$setInputs(data = 0) #to bypass ignoreInit = TRUE\n    session$setInputs(\n      data = \"mtcars\",\n      confirm = 0\n    )\n    expect_equal(imported_rv$name, input$data)\n    expect_equal(session$getReturned()$name(), input$data)\n    expect_is(imported_rv$data, \"data.frame\")\n    expect_is(session$getReturned()$data(), \"data.frame\")\n\n    session$setInputs(env = \"datasets\")\n    session$setInputs(data = \"faithful\", confirm = 1)\n    expect_is(session$getReturned()$data(), \"data.frame\")\n    expect_equivalent(session$getReturned()$data(), faithful)\n  })\n})\n\n\ntest_that(\"get_dimensions works\", {\n  expect_null(get_dimensions(NULL))\n\n  mydata <- mtcars\n  mydata2 <- mtcars\n  expect_is(get_dimensions(\"mydata\"), \"character\")\n  expect_length(get_dimensions(c(\"mydata\", \"mydata2\")), 2)\n\n  mylist <- list(a = 1)\n  expect_identical(unname(get_dimensions(\"mylist\")), \"Not a data.frame\")\n})\n\n\ntest_that(\"list_pkg_data works\", {\n  expect_null(list_pkg_data(\"not.a.package\"))\n  expect_is(list_pkg_data(\"datasets\"), \"character\")\n})\n\n"
  },
  {
    "path": "tests/testthat/test-import-googlesheets.R",
    "content": "test_that(\"import_googlesheets_ui works\", {\n  expect_is(import_googlesheets_ui(\"ID\"), \"shiny.tag\")\n})\n\ntest_that(\"import_googlesheets_server works\", {\n  testthat::skip_on_cran()\n  testthat::skip_if_offline()\n  shiny::testServer(import_googlesheets_server, {\n    session$setInputs(link = 0) #to bypass ignoreInit = TRUE\n    session$setInputs(\n      link = \"https://docs.google.com/spreadsheets/d/1U6Cf_qEOhiR9AZqTqS3mbMF3zt2db48ZP5v3rkrAEJY/edit?usp=sharing\",\n      confirm = 0\n    )\n    expect_is(imported_rv$data, \"data.frame\")\n    expect_is(session$getReturned()$data(), \"data.frame\")\n  })\n})\n\n"
  },
  {
    "path": "tests/testthat/test-import-modal.R",
    "content": "test_that(\"import_ui works\", {\n  expect_is(import_ui(\"ID\"), \"shiny.tag\")\n})\n\ntest_that(\"import_server works\", {\n  shiny::testServer(import_server, args = list(return_class = \"data.table\"), {\n    data(mtcars)\n    session$env$data_rv$data = mtcars\n    session$env$data_rv$name = \"mtcars\"\n\n    session$setInputs(confirm = 1)\n\n    expect_is(session$getReturned()$data(), \"data.table\")\n    expect_equal(session$getReturned()$name(), \"mtcars\")\n  })\n})\n"
  },
  {
    "path": "tests/testthat/test-import-url.R",
    "content": "test_that(\"import_url_ui works\", {\n  expect_is(import_url_ui(\"ID\"), \"shiny.tag\")\n})\n\ntest_that(\"import_url_server works with json\", {\n  testthat::skip_on_cran()\n  testthat::skip_if_offline()\n  shiny::testServer(import_url_server, {\n    session$setInputs(link = 0) #to bypass ignoreInit = TRUE\n    session$setInputs(\n      link = \"https://raw.githubusercontent.com/dreamRs/datamods/master/inst/extdata/mtcars.json\",\n      confirm = 0\n    )\n    expect_is(imported_rv$data, \"data.frame\")\n    expect_is(session$getReturned()$data(), \"data.frame\")\n  })\n})\n\ntest_that(\"import_url_server works with csv\", {\n  testthat::skip_on_cran()\n  testthat::skip_if_offline()\n  shiny::testServer(import_url_server, {\n    session$setInputs(link = 0) #to bypass ignoreInit = TRUE\n    session$setInputs(\n      link = \"https://raw.githubusercontent.com/dreamRs/datamods/master/inst/extdata/mtcars.csv\",\n      confirm = 0\n    )\n    expect_is(imported_rv$data, \"data.frame\")\n    expect_is(session$getReturned()$data(), \"data.frame\")\n  })\n})\n\ntest_that(\"import_url_server works with shortened URL\", {\n  testthat::skip_on_cran()\n  testthat::skip_if_offline()\n  shiny::testServer(import_url_server, {\n    session$setInputs(link = 0) #to bypass ignoreInit = TRUE\n    session$setInputs(\n      link = \"https://tinyurl.com/datamodsjson\",\n      confirm = 0\n    )\n    expect_is(imported_rv$data, \"data.frame\")\n    expect_is(session$getReturned()$data(), \"data.frame\")\n  })\n})\n\n"
  },
  {
    "path": "tests/testthat/test-onLoad.R",
    "content": "test_that(\"onLoad works\", {\n  .onLoad()\n  x <- shiny::resourcePaths()\n  expect_true(\"datamods\" %in% names(x))\n})\n"
  },
  {
    "path": "tests/testthat/test-update-variables.R",
    "content": "test_that(\"update_variables_ui works\", {\n  expect_is(update_variables_ui(\"ID\"), \"shiny.tag\")\n})\n\n\n# test_that(\"update_variables_server works\", {\n#   data(mtcars)\n#   shiny::testServer(update_variables_server, args = list(data = mtcars), {\n#     tok <- token$x\n#     selection <- as.list(rep(TRUE, ncol(mtcars)))\n#     names(selection) <- paste(\"selection\", tok, pad0(seq_along(mtcars)), sep = \"-\")\n#\n#     name <- as.list(names(mtcars))\n#     names(name) <- paste(\"name\", tok, pad0(seq_along(mtcars)), sep = \"-\")\n#\n#     class_toset <- as.list(rep(\"numeric\", ncol(mtcars)))\n#     names(class_toset) <- paste(\"class_to_set\", tok, pad0(seq_along(mtcars)), sep = \"-\")\n#\n#     do.call(session$setInputs, selection)\n#     do.call(session$setInputs, name)\n#     do.call(session$setInputs, class_toset)\n#\n#     session$setInputs(validate = 1)\n#\n#     # print(session$getReturned()())\n#     expect_is(session$getReturned()(), \"data.frame\")\n#     expect_equal(session$getReturned()(), mtcars)\n#   })\n# })\n\n\n\ntest_that(\"get_classes works\", {\n  expect_is(get_classes(mtcars), \"character\")\n  expect_length(get_classes(mtcars), ncol(mtcars))\n})\n\ntest_that(\"get_classes works\", {\n  expect_is(get_n_unique(mtcars), \"integer\")\n  expect_length(get_n_unique(mtcars), ncol(mtcars))\n})\n\ntest_that(\"pad0 works\", {\n  expect_is(pad0(c(1, 15, 150, NA)), \"character\")\n  expect_length(pad0(c(1, 15, 150, NA)), 4)\n})\n\ntest_that(\"summary_vars works\", {\n  expect_is(summary_vars(mtcars), \"data.frame\")\n  expect_identical(nrow(summary_vars(mtcars)), ncol(mtcars))\n})\n\n\n\ntest_that(\"update_variables_datagrid works\", {\n  variables <- summary_vars(iris)\n  dt <- update_variables_datagrid(variables)\n  expect_is(dt, \"htmlwidget\")\n})\n\n\n\ntest_that(\"convert_to works\", {\n  dat <- data.frame(\n    v1 = month.name,\n    v2 = month.abb,\n    v3 = 1:12,\n    v4 = as.numeric(Sys.Date() + 0:11),\n    v5 = as.character(Sys.Date() + 0:11),\n    v6 = as.factor(c(\"a\", \"a\", \"b\", \"a\", \"b\", \"a\", \"a\", \"b\", \"a\", \"b\", \"b\", \"a\")),\n    v7 = as.character(11:22),\n    stringsAsFactors = FALSE\n  )\n\n  expect_is(\n    convert_to(dat, \"v3\", \"character\")$v3,\n    \"character\"\n  )\n  expect_is(\n    convert_to(dat, \"v6\", \"character\")$v6,\n    \"character\"\n  )\n  expect_is(\n    convert_to(dat, \"v7\", \"numeric\")$v7,\n    \"numeric\"\n  )\n  expect_is(\n    convert_to(dat, \"v4\", \"date\", origin = \"1970-01-01\")$v4,\n    \"Date\"\n  )\n  expect_is(\n    convert_to(dat, \"v5\", \"date\")$v5,\n    \"Date\"\n  )\n})\n\n\n\ntest_that(\"get_vars_to_convert works\", {\n  # 2 variables to convert\n  new_classes <- list(\n    \"Sepal.Length\" = \"numeric\",\n    \"Sepal.Width\" = \"numeric\",\n    \"Petal.Length\" = \"character\",\n    \"Petal.Width\" = \"numeric\",\n    \"Species\" = \"character\"\n  )\n  res <- get_vars_to_convert(summary_vars(iris), new_classes)\n  expect_is(res, \"data.frame\")\n  expect_identical(nrow(res), 2L)\n\n  # No changes\n  new_classes <- list(\n    \"Sepal.Length\" = \"numeric\",\n    \"Sepal.Width\" = \"numeric\",\n    \"Petal.Length\" = \"numeric\",\n    \"Petal.Width\" = \"numeric\",\n    \"Species\" = \"factor\"\n  )\n  res <- get_vars_to_convert(summary_vars(iris), new_classes)\n  expect_is(res, \"data.frame\")\n  expect_identical(nrow(res), 0L)\n\n\n  new_classes <- list(\n    \"mpg\" = \"character\",\n    \"cyl\" = \"numeric\",\n    \"disp\" = \"character\",\n    \"hp\" = \"numeric\",\n    \"drat\" = \"character\",\n    \"wt\" = \"character\",\n    \"qsec\" = \"numeric\",\n    \"vs\" = \"character\",\n    \"am\" = \"numeric\",\n    \"gear\" = \"character\",\n    \"carb\" = \"integer\"\n  )\n  res <- get_vars_to_convert(summary_vars(mtcars), new_classes)\n  expect_is(res, \"data.frame\")\n  expect_identical(nrow(res), 7L)\n})\n\n\n"
  },
  {
    "path": "tests/testthat/test-validation.R",
    "content": "test_that(\"validation_ui works\", {\n  expect_is(validation_ui(\"ID\"), \"shiny.tag.list\")\n  expect_is(validation_ui(\"ID\", display = \"inline\"), \"shiny.tag.list\")\n})\n\n# test_that(\"validation_server works\", {\n#   rv <- shiny::reactiveVal(cars)\n#   shiny::testServer(\n#     validation_server,\n#     args = list(\n#       data = rv,\n#       n_row = ~ . > 20,\n#       n_col = ~ . >= 3,\n#       rules = validate::validator(\n#         speed >= 0\n#         , dist >= 0\n#         , speed/dist <= 1.5\n#       )\n#     ), {\n#       rv(cars)\n#       expect_is(valid_ui$x, \"shiny.tag\")\n#       expect_is(valid_rv$status, \"character\")\n#     }\n#   )\n# })\n"
  },
  {
    "path": "tests/testthat.R",
    "content": "library(testthat)\nlibrary(datamods)\n\ntest_check(\"datamods\")\n"
  },
  {
    "path": "vignettes/.gitignore",
    "content": "*.html\n*.R\n"
  },
  {
    "path": "vignettes/datamods.Rmd",
    "content": "---\ntitle: \"Getting started with datamods\"\noutput: rmarkdown::html_vignette\nvignette: >\n  %\\VignetteIndexEntry{Getting started with datamods}\n  %\\VignetteEngine{knitr::rmarkdown}\n  %\\VignetteEncoding{UTF-8}\n---\n\n```{r, include = FALSE}\nknitr::opts_chunk$set(\n  collapse = TRUE,\n  comment = \"#>\",\n  eval = FALSE\n)\n```\n\n```{r setup}\nlibrary(datamods)\n```\n\n\nThe {datamods} package contains modules to work with data in Shiny application, currently the following modules are implemented :\n\n* Import modules : import data from various sources\n* Update table structure: select columns to keep, rename variable and convert from a class to anoter (e.g. numeric to character)\n* Filter data : interactively filter a `data.frame`\n* Validate : check that data respect some expectations (with [package {validate}](https://cran.r-project.org/package=validate))\n* Sample data: interactively sample a `data.frame`.\n\n\n## Import\n\n### From environment\n\nImports data from the user's global environment or a package environment to retrieve included in it. \nIt searches for data sets in the global environment and lets the user choose the data to use.\n\n```r\n# UI\nimport_globalenv_ui(\"myid\")\n\n# Server\nimported <- import_globalenv_server(\"myid\")\n```\n\n<img src=\"figures/datamods-env.png\" style=\"width:100%\"></img>\n\n\n### From file\n\nImports data from an external file. The file can be of any format, csv, xlsx, tsv etc.. Import is performed by package [rio](https://github.com/gesistsa/rio).\nIn case of Excel files, it gives an option to choose the sheet. \n\n```r\n# UI\nimport_file_ui(\"myid\")\n\n# Server\nimported <- import_file_server(\"myid\")\n```\n\n<img src=\"figures/datamods-file.png\" style=\"width:100%\"></img>\n\n\n### From clipboard\n\nImports data via copy/paste. Simply copy and paste data from any source.\n\n```r\n# UI\nimport_copypaste_ui(\"myid\")\n\n# Server\nimported <- import_copypaste_server(\"myid\")\n```\n\n<img src=\"figures/datamods-paste.png\" style=\"width:100%\"></img>\n\n\n### From Googlesheet\n\nImports data from a Googlesheet. Use the shareable link to read data.\n\n```r\n# UI\nimport_googlesheets_ui(\"myid\")\n\n# Server\nimported <- import_googlesheets_server(\"myid\")\n```\n\n<img src=\"figures/datamods-googlesheet.png\" style=\"width:100%\"></img>\n\n### From URL\n\nImports data from a URL. Only flat data in any format supported by [package rio](https://CRAN.R-project.org/package=rio/vignettes/rio.html#Supported_file_formats).\n\n```r\n# UI\nimport_url_ui(\"myid\")\n\n# Server\nimported <- import_url_server(\"myid\")\n```\n\n\n### Usage\n\nAll modules are used in the same way in a Shiny application, here is an example:\n\n```r\nlibrary(shiny)\nlibrary(datamods)\n\nui <- fluidPage(\n  tags$h3(\"Import data with copy & paste\"),\n  fluidRow(\n    column(\n      width = 4,\n      import_copypaste_ui(\"myid\")\n    ),\n    column(\n      width = 8,\n      tags$b(\"Imported data:\"),\n      verbatimTextOutput(outputId = \"status\"),\n      verbatimTextOutput(outputId = \"data\")\n    )\n  )\n)\n\nserver <- function(input, output, session) {\n\n  imported <- import_copypaste_server(\"myid\")\n\n  output$status <- renderPrint({\n    imported$status()\n  })\n  output$data <- renderPrint({\n    imported$data()\n  })\n\n}\n\nshinyApp(ui, server)  \n```\n\nAll modules have the same return value server-side, a `list` with three slots:\n\n* **status**: a `reactive` function returning the status: `NULL`, `error` or `success`.\n* **name**: a `reactive` function returning the name of the imported data as `character`.\n* **data**: a `reactive` function returning the imported `data.frame`.\n\n\n### Modal Window\n\nAll modules can be launched at once in a modal window:\n\n<img src=\"figures/datamods-modal-2.png\" style=\"width:100%\"></img>\n\n\nLaunch the modal server-side with:\n\n```r\nobserveEvent(input$launch_modal, {\n  import_modal(\n    id = \"myid\",\n    title = \"Import data to be used in application\"\n  )\n})\n```\n\nSee `?import_modal` for a complete example.\n\n\n\n## Update Modules\n\nThis module allow to dynamically select, rename and convert variables of a dataset.\n\n<img src=\"figures/datamods-update-2.png\" style=\"width:100%\"></img>\n\n\nSome options for converting to date and numeric are available in a dropdown menu.\n\nReturn value of the module is a `reactive` function with the update data.\n\n\n\n## Validate\n\nWhen importing data into an application it can be useful to check that data respect some expectations: number of rows/columns, existence of a variable, ... This module allow to validate rules defined with package [validate](https://github.com/data-cleaning/validate).\n\n```r\n# UI\nvalidation_ui(\"validation\", display = \"inline\")\n\n# Server\nresults <- validation_server(\n  id = \"validation\",\n  data = dataset,\n  n_row = ~ . > 20, # more than 20 rows\n  n_col = ~ . >= 3, # at least 3 columns\n  rules = myrules\n)\n\n# Rules are defined as follow:\nmyrules <- validator(\n  is.character(Manufacturer) | is.factor(Manufacturer),\n  is.numeric(Price),\n  Price > 12, # we should use 0 for testing positivity, but that's for the example\n  !is.na(Luggage.room),\n  in_range(Cylinders, min = 4, max = 8),\n  Man.trans.avail %in% c(\"Yes\", \"No\")\n)\n# Add some labels\nlabel(myrules) <- c(\n  \"Variable Manufacturer must be character\",\n  \"Variable Price must be numeric\",\n  \"Variable Price must be strictly positive\",\n  \"Luggage.room must not contain any missing values\",\n  \"Cylinders must be between 4 and 8\",\n  \"Man.trans.avail must be 'Yes' or 'No'\"\n)\n# you can also add a description()\n```\n\n<img src=\"figures/datamods-validation-2.png\" style=\"width:100%\"></img>\n\n\nValidation results can be displayed in a dropdown menu (above left) or inline where the module is called.\n\nThe return value server-side is a list with the following items:\n\n* **status**: a reactive function returning the best status available between \"OK\", \"Failed\" or \"Error\".\n* **details**: a reactive function returning a list with validation details.\n\n\n## Filter\n\nInteractively filter a `data.frame` and generate code to reproduce filters applied:\n\n```r\n# UI\nfilter_data_ui(\"filtering\", max_height = \"500px\")\n\n# Server\nres_filter <- filter_data_server(\n  id = \"filtering\",\n  data = reactive(mtcars),\n  name = reactive(\"mtcars\"),\n  vars = reactive(names(mtcars)),\n  widget_num = \"slider\",\n  widget_date = \"slider\",\n  label_na = \"Missing\"\n)\n```\n\nYou can select variables for which to create a filter and choose widgets used to create the UI filter.\n\n<img src=\"figures/datamods-filter-2.png\" style=\"width:100%\"></img>\n\nThe return value server-side is a list with the following items:\n\n* **filtered**: a `reactive` function returning the data filtered.\n* **code**: a `reactive` function returning the dplyr pipeline to filter data.\n* **expr**: a `reactive` function returning an expression to filter data.\n\n\n\n## Sample\n\nInteractively sample a `data.frame` to keep only part of the data, depending on the number or proportion of rows to keep.\n\n```r\n# UI\nsample_ui(\"myID\")\n\n# Server\nresult_sample <- sample_server(\"myID\", reactive(iris))\n```\n\n<img src=\"figures/datamods-sample.png\" style=\"width:100%\"></img>\n\n\n\n## Edit\n\nInteractively edit a `data.frame`, this module also allow to :\n\n* **adding**, **deleting** and **modifying** rows\n* choosing **editable columns** and choosing **mandatory columns**\n* **exporting data** (csv and Excel)\n\n\n```r\n# UI\nedit_data_ui(id = \"id\")\n\n# Server\n  res_edited <- edit_data_server(\n    id = \"id\",\n    data_r = reactive(demo_edit),\n    add = TRUE,\n    update = TRUE,\n    delete = TRUE,\n    download_csv = TRUE,\n    download_excel = TRUE,\n    file_name_export = \"datas\",\n    var_edit = c(\"name\", \"job\", \"credit_card_provider\", \"credit_card_security_code\"),\n    var_mandatory = c(\"name\", \"job\")\n  )\n```\n\n<img src=\"figures/datamods-edit-data.png\" style=\"width:100%\"></img>\n\n\nThis module returns the edited table with the user modifications.\nSee ?demo_edit to see the data created for this data edit example.\n"
  },
  {
    "path": "vignettes/i18n.Rmd",
    "content": "---\ntitle: \"Internationalization\"\noutput: rmarkdown::html_vignette\nvignette: >\n  %\\VignetteIndexEntry{Internationalization}\n  %\\VignetteEngine{knitr::rmarkdown}\n  %\\VignetteEncoding{UTF-8}\n---\n\n```{r, include = FALSE}\nknitr::opts_chunk$set(\n  collapse = TRUE,\n  comment = \"#>\",\n  eval = FALSE\n)\n```\n\n```{r setup}\nlibrary(datamods)\n```\n\nWhen using {datamods} modules, a simple way to modify labels display is provided for using a different language or simply use other labels.\nThere are 4 different ways to use new labels:\n\n```r\n# Using a supported language\nset_i18n(\"fr\")\n\n# Using a named list\nset_i18n(list(\"Some label\" = \"Its translation\", ...))\n\n# Using a data.framewith 2 columns\nset_i18n(data.frame(label = c(...), translation = c(...)))\n\n# Using a CSV file\nset_i18n(\"path/to/file.csv\")\n```\n\n\n## Integrated languages\n\nThe following languages are integrated in {datamods} :\n\n* ![](figures/i18n/gb.svg){height=16, style=\"height:16px\"} english, the default.\n\n* ![](figures/i18n/fr.svg){height=16, style=\"height:16px\"} french, activate with:\n\n```{r}\nset_i18n(\"fr\")\n```\n\n* ![](figures/i18n/mk.svg){height=16, style=\"height:16px\"} macedonian, activate with:\n\n```{r}\nset_i18n(\"mk\")\n```\n\n* ![](figures/i18n/br.svg){height=16, style=\"height:16px\"} ![](figures/i18n/pt.svg){height=16, style=\"height:16px\"} brazilian portuguese, activate with:\n\n```{r}\nset_i18n(\"pt\")\n```\n\n* ![](figures/i18n/al.svg){height=16, style=\"height:16px\"} albanian, activate with:\n\n```{r}\nset_i18n(\"al\")\n```\n\n* ![](figures/i18n/cn.svg){height=16, style=\"height:16px\"} chinese, activate with:\n\n```{r}\nset_i18n(\"cn\")\n```\n\n* ![](figures/i18n/es.svg){height=16, style=\"height:16px\"} spanish, activate with:\n\n```{r}\nset_i18n(\"es\")\n```\n\n* ![](figures/i18n/de.svg){height=16, style=\"height:16px\"} german, activate with:\n\n```{r}\nset_i18n(\"de\")\n```\n\n* ![](figures/i18n/tr.svg){height=16, style=\"height:16px\"} turkish, activate with:\n\n```{r}\nset_i18n(\"tr\")\n```\n\n* ![](figures/i18n/kr.svg){height=16, style=\"height:16px\"} korean, activate with:\n\n```{r}\nset_i18n(\"kr\")\n```\n\n* ![](figures/i18n/pl.svg){height=16, style=\"height:16px\"} polish, activate with:\n\n```{r}\nset_i18n(\"pl\")\n```\n\n* ![](figures/i18n/ja.svg){height=16, style=\"height:16px\"} japanese, activate with:\n\n```{r}\nset_i18n(\"ja\")\n```\n\nIf you want another language to be supported, you can submit a Pull Request to add a CSV file like the one used for french (file is located in `inst/i18n` folder in the package, you can see it [here on GitHub](https://github.com/dreamRs/datamods/blob/master/inst/i18n/fr.csv)).\n\n\n## Using a list\n\nYou can change labels with a named `list`, where names correspond to the labels and values to the translation to use:\n\n```r\noptions(\"datamods.i18n\" = list(\n  \"Import a dataset from an environment\" = \"Importer un jeu de données depuis l'environnement global\",\n  \"Select a data.frame:\" = \"Sélectionner un data.frame :\",\n  ...\n))\n```\n\n\n## Using a data.frame\n\nYou can change labels with a `data.frame` with two columns `label` (the original label) and `translation` (the new label to display):\n\n```r\nset_i18n(data.frame(\n  label = c(\"Import a dataset from an environment\", \"Select a data.frame:\", ...),\n  translation = c(\"Importer un jeu de données depuis l'environnement global\", \"Sélectionner un data.frame :\", ...)\n))\n```\n\n\n## Using a file\n\nUse a CSV file with same structure than `data.frame` above:\n\n```r\nset_i18n(\"path/to/file.csv\")\n```\n\nAn example of file is shown below.\n\n\n## All labels\n\nHere's the file used for french translation with all labels used in the package:\n\n```{r, echo=FALSE, eval=TRUE, comment=\"\"}\ncat(readLines(system.file(\"i18n\", \"fr.csv\", package = \"datamods\"), encoding = \"UTF-8\"), sep = '\\n')\n```\n\n\n\n\n"
  }
]