├── .babelrc ├── .editorconfig ├── .gitattributes ├── .github └── workflows │ ├── build.yaml │ └── codeql-analysis.yml ├── .gitignore ├── .prettierrc ├── .yarnclean ├── .yarnrc ├── BUILD.md ├── CHANGELOG.md ├── LICENSE.txt ├── README.md ├── TODO.md ├── craco.config.js ├── dev-app-update.yml ├── docs ├── .gitignore ├── 404.html ├── Gemfile ├── Gemfile.lock ├── _config.yml ├── _layouts │ └── default.html ├── _sass │ ├── additions.scss │ ├── jekyll-theme-cayman.scss │ └── variables.scss ├── assets │ ├── css │ │ └── style.scss │ └── img │ │ ├── icon_linux.svg │ │ ├── icon_macos.svg │ │ ├── icon_windows.svg │ │ ├── raxmlgui_icon_256x256x32.png │ │ └── screenshots │ │ ├── basic.png │ │ ├── basic2.png │ │ ├── basic2_dark.png │ │ ├── basic_dark.png │ │ ├── console.png │ │ ├── model.png │ │ ├── parallel.png │ │ ├── partition_editor.png │ │ └── pipelines.png ├── favicon.ico ├── index.md └── jekyll-theme-cayman │ ├── .gitignore │ ├── Gemfile │ ├── LICENSE.txt │ ├── README.md │ ├── _layouts │ ├── default.html │ ├── page.html │ └── post.html │ └── jekyll-theme-cayman.gemspec ├── jsconfig.json ├── package.json ├── patches └── electron-webpack+2.8.2.patch ├── public ├── disk-image.icns ├── entitlements.mac.inherit.plist ├── favicon.ico ├── icon.icns ├── icon.ico ├── index.html └── manifest.json ├── scripts ├── download-binaries.js └── notarize.js ├── sentry-symbols.js ├── src ├── app │ ├── AlignmentCard.js │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── AstralTreeCard.js │ ├── CitationModal.js │ ├── Console.js │ ├── Input.js │ ├── Model.js │ ├── Output.js │ ├── PartitionEditor.js │ ├── PartitionFileCard.js │ ├── Raxml.js │ ├── TreeCard.js │ ├── bootstrap.js │ ├── components │ │ ├── CodeHighlight.js │ │ ├── ErrorBoundary.js │ │ ├── ErrorDialog.js │ │ ├── ModifiedDialog.js │ │ ├── OptionCheck.js │ │ ├── OptionSelect.js │ │ └── OptionTextField.js │ ├── index.js │ ├── jsconfig.json │ ├── store │ │ ├── Alignment.js │ │ ├── AppStore.js │ │ ├── AstralTree.js │ │ ├── Citation.js │ │ ├── Config.js │ │ ├── InputFile.js │ │ ├── Option.js │ │ ├── Partition.js │ │ ├── Run.js │ │ ├── RunList.js │ │ ├── StoreBase.js │ │ └── index.js │ └── theme │ │ └── index.js ├── common │ ├── errors.js │ ├── fastaParser.js │ ├── io.js │ ├── phylipParser.js │ ├── typecheckAlignment.js │ └── utils.js ├── constants │ └── ipc.js ├── electron.js ├── index.css ├── index.js ├── main │ ├── api.js │ ├── index.js │ ├── menu │ │ ├── index.js │ │ ├── subMenuAnalysis.js │ │ ├── subMenuDeveloper.js │ │ └── subMenuFile.js │ └── utils │ │ ├── saveScreenshot.js │ │ └── utils.js ├── registerServiceWorker.js └── settings │ ├── raxml.js │ └── raxmlng.js ├── static ├── example-files │ ├── astral │ │ └── 1KP-genetrees.tre │ ├── example_data_raxmlGUI.zip │ ├── fasta │ │ ├── aminoacid.txt │ │ ├── bin1.txt │ │ ├── bin2.txt │ │ ├── binary.txt │ │ ├── dna.txt │ │ ├── mixed_data.txt │ │ ├── multistate.txt │ │ ├── nucleotide.txt │ │ ├── partition_file.txt │ │ └── test.fa │ ├── nexus │ │ ├── aminoacid.nex │ │ └── nucleotide.nex │ ├── phylip │ │ ├── AA.txt │ │ ├── align_allvariant.txt │ │ ├── aminoacid.txt │ │ ├── binary.txt │ │ ├── dna_interleaved.txt │ │ ├── dna_interleaved_relaxed.txt │ │ ├── dna_sequential.txt │ │ ├── dna_sequential_relaxed.txt │ │ ├── mixed_data.txt │ │ ├── multistate.txt │ │ ├── nucleotide.txt │ │ └── partition_file.txt │ └── tree │ │ ├── backboneConstraint │ │ ├── backboneConstraint.txt │ │ └── dna.phy │ │ ├── fail │ │ ├── align.fas │ │ └── align.txt │ │ ├── multifurcatingConstraint │ │ ├── dna.phy │ │ └── multifurcatingConstraint.txt │ │ ├── success │ │ ├── align.fas │ │ └── align.txt │ │ └── test.tre ├── test-files │ ├── Primates.nex │ ├── fail_bad_base_at_site.txt │ ├── fail_bad_name.txt │ ├── fail_different_types.fas │ ├── fail_duplicate_taxon.fas │ ├── fail_duplicate_taxon.phy │ ├── fail_too_few_sequences_modeltest.txt │ ├── fail_too_few_sequences_raxml.txt │ ├── fail_unequal_sequence_length.fas │ ├── fail_unequal_sequence_length.phy │ ├── test_ambiguous_nucleotide.txt │ ├── test_interleaved.txt │ ├── test_invariant_sites.txt │ ├── test_lower_case_bases.txt │ ├── test_questionmark_nucleotide.txt │ ├── wrong_site_count.txt │ └── wrong_taxa_count.txt └── test-results │ └── ASTRAL_simulated_14taxon.gene.tre ├── webpack.config.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", { 5 | "targets": { 6 | "node": "current" 7 | } 8 | } 9 | ] 10 | ], 11 | "plugins": [ 12 | ["@babel/plugin-proposal-decorators", { "legacy": true }], 13 | ["@babel/plugin-proposal-class-properties", { "loose": true }] 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | end_of_line = lf 8 | indent_style = space 9 | indent_size = 2 10 | max_line_length = 120 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | 15 | [*.md] 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | *.png binary 3 | *.jpg binary 4 | *.jpeg binary 5 | *.ico binary 6 | *.icns binary 7 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: Build/release 2 | 3 | on: push 4 | 5 | jobs: 6 | release: 7 | runs-on: ${{ matrix.os }} 8 | 9 | strategy: 10 | matrix: 11 | os: [macos-latest, ubuntu-latest, windows-latest] 12 | 13 | steps: 14 | - name: Check out Git repository 15 | uses: actions/checkout@v2 16 | 17 | - name: Install Node.js, NPM and Yarn 18 | uses: actions/setup-node@v2 19 | with: 20 | node-version: 18 21 | 22 | - name: Install deps 23 | run: yarn 24 | 25 | - name: Download binaries 26 | run: npm run download-binaries 27 | 28 | - name: Build/release Electron app 29 | uses: samuelmeuli/action-electron-builder@v1 30 | with: 31 | # GitHub token, automatically provided to the action 32 | # (No need to define this secret in the repo settings) 33 | github_token: ${{ secrets.github_token }} 34 | mac_certs: ${{ secrets.mac_certs }} 35 | mac_certs_password: ${{ secrets.mac_certs_password }} 36 | 37 | # If the commit is tagged with a version (e.g. "v1.0.0"), 38 | # release the app after building 39 | release: ${{ startsWith(github.ref, 'refs/tags/v') }} 40 | env: 41 | # macOS notarization API key 42 | APPLEID: ${{ secrets.apple_id }} 43 | APPLEIDPASS: ${{ secrets.apple_id_pass }} 44 | APPLEIDTEAM: ${{ secrets.apple_id_team }} 45 | SENTRY_URL: ${{ secrets.sentry_url }} 46 | SENTRY_ORG: ${{ secrets.sentry_org }} 47 | SENTRY_PROJECT: ${{ secrets.sentry_project }} 48 | SENTRY_AUTH_TOKEN: ${{ secrets.sentry_auth_token }} 49 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '20 1 * * 4' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 37 | # Learn more: 38 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 39 | 40 | steps: 41 | - name: Checkout repository 42 | uses: actions/checkout@v2 43 | 44 | # Initializes the CodeQL tools for scanning. 45 | - name: Initialize CodeQL 46 | uses: github/codeql-action/init@v1 47 | with: 48 | languages: ${{ matrix.language }} 49 | # If you wish to specify custom queries, you can do so here or in a config file. 50 | # By default, queries listed here will override any specified in a config file. 51 | # Prefix the list here with "+" to use these queries and those in the config file. 52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 53 | 54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 55 | # If this step fails, then you should remove it and run the build manually (see below) 56 | - name: Autobuild 57 | uses: github/codeql-action/autobuild@v1 58 | 59 | # ℹ️ Command-line programs to run using the OS shell. 60 | # 📚 https://git.io/JvXDl 61 | 62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 63 | # and modify them (or add more) to build your code if your project 64 | # uses a compiled language 65 | 66 | #- run: | 67 | # make bootstrap 68 | # make release 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v1 72 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | /dist 12 | /release 13 | 14 | # misc 15 | .DS_Store 16 | 17 | # package manager 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | .yarn 22 | .yarnrc.yml 23 | 24 | # external dependencies 25 | /static/bin 26 | 27 | # output 28 | RAxML_* 29 | *.raxml.* 30 | *.reduced 31 | *_concat.* 32 | 33 | # environment 34 | sentry.properties 35 | .env 36 | .env.local 37 | .env.development.local 38 | .env.test.local 39 | .env.production.local 40 | .env 41 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "files": [".prettierrc", ".babelrc", ".eslintrc", ".stylelintrc"], 5 | "options": { 6 | "parser": "json" 7 | } 8 | } 9 | ], 10 | "singleQuote": true, 11 | "printWidth": 80, 12 | "tabWidth": 2, 13 | "useTabs": false, 14 | "semi": true, 15 | "bracketSpacing": true, 16 | "jsxBracketSameLine": false 17 | } 18 | -------------------------------------------------------------------------------- /.yarnclean: -------------------------------------------------------------------------------- 1 | # test directories 2 | __tests__ 3 | test 4 | tests 5 | powered-test 6 | 7 | # asset directories 8 | docs 9 | doc 10 | website 11 | images 12 | assets 13 | 14 | # examples 15 | example 16 | examples 17 | 18 | # code coverage directories 19 | coverage 20 | .nyc_output 21 | 22 | # build scripts 23 | Makefile 24 | Gulpfile.js 25 | Gruntfile.js 26 | 27 | # configs 28 | appveyor.yml 29 | circle.yml 30 | codeship-services.yml 31 | codeship-steps.yml 32 | wercker.yml 33 | .tern-project 34 | .gitattributes 35 | .editorconfig 36 | .*ignore 37 | .eslintrc 38 | .jshintrc 39 | .flowconfig 40 | .documentup.json 41 | .yarn-metadata.json 42 | .travis.yml 43 | 44 | # misc 45 | LICENSE 46 | LICENSE.txt 47 | CONTRIBUTING 48 | AUTHORS 49 | *.md 50 | *.jpg 51 | -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | network-timeout 120000 2 | -------------------------------------------------------------------------------- /BUILD.md: -------------------------------------------------------------------------------- 1 | # Building 2 | 3 | ## App 4 | ### Before pushing 5 | * Check if there are any warnings in the console. Those will be treated as errors in the CI environment. 6 | 7 | ### Recommended GitHub Releases Workflow¶ 8 | From [electron.build publish](https://www.electron.build/configuration/publish#recommended-github-releases-workflow) 9 | 10 | 1. Draft a new release. Set the “Tag version” to the value of version in your application package.json, and prefix it with v. “Release title” can be anything you want. 11 | 2. For example, if your application package.json version is 1.2.3, your draft’s “Tag version” would be v1.2.3. 12 | 3. Push some commits. Every CI build will update the artifacts attached to this draft. 13 | 4. Once you are done, publish the release. GitHub will tag the latest commit for you. 14 | The benefit of this workflow is that it allows you to always have the latest artifacts, and the release can be published once it is ready. 15 | 5. Update CHANGELOG and the download links in `docs/_layouts/default.html` to the new version. 16 | 5. Bump the version in package.json to use for the next draft and push to update the download links on the github page. 17 | 6. Uploading Debug Information 18 | To get symbolicated stack traces for native crashes, you have to upload debug symbols to Sentry. Sentry Wizard creates a convenient sentry-symbols.js script that will upload the Electron symbols for you. After installing the SDK and every time you upgrade the Electron version, run this script: 19 | 20 | ## Homepage 21 | 22 | Build steps for local development 23 | 24 | ## Prerequisites 25 | Install ruby 2.4 or higher 26 | 27 | Run 28 | ``` 29 | gem install jekyll bundler 30 | ``` 31 | 32 | In docs folder, run 33 | ``` 34 | bundle install 35 | ``` 36 | 37 | ## Local serve 38 | 39 | Run npm script `docs-serve` or in docs folder run 40 | ``` 41 | bundle exec jekyll serve 42 | ``` 43 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | Types of changes 8 | ### Added 9 | for new features. 10 | ### Changed 11 | for changes in existing functionality. 12 | ### Deprecated 13 | for soon-to-be removed features. 14 | ### Removed 15 | for now removed features. 16 | ### Fixed 17 | for any bug fixes. 18 | ### Security 19 | in case of vulnerabilities. 20 | 21 | ## [Unreleased] - YYYY-MM-DD 22 | ### Added 23 | - Added support for species tree from gene trees inference using ASTRAL 24 | 25 | ## [2.0.15] - 2025-04-14 26 | ### Changed 27 | - Performance and security updates 28 | ### Fixed 29 | - Error when dragging and dropping alignments in the app 30 | ## [2.0.14] - 2025-02-28 31 | ### Changed 32 | - Performance and security updates 33 | ### Removed 34 | - Dropping macOS 10.13 / 10.14 support 35 | ## [2.0.13] - 2024-09-29 36 | ### Changed 37 | - Performance and security updates 38 | ### Removed 39 | - Dropping Windows 7/8/8.1 Support 40 | ## [2.0.12] - 2024-09-29 41 | ### Changed 42 | - Performance and security updates 43 | ## [2.0.11] - 2024-09-28 44 | ### Changed 45 | - Updated to include the latest binaries for raxml-ng on Mac and Linux (1.2.2). 46 | ## [2.0.10] - 2022-09-13 47 | ### Changed 48 | - Performance and security updates 49 | ## [2.0.9] - 2022-06-30 50 | ### Added 51 | - Added substantially more logging in case an error occurrs 52 | ### Changed 53 | - Some maintenance and smaller UI updates 54 | ### Removed 55 | - Removed ModelTest from Windows 7 and lower 56 | ### Fixed 57 | - Fixed problems using RAxML and ModelTest with Mac M1 laptops 58 | ## [2.0.8] - 2022-05-09 59 | ### Changed 60 | - Updated example files 61 | ### Fixed 62 | - Left aligned Run buttom to always be visible 63 | - Made substitution model options available also on selecting GTRCAT for raxml 8.x 64 | - Added GAMMA to non-GTR model labels for raxml 8.x 65 | ## [2.0.7] - 2022-02-22 66 | ### Changed 67 | - Updated to include the latest binaries for raxml-ng on Mac and Linux (1.1.0). 68 | - Allow copy RAxML command 69 | ### Fixed 70 | - Fixed Linux issue running raxml-ng binaries 71 | 72 | ## [2.0.6] - 2021-10-05 73 | ### Changed 74 | - Updated to include the latest binaries for raxml-ng on Mac and Linux (1.0.3). 75 | - Updated to include the latest binaries for RAxML on Windows 8 and 10 (8.2.12). 76 | - A bit of restyling. 77 | ### Fixed 78 | - Fixed a bug that only one error could be reported. 79 | - Fixed a bug in outgroup selection. 80 | 81 | ## [2.0.5] - 2021-05-09 82 | ### Added 83 | - Using RAxML 8 you can now select these substitution models for nucleotide data as well: JC69, K80, HKY85. 84 | - ModelTest will also recognize these models if they are the best fit. 85 | ### Fixed 86 | - Fixed an error when restarting the app after an update. 87 | 88 | ## [2.0.4] - 2021-04-22 89 | ### Fixed 90 | - Fixed a crash with ModelTest-NG on Windows. 91 | 92 | ## [2.0.3] - 2021-04-14 93 | ### Added 94 | - Modeltest-NG is now also available on Windows (Tested on Windows 10 only). 95 | ### Fixed 96 | - Fixed some smaller styling issues. 97 | 98 | ## [2.0.2] - 2021-03-29 99 | ### Added 100 | - Display more detailed information when an input alignment has been modified. 101 | - Allow completely unknown binary sequences. 102 | ### Fixed 103 | - Small bugfix: Remove "null" showing up in SnackBar text 104 | 105 | ## [2.0.1] - 2021-03-04 106 | ### Added 107 | - Some common errors in alignments will be automatically fixed when loading an alignment. This includes, replacing illegal characters with underscores in taxon names, disambiguating duplicated taxon names, shortening taxon names that are too long. 108 | ### Changed 109 | - Updated to include the latest binaries for raxml-ng on Mac and Linux (1.0.1). 110 | ### Fixed 111 | - Now correctly recognizes ? and N in nucleotide sequences. 112 | - Fixed a small bug that showed output files that are not a result of the actual analysis. 113 | - Added the correct citation for the release paper. 114 | - Fixed a bug where selecting the output dir would lead to the change in all tabs. 115 | - Fixed a bug where adding an alignment would add it in all tabs. 116 | - Fixed a crash when running ModelTest-NG on binary or multistate alignments. 117 | - Fixed a crash when the input alignment did not exist when starting a run. 118 | - Fixed a bug that deleted last parts of a taxon names with whitespaces. 119 | 120 | ## [2.0.0] - 2017-06-20 121 | 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RaxmlGUI2 2 | 3 | A desktop GUI for RAxML. 4 | 5 | ## Development 6 | 7 | This is a an [Electron](https://electronjs.org/) App that was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 8 | 9 | ```yarn start``` will start the Electron app and the React app at the same time. 10 | ```yarn build``` will build the React app and package it along the Electron app. 11 | 12 | 13 | ## Input formats 14 | RaxmlGUI supports both FASTA and PHYLIP format. 15 | 16 | The strict phylip format reserves the first ten characters before each sequence for the name. 17 | The relaxed format allows longer name but requires no space within the name to know where it ends. 18 | 19 | ### Examples 20 | 21 | #### Phylip interleaved strict 22 | ``` 23 | 5 42 24 | Turkey AAGCTNGGGC ATTTCAGGGT 25 | Salmo gairAAGCCTTGGC AGTGCAGGGT 26 | H. SapiensACCGGTTGGC CGTTCAGGGT 27 | Chimp AAACCCTTGC CGTTACGCTT 28 | Gorilla AAACCCTTGC CGGTACGCTT 29 | 30 | GAGCCCGGGC AATACAGGGT AT 31 | GAGCCGTGGC CGGGCACGGT AT 32 | ACAGGTTGGC CGTTCAGGGT AA 33 | AAACCGAGGC CGGGACACTC AT 34 | AAACCATTGC CGGTACGCTT AA 35 | ``` 36 | 37 | #### Phylip interleaved relaxed 38 | ``` 39 | 5 42 40 | Turkey AAGCTNGGGC ATTTCAGGGT 41 | Salmo_gair AAGCCTTGGC AGTGCAGGGT 42 | H._Sapiens ACCGGTTGGC CGTTCAGGGT 43 | Chimp AAACCCTTGC CGTTACGCTT 44 | Gorilla AAACCCTTGC CGGTACGCTT 45 | 46 | GAGCCCGGGC AATACAGGGT AT 47 | GAGCCGTGGC CGGGCACGGT AT 48 | ACAGGTTGGC CGTTCAGGGT AA 49 | AAACCGAGGC CGGGACACTC AT 50 | AAACCATTGC CGGTACGCTT AA 51 | ``` 52 | 53 | #### Phylip sequential strict 54 | ``` 55 | 5 42 56 | Turkey AAGCTNGGGC ATTTCAGGGT 57 | GAGCCCGGGC AATACAGGGT AT 58 | Salmo gairAAGCCTTGGC AGTGCAGGGT 59 | GAGCCGTGGC CGGGCACGGT AT 60 | H. SapiensACCGGTTGGC CGTTCAGGGT 61 | ACAGGTTGGC CGTTCAGGGT AA 62 | Chimp AAACCCTTGC CGTTACGCTT 63 | AAACCGAGGC CGGGACACTC AT 64 | Gorilla AAACCCTTGC CGGTACGCTT 65 | AAACCATTGC CGGTACGCTT AA 66 | ``` 67 | 68 | #### Phylip sequential relaxed 69 | ``` 70 | 5 42 71 | Turkey AAGCTNGGGC ATTTCAGGGT 72 | GAGCCCGGGC AATACAGGGT AT 73 | Salmo_gair AAGCCTTGGC AGTGCAGGGT 74 | GAGCCGTGGC CGGGCACGGT AT 75 | H._Sapiens ACCGGTTGGC CGTTCAGGGT 76 | ACAGGTTGGC CGTTCAGGGT AA 77 | Chimp AAACCCTTGC CGTTACGCTT 78 | AAACCGAGGC CGGGACACTC AT 79 | Gorilla AAACCCTTGC CGGTACGCTT 80 | AAACCATTGC CGGTACGCTT AA 81 | ``` 82 | 83 | #### MacOS code-signing and notarizing 84 | https://medium.com/@TwitterArchiveEraser/notarize-electron-apps-7a5f988406db 85 | https://github.com/electron/electron-notarize 86 | https://stackoverflow.com/questions/53112078/how-to-upload-dmg-file-for-notarization-in-xcode/53121755#53121755 87 | 88 | #### Publishing with electron-builder 89 | Need to have a GH_TOKEN in your shell env 90 | 91 | #### Binaries 92 | The binaries for RAxML on MacOS were compiled from this repository: https://github.com/jtklein/standard-RAxML 93 | 94 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | Todo: 2 | - Github page for downloading the latest release 3 | - Choose light or dark theme 4 | - Option for empirical frequencies? 5 | - In the Output section, add collapsable list of output files with descriptions 6 | - Option to remove existing files (shell.moveItemToTrash(fullPath)) 7 | - Spinning wheel while running to distinguishing it from getting stuck 8 | - Fix parsing a relaxed phylip as strict 9 | - Don't make multithreaded binaries available if num cpus is one. 10 | - Implement auto-updating/checking mechanism. 11 | - Create publish script 12 | -------------------------------------------------------------------------------- /craco.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | babel: { 3 | plugins: [ 4 | ["@babel/plugin-proposal-decorators", { legacy: true }], 5 | ["@babel/plugin-proposal-class-properties", { loose: true }] 6 | ] 7 | }, 8 | webpack: { 9 | configure: { 10 | target: 'electron-renderer' 11 | } 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /dev-app-update.yml: -------------------------------------------------------------------------------- 1 | owner: AntonelliLab 2 | repo: raxmlGUI 3 | provider: github 4 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _site 2 | .sass-cache 3 | .jekyll-metadata 4 | -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | 5 | 18 | 19 |
20 |

404

21 | 22 |

Page not found :(

23 |

The requested page could not be found.

24 |
25 | -------------------------------------------------------------------------------- /docs/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | # Hello! This is where you manage which Jekyll version is used to run. 4 | # When you want to use a different version, change it below, save the 5 | # file and run `bundle install`. Run Jekyll with `bundle exec`, like so: 6 | # 7 | # bundle exec jekyll serve 8 | # 9 | # This will help ensure the proper Jekyll version is running. 10 | # Happy Jekylling! 11 | gem "jekyll", "~> 3.9.0" 12 | 13 | # This is the default theme for new Jekyll sites. You may change this to anything you like. 14 | # gem "minima", "~> 2.0" 15 | gem "jekyll-theme-cayman" 16 | 17 | # If you want to use GitHub Pages, remove the "gem "jekyll"" above and 18 | # uncomment the line below. To upgrade, run `bundle update github-pages`. 19 | # gem "github-pages", group: :jekyll_plugins 20 | 21 | # If you have any plugins, put them here! 22 | group :jekyll_plugins do 23 | gem "jekyll-feed", "~> 0.6" 24 | end 25 | 26 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem 27 | # and associated library. 28 | install_if -> { RUBY_PLATFORM =~ %r!mingw|mswin|java! } do 29 | gem "tzinfo", "~> 1.2" 30 | gem "tzinfo-data" 31 | end 32 | 33 | # Performance-booster for watching directories on Windows 34 | gem "wdm", "~> 0.1.0", :install_if => Gem.win_platform? 35 | 36 | # kramdown v2 ships without the gfm parser by default. If you're using 37 | # kramdown v1, comment out this line. 38 | gem "kramdown-parser-gfm" 39 | 40 | # To preview as github page 41 | gem "github-pages", group: :jekyll_plugins 42 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Jekyll! 2 | # 3 | # This config file is meant for settings that affect your whole blog, values 4 | # which you are expected to set up once and rarely edit after that. If you find 5 | # yourself editing this file very often, consider using Jekyll's data files 6 | # feature for the data you need to update frequently. 7 | # 8 | # For technical reasons, this file is *NOT* reloaded automatically when you use 9 | # 'bundle exec jekyll serve'. If you change this file, please restart the server process. 10 | 11 | # Site settings 12 | # These are used to personalize your new site. If you look in the HTML files, 13 | # you will see them accessed via {{ site.title }}, {{ site.email }}, and so on. 14 | # You can create any custom variable you would like, and they will be accessible 15 | # in the templates via {{ site.myvariable }}. 16 | title: raxmlGUI 2.0 17 | #email: your-email@example.com 18 | description: >- # this means to ignore newlines until "baseurl:" 19 | raxmlGUI 2.0 - a new user-friendly program integrating RAxML-NG 20 | and ModelTest-NG for cutting-edge phylogenetic analysis 21 | baseurl: 'raxmlGUI' # the subpath of your site, e.g. /blog 22 | url: '' # the base hostname & protocol for your site, e.g. http://example.com 23 | twitter_username: jekyllrb 24 | github_username: jekyll 25 | 26 | # Build settings 27 | markdown: kramdown 28 | theme: jekyll-theme-cayman 29 | plugins: 30 | - jekyll-feed 31 | 32 | # Exclude from processing. 33 | # The following items will not be processed, by default. Create a custom list 34 | # to override the default setting. 35 | # exclude: 36 | # - Gemfile 37 | # - Gemfile.lock 38 | # - node_modules 39 | # - vendor/bundle/ 40 | # - vendor/cache/ 41 | # - vendor/gems/ 42 | # - vendor/ruby/ 43 | 44 | show_downloads: true 45 | show_view_on_github: false 46 | google_analytics: UA-149851800-1 47 | 48 | github: [metadata] 49 | -------------------------------------------------------------------------------- /docs/_sass/additions.scss: -------------------------------------------------------------------------------- 1 | /* Style the collapsible content. Note: hidden by default */ 2 | .collapsibleContent { 3 | padding: 0 18px; 4 | display: none; 5 | overflow: hidden; 6 | } 7 | 8 | .basic-section { 9 | position:relative; 10 | padding-top:2.5rem; 11 | padding-bottom:0; 12 | background-color:#edeef0; 13 | } 14 | 15 | .basic-container { 16 | position:relative; 17 | max-width:1248px; 18 | margin-right:auto; 19 | margin-left:auto; 20 | padding:2rem 2.625rem 2.5rem; 21 | padding-right:.75rem; 22 | padding-left:.75rem; 23 | text-align:center; 24 | padding-bottom:0; 25 | overflow:hidden; 26 | } 27 | 28 | .basic-title { 29 | position:relative; 30 | display:-webkit-box; 31 | display:-webkit-flex; 32 | display:-ms-flexbox; 33 | display:flex; 34 | margin-top:2rem; 35 | margin-bottom:2rem; 36 | -webkit-box-orient:vertical; 37 | -webkit-box-direction:normal; 38 | -webkit-flex-direction:column; 39 | -ms-flex-direction:column; 40 | flex-direction:column; 41 | -webkit-box-pack:start; 42 | -webkit-justify-content:flex-start; 43 | -ms-flex-pack:start; 44 | justify-content:flex-start; 45 | -webkit-box-align:center; 46 | -webkit-align-items:center; 47 | -ms-flex-align:center; 48 | align-items:center; 49 | text-align:center; 50 | } 51 | 52 | .basic-info { 53 | font-size:1rem; 54 | line-height:1.35em; 55 | font-weight:500; 56 | letter-spacing:-.01875rem; 57 | } 58 | 59 | .basic-screenshot-container { 60 | position:relative; 61 | height:41rem; 62 | max-height:100%; 63 | max-width:100%; 64 | } 65 | 66 | .basic-screenshot { 67 | left:0; 68 | top:0; 69 | overflow:hidden; 70 | border:.25rem solid #eee; 71 | border-radius:1.3rem; 72 | background-color:#eee; 73 | -o-object-fit:contain; 74 | object-fit:contain; 75 | vertical-align: middle; 76 | display: inline-block; 77 | max-width: 100%; 78 | position: absolute; 79 | z-index: 1; 80 | border-color: #eee; 81 | opacity: 0; 82 | } 83 | 84 | .basic-screenshot.active { 85 | opacity: 1; 86 | transition: opacity 0.5s ease-in-out; 87 | } 88 | 89 | .features-section { 90 | position:relative; 91 | padding-top:2.5rem; 92 | padding-bottom:0; 93 | background-color:#141415; 94 | } 95 | 96 | .features-container { 97 | position:relative; 98 | max-width:1248px; 99 | margin-right:auto; 100 | margin-left:auto; 101 | padding:2rem 2.625rem 2.5rem; 102 | padding-right:.75rem; 103 | padding-left:.75rem; 104 | text-align:center; 105 | align-items: stretch; 106 | } 107 | 108 | .features-title { 109 | position:relative; 110 | display:-webkit-box; 111 | display:-webkit-flex; 112 | display:-ms-flexbox; 113 | display:flex; 114 | margin-top:2rem; 115 | margin-bottom:2rem; 116 | -webkit-box-orient:vertical; 117 | -webkit-box-direction:normal; 118 | -webkit-flex-direction:column; 119 | -ms-flex-direction:column; 120 | flex-direction:column; 121 | -webkit-box-pack:start; 122 | -webkit-justify-content:flex-start; 123 | -ms-flex-pack:start; 124 | justify-content:flex-start; 125 | -webkit-box-align:center; 126 | -webkit-align-items:center; 127 | -ms-flex-align:center; 128 | align-items:center; 129 | text-align:center; 130 | color:#fafafa; 131 | } 132 | 133 | .features-info { 134 | font-size:1rem; 135 | line-height:1.35em; 136 | font-weight:500; 137 | letter-spacing:-.01875rem; 138 | color:#707070; 139 | } 140 | 141 | .feature { 142 | z-index:1; 143 | width:100%; 144 | padding:1rem; 145 | text-align:left; 146 | float:none; 147 | } 148 | 149 | .feature-grid { 150 | display:-ms-grid; 151 | display:grid; 152 | grid-column-gap:1rem; 153 | grid-row-gap:1rem; 154 | grid-template-areas:"."; 155 | margin-bottom:2rem; 156 | } 157 | 158 | @media (min-width: 600px) { 159 | .feature-grid { grid-template-columns: repeat(2, 1fr); } 160 | } 161 | 162 | @media (min-width: 600px) { 163 | .feature-reversed { 164 | grid-column: 1; 165 | grid-row: 1; 166 | } 167 | } 168 | 169 | .feature-image img { 170 | height:auto; 171 | max-width:100%; 172 | vertical-align:top; 173 | } 174 | 175 | .feature-figure { 176 | display:inline-block; 177 | vertical-align:top; 178 | margin:0; 179 | max-width:100%; 180 | } 181 | 182 | .feature-header { 183 | font-size:1.5rem; 184 | line-height:1.3em; 185 | font-weight:500; 186 | letter-spacing:-.0375rem; 187 | margin-bottom:.6875rem; 188 | color:#fafafa; 189 | } 190 | 191 | .feature-info { 192 | font-size:1rem; 193 | line-height:1.35em; 194 | font-weight:500; 195 | letter-spacing:-.01875rem; 196 | margin-bottom:2rem; 197 | opacity:1; 198 | color:#707070; 199 | } 200 | -------------------------------------------------------------------------------- /docs/_sass/jekyll-theme-cayman.scss: -------------------------------------------------------------------------------- 1 | @import "normalize"; 2 | @import "rouge-github"; 3 | @import "variables"; 4 | @import "additions"; 5 | @import url('https://fonts.googleapis.com/css?family=Open+Sans:400,700'); 6 | 7 | @mixin large { 8 | @media screen and (min-width: #{$large-breakpoint}) { 9 | @content; 10 | } 11 | } 12 | 13 | @mixin medium { 14 | @media screen and (min-width: #{$medium-breakpoint}) and (max-width: #{$large-breakpoint}) { 15 | @content; 16 | } 17 | } 18 | 19 | @mixin small { 20 | @media screen and (max-width: #{$medium-breakpoint}) { 21 | @content; 22 | } 23 | } 24 | 25 | * { 26 | box-sizing: border-box; 27 | } 28 | 29 | body { 30 | padding: 0; 31 | margin: 0; 32 | font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; 33 | font-size: 16px; 34 | line-height: 1.5; 35 | color: $body-text-color; 36 | } 37 | 38 | a { 39 | color: $body-link-color; 40 | text-decoration: none; 41 | 42 | &:hover { 43 | text-decoration: underline; 44 | } 45 | } 46 | 47 | .btn { 48 | display: inline-block; 49 | margin-bottom: 1rem; 50 | color: rgba(255, 255, 255, 0.7); 51 | background-color: rgba(255, 255, 255, 0.08); 52 | border-color: rgba(255, 255, 255, 0.2); 53 | border-style: solid; 54 | border-width: 1px; 55 | border-radius: 0.3rem; 56 | transition: color 0.2s, background-color 0.2s, border-color 0.2s; 57 | 58 | &:hover { 59 | color: rgba(255, 255, 255, 0.8); 60 | text-decoration: none; 61 | background-color: rgba(255, 255, 255, 0.2); 62 | border-color: rgba(255, 255, 255, 0.3); 63 | } 64 | 65 | + .btn { 66 | margin-left: 1rem; 67 | } 68 | 69 | @include large { 70 | padding: 0.75rem 1rem; 71 | } 72 | 73 | @include medium { 74 | padding: 0.6rem 0.9rem; 75 | font-size: 0.9rem; 76 | } 77 | 78 | @include small { 79 | display: block; 80 | width: 100%; 81 | padding: 0.75rem; 82 | font-size: 0.9rem; 83 | 84 | + .btn { 85 | margin-top: 1rem; 86 | margin-left: 0; 87 | } 88 | } 89 | } 90 | 91 | .page-header { 92 | color: $header-heading-color; 93 | text-align: center; 94 | background-color: $header-bg-color; 95 | background-image: linear-gradient(120deg, $header-bg-color-secondary, $header-bg-color); 96 | // background-image: linear-gradient(120deg, $header-bg-color-secondary, $header-bg-color-middle, $header-bg-color); 97 | // background-image: linear-gradient(120deg, $header-bg-color-secondary, $header-bg-color-middle 40%, $header-bg-color 70%); 98 | 99 | @include large { 100 | padding: 5rem 6rem; 101 | } 102 | 103 | @include medium { 104 | padding: 3rem 4rem; 105 | } 106 | 107 | @include small { 108 | padding: 2rem 1rem; 109 | } 110 | } 111 | 112 | .project-name { 113 | margin-top: 0; 114 | margin-bottom: 0.1rem; 115 | 116 | @include large { 117 | font-size: 3.25rem; 118 | } 119 | 120 | @include medium { 121 | font-size: 2.25rem; 122 | } 123 | 124 | @include small { 125 | font-size: 1.75rem; 126 | } 127 | } 128 | 129 | .project-tagline { 130 | margin-bottom: 2rem; 131 | font-weight: normal; 132 | opacity: 0.7; 133 | 134 | @include large { 135 | font-size: 1.25rem; 136 | } 137 | 138 | @include medium { 139 | font-size: 1.15rem; 140 | } 141 | 142 | @include small { 143 | font-size: 1rem; 144 | } 145 | } 146 | 147 | .main-content { 148 | word-wrap: break-word; 149 | 150 | :first-child { 151 | margin-top: 0; 152 | } 153 | 154 | @include large { 155 | max-width: 64rem; 156 | padding: 2rem 6rem; 157 | margin: 0 auto; 158 | font-size: 1.1rem; 159 | } 160 | 161 | @include medium { 162 | padding: 2rem 4rem; 163 | font-size: 1.1rem; 164 | } 165 | 166 | @include small { 167 | padding: 2rem 1rem; 168 | font-size: 1rem; 169 | } 170 | 171 | img { 172 | max-width: 100%; 173 | } 174 | 175 | h1, 176 | h2, 177 | h3, 178 | h4, 179 | h5, 180 | h6 { 181 | margin-top: 2rem; 182 | margin-bottom: 1rem; 183 | font-weight: normal; 184 | color: $section-headings-color; 185 | } 186 | 187 | p { 188 | margin-bottom: 1em; 189 | } 190 | 191 | code { 192 | padding: 2px 4px; 193 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; 194 | font-size: 0.9rem; 195 | color: $code-text-color; 196 | background-color: $code-bg-color; 197 | border-radius: 0.3rem; 198 | } 199 | 200 | pre { 201 | padding: 0.8rem; 202 | margin-top: 0; 203 | margin-bottom: 1rem; 204 | font: 1rem Consolas, "Liberation Mono", Menlo, Courier, monospace; 205 | color: $code-text-color; 206 | word-wrap: normal; 207 | background-color: $code-bg-color; 208 | border: solid 1px $border-color; 209 | border-radius: 0.3rem; 210 | 211 | > code { 212 | padding: 0; 213 | margin: 0; 214 | font-size: 0.9rem; 215 | color: $code-text-color; 216 | word-break: normal; 217 | white-space: pre; 218 | background: transparent; 219 | border: 0; 220 | } 221 | } 222 | 223 | .highlight { 224 | margin-bottom: 1rem; 225 | 226 | pre { 227 | margin-bottom: 0; 228 | word-break: normal; 229 | } 230 | } 231 | 232 | .highlight pre, 233 | pre { 234 | padding: 0.8rem; 235 | overflow: auto; 236 | font-size: 0.9rem; 237 | line-height: 1.45; 238 | border-radius: 0.3rem; 239 | -webkit-overflow-scrolling: touch; 240 | } 241 | 242 | pre code, 243 | pre tt { 244 | display: inline; 245 | max-width: initial; 246 | padding: 0; 247 | margin: 0; 248 | overflow: initial; 249 | line-height: inherit; 250 | word-wrap: normal; 251 | background-color: transparent; 252 | border: 0; 253 | 254 | &:before, 255 | &:after { 256 | content: normal; 257 | } 258 | } 259 | 260 | ul, 261 | ol { 262 | margin-top: 0; 263 | } 264 | 265 | blockquote { 266 | padding: 0 1rem; 267 | margin-left: 0; 268 | color: $blockquote-text-color; 269 | border-left: 0.3rem solid $border-color; 270 | 271 | > :first-child { 272 | margin-top: 0; 273 | } 274 | 275 | > :last-child { 276 | margin-bottom: 0; 277 | } 278 | } 279 | 280 | table { 281 | display: block; 282 | width: 100%; 283 | overflow: auto; 284 | word-break: normal; 285 | word-break: keep-all; // For Firefox to horizontally scroll wider tables. 286 | -webkit-overflow-scrolling: touch; 287 | 288 | th { 289 | font-weight: bold; 290 | } 291 | 292 | th, 293 | td { 294 | padding: 0.5rem 1rem; 295 | border: 1px solid $table-border-color; 296 | } 297 | } 298 | 299 | dl { 300 | padding: 0; 301 | 302 | dt { 303 | padding: 0; 304 | margin-top: 1rem; 305 | font-size: 1rem; 306 | font-weight: bold; 307 | } 308 | 309 | dd { 310 | padding: 0; 311 | margin-bottom: 1rem; 312 | } 313 | } 314 | 315 | hr { 316 | height: 2px; 317 | padding: 0; 318 | margin: 1rem 0; 319 | background-color: $hr-border-color; 320 | border: 0; 321 | } 322 | } 323 | 324 | .site-footer { 325 | padding-top: 2rem; 326 | margin-top: 2rem; 327 | border-top: solid 1px $hr-border-color; 328 | 329 | @include large { 330 | font-size: 1rem; 331 | } 332 | 333 | @include medium { 334 | font-size: 1rem; 335 | } 336 | 337 | @include small { 338 | font-size: 0.9rem; 339 | } 340 | } 341 | 342 | .site-footer-owner { 343 | display: block; 344 | font-weight: bold; 345 | } 346 | 347 | .site-footer-credits { 348 | color: $blockquote-text-color; 349 | } 350 | -------------------------------------------------------------------------------- /docs/_sass/variables.scss: -------------------------------------------------------------------------------- 1 | // Breakpoints 2 | $large-breakpoint: 64em !default; 3 | $medium-breakpoint: 42em !default; 4 | 5 | // Headers 6 | $header-heading-color: #fff !default; 7 | // $header-bg-color: hsla(211, 34%, 83%, 1) !default; 8 | // $header-bg-color: hsla(211, 34%, 77%, 1) !default; 9 | $header-bg-color: hsla(211, 34%, 41%, 1) !default; 10 | // $header-bg-color-middle: hsla(33, 34%, 83%, 1) !default; 11 | // $header-bg-color-middle: hsla(33, 34%, 77%, 1) !default; 12 | $header-bg-color-middle: hsla(33, 34%, 41%, 1) !default; 13 | // $header-bg-color-secondary: hsla(92, 34%, 83%, 1) !default; 14 | // $header-bg-color-secondary: hsla(92, 34%, 77%, 1) !default; 15 | $header-bg-color-secondary: hsla(92, 34%, 41%, 1) !default; 16 | 17 | // Text 18 | $section-headings-color: hsla(211, 27%, 23%, 1) !default; 19 | $body-text-color: #606c71 !default; 20 | $body-link-color: #1e6bb8 !default; 21 | $blockquote-text-color: #819198 !default; 22 | 23 | // Code 24 | $code-bg-color: #f3f6fa !default; 25 | $code-text-color: #567482 !default; 26 | 27 | // Borders 28 | $border-color: #dce6f0 !default; 29 | $table-border-color: #e9ebec !default; 30 | $hr-border-color: #eff0f1 !default; 31 | -------------------------------------------------------------------------------- /docs/assets/css/style.scss: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | @import "{{ site.theme }}"; 5 | -------------------------------------------------------------------------------- /docs/assets/img/icon_macos.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/assets/img/icon_windows.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/assets/img/raxmlgui_icon_256x256x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonelliLab/raxmlGUI/f5b59126ea6c34e84e89a1c2c07b966e07afd216/docs/assets/img/raxmlgui_icon_256x256x32.png -------------------------------------------------------------------------------- /docs/assets/img/screenshots/basic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonelliLab/raxmlGUI/f5b59126ea6c34e84e89a1c2c07b966e07afd216/docs/assets/img/screenshots/basic.png -------------------------------------------------------------------------------- /docs/assets/img/screenshots/basic2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonelliLab/raxmlGUI/f5b59126ea6c34e84e89a1c2c07b966e07afd216/docs/assets/img/screenshots/basic2.png -------------------------------------------------------------------------------- /docs/assets/img/screenshots/basic2_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonelliLab/raxmlGUI/f5b59126ea6c34e84e89a1c2c07b966e07afd216/docs/assets/img/screenshots/basic2_dark.png -------------------------------------------------------------------------------- /docs/assets/img/screenshots/basic_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonelliLab/raxmlGUI/f5b59126ea6c34e84e89a1c2c07b966e07afd216/docs/assets/img/screenshots/basic_dark.png -------------------------------------------------------------------------------- /docs/assets/img/screenshots/console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonelliLab/raxmlGUI/f5b59126ea6c34e84e89a1c2c07b966e07afd216/docs/assets/img/screenshots/console.png -------------------------------------------------------------------------------- /docs/assets/img/screenshots/model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonelliLab/raxmlGUI/f5b59126ea6c34e84e89a1c2c07b966e07afd216/docs/assets/img/screenshots/model.png -------------------------------------------------------------------------------- /docs/assets/img/screenshots/parallel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonelliLab/raxmlGUI/f5b59126ea6c34e84e89a1c2c07b966e07afd216/docs/assets/img/screenshots/parallel.png -------------------------------------------------------------------------------- /docs/assets/img/screenshots/partition_editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonelliLab/raxmlGUI/f5b59126ea6c34e84e89a1c2c07b966e07afd216/docs/assets/img/screenshots/partition_editor.png -------------------------------------------------------------------------------- /docs/assets/img/screenshots/pipelines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonelliLab/raxmlGUI/f5b59126ea6c34e84e89a1c2c07b966e07afd216/docs/assets/img/screenshots/pipelines.png -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonelliLab/raxmlGUI/f5b59126ea6c34e84e89a1c2c07b966e07afd216/docs/favicon.ico -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # Feel free to add content and custom Front Matter to this file. 3 | # To modify the layout, see https://jekyllrb.com/docs/themes/#overriding-theme-defaults 4 | 5 | #layout: home 6 | description: A new user-friendly program integrating RAxML-NG and ModelTest-NG for cutting-edge phylogenetic analysis 7 | --- 8 | 9 | The program presented here is the first release, the most important functions and analyses are implemented and functional. However, we encourage users to [send us any feedback they may have](mailto:raxmlgui.help@gmail.com). raxmlGUI 2.0 facilitates phylogenetic analyses by coupling an intuitive interface with the unmatched performance of RAxML. Read more in the [accompanying paper](http://dx.doi.org/10.1111/2041-210X.13512). 10 | 11 | ------------------------ 12 | 13 | 14 | 1 Edler, D., J. Klein, A. Antonelli, and D. Silvestro. 2020. **raxmlGUI 2.0: A graphical interface and toolkit for phylogenetic analyses using RAxML.** _Methods in Ecology and Evolution_, doi: http://dx.doi.org/10.1111/2041-210X.13512 15 | 16 | 17 | 18 | 2 Silvestro, D. and I. Michalak. 2012. **raxmlGUI: a graphical front-end for RAxML.** _Organisms Diversity and Evolution_ 12:335–337. 19 | 20 | 21 | 22 | 3 Stamatakis, A. 2014. **Raxml version 8: a tool for phylogenetic analysis andpost-analysis of large phylogenies.** _Bioinformatics_ 30:1312–1313. 23 | 24 | 25 | 26 | 4 Kozlov, A. M., D. Darriba, T. Flouri, B. Morel, and A. Stamatakis. 2019. **RAxML-NG: a fast, scalable and user-friendly tool for maximum likelihood phylogenetic inference.** _Bioinformatics_ 35:4453–4455. 27 | 28 | 29 | 30 | 5 Darriba, D., D. Posada, A. M. Kozlov, A. Stamatakis, B. Morel, T. Flouri. 2020. **ModelTest-NG: A New and Scalable Tool for the Selection of DNA and Protein Evolutionary Models.** _Molecular Biology and Evolution_ 37:291–294. 31 | 32 | -------------------------------------------------------------------------------- /docs/jekyll-theme-cayman/.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | .bundle 3 | .sass-cache 4 | _site 5 | Gemfile.lock 6 | -------------------------------------------------------------------------------- /docs/jekyll-theme-cayman/Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | gemspec 5 | -------------------------------------------------------------------------------- /docs/jekyll-theme-cayman/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Daniel Edler 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/jekyll-theme-cayman/README.md: -------------------------------------------------------------------------------- 1 | # jekyll-theme-cayman 2 | 3 | Welcome to your new Jekyll theme! In this directory, you'll find the files you need to be able to package up your theme into a gem. Put your layouts in `_layouts`, your includes in `_includes`, your sass files in `_sass` and any other assets in `assets`. 4 | 5 | To experiment with this code, add some sample content and run `bundle exec jekyll serve` – this directory is setup just like a Jekyll site! 6 | 7 | TODO: Delete this and the text above, and describe your gem 8 | 9 | 10 | ## Installation 11 | 12 | Add this line to your Jekyll site's `Gemfile`: 13 | 14 | ```ruby 15 | gem "jekyll-theme-cayman" 16 | ``` 17 | 18 | And add this line to your Jekyll site's `_config.yml`: 19 | 20 | ```yaml 21 | theme: jekyll-theme-cayman 22 | ``` 23 | 24 | And then execute: 25 | 26 | $ bundle 27 | 28 | Or install it yourself as: 29 | 30 | $ gem install jekyll-theme-cayman 31 | 32 | ## Usage 33 | 34 | TODO: Write usage instructions here. Describe your available layouts, includes, sass and/or assets. 35 | 36 | ## Contributing 37 | 38 | Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/hello. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. 39 | 40 | ## Development 41 | 42 | To set up your environment to develop this theme, run `bundle install`. 43 | 44 | Your theme is setup just like a normal Jekyll site! To test your theme, run `bundle exec jekyll serve` and open your browser at `http://localhost:4000`. This starts a Jekyll server using your theme. Add pages, documents, data, etc. like normal to test your theme's contents. As you make modifications to your theme and to your content, your site will regenerate and you should see the changes in the browser after a refresh, just like normal. 45 | 46 | When your theme is released, only the files in `_layouts`, `_includes`, `_sass` and `assets` tracked with Git will be bundled. 47 | To add a custom directory to your theme-gem, please edit the regexp in `jekyll-theme-cayman.gemspec` accordingly. 48 | 49 | ## License 50 | 51 | The theme is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). 52 | 53 | -------------------------------------------------------------------------------- /docs/jekyll-theme-cayman/_layouts/default.html: -------------------------------------------------------------------------------- 1 | {{ content }} 2 | -------------------------------------------------------------------------------- /docs/jekyll-theme-cayman/_layouts/page.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | 5 | {{ content }} 6 | -------------------------------------------------------------------------------- /docs/jekyll-theme-cayman/_layouts/post.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | 5 | {{ content }} 6 | -------------------------------------------------------------------------------- /docs/jekyll-theme-cayman/jekyll-theme-cayman.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Gem::Specification.new do |spec| 4 | spec.name = "jekyll-theme-cayman" 5 | spec.version = "0.1.0" 6 | spec.authors = ["Daniel Edler"] 7 | spec.email = ["edler.dev@gmail.com"] 8 | 9 | spec.summary = "TODO: Write a short summary, because Rubygems requires one." 10 | spec.homepage = "TODO: Put your gem's website or public repo URL here." 11 | spec.license = "MIT" 12 | 13 | spec.files = `git ls-files -z`.split("\x0").select { |f| f.match(%r!^(assets|_layouts|_includes|_sass|LICENSE|README)!i) } 14 | 15 | spec.add_runtime_dependency "jekyll", "~> 3.9" 16 | 17 | spec.add_development_dependency "bundler", ">= 2.1.0" 18 | spec.add_development_dependency "rake", "~> 12.0" 19 | end 20 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext" 4 | }, 5 | "exclude": [ 6 | "node_modules", 7 | "build", 8 | "dist" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "raxmlgui", 3 | "productName": "raxmlGUI", 4 | "version": "2.0.16", 5 | "private": true, 6 | "author": "AntonelliLab ", 7 | "license": "AGPL-3.0", 8 | "description": "raxmlGUI - A new graphical front-end for RAxML", 9 | "homepage": "./", 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/AntonelliLab/raxmlGUI.git" 13 | }, 14 | "bugs": { 15 | "url": "https://github.com/AntonelliLab/raxmlGUI/issues" 16 | }, 17 | "keywords": [ 18 | "Electron", 19 | "RAxML", 20 | "GUI", 21 | "Phylogenetics" 22 | ], 23 | "main": "build/electron.js", 24 | "scripts": { 25 | "start": "cross-env ELECTRON_START_URL=http://localhost:3000/ run-p react-start electron-dev", 26 | "react-start": "cross-env BROWSER=none craco start", 27 | "react-build": "craco build", 28 | "react-test": "craco test --env=jsdom", 29 | "react-eject": "react-scripts eject", 30 | "wait-dev": "wait-on $ELECTRON_START_URL", 31 | "download-binaries": "node scripts/download-binaries.js", 32 | "electron-dev": "electron-webpack dev", 33 | "electron-start": "cross-env DEV=true run-s wait-dev electron-dev", 34 | "electron-build": "electron-builder", 35 | "electron-build-win": "electron-builder -w", 36 | "electron-build-linux": "electron-builder -l", 37 | "electron-build-all": "electron-builder -mwl", 38 | "electron-build-publish-all": "electron-builder -mwl -p always", 39 | "electron-pack": "electron-builder --dir -c.compression=store -c.mac.identity=null", 40 | "electron-pack-win": "electron-builder -w --dir -c.compression=store", 41 | "electron-compile": "electron-webpack", 42 | "electron-copy": "shx cp dist/main/main.js build/electron.js", 43 | "compile": "run-s electron-compile electron-copy", 44 | "build": "run-s react-build compile", 45 | "build-mac": "run-s react-build compile electron-build", 46 | "build-win": "run-s react-build compile electron-build-win", 47 | "build-linux": "run-s react-build compile electron-build-linux", 48 | "build-all": "run-s react-build compile electron-build-all", 49 | "dist-pack": "run-s react-build compile electron-pack", 50 | "dist-pack-win": "run-s react-build compile electron-pack-win", 51 | "publish-all": "run-s react-build compile electron-build-publish-all", 52 | "postinstall-deps": "electron-builder install-app-deps", 53 | "postinstall-patch": "patch-package", 54 | "postinstall": "run-s postinstall-deps postinstall-patch", 55 | "docs-serve": "cd docs && bundle exec jekyll serve" 56 | }, 57 | "dependencies": { 58 | "@babel/plugin-proposal-decorators": "^7.19.0", 59 | "@craco/craco": "^7.1.0", 60 | "@emotion/react": "^11.14.0", 61 | "@emotion/styled": "^11.14.0", 62 | "@mui/icons-material": "^6.4.11", 63 | "@mui/lab": "^6.0.1-beta.34", 64 | "@mui/material": "^6.4.11", 65 | "@mui/styles": "^6.4.11", 66 | "@sentry/electron": "^4.0.2", 67 | "classnames": "^2.3.2", 68 | "clean-stack": "3.0.1", 69 | "clsx": "^1.2.1", 70 | "computed-async-mobx": "^4.2.0", 71 | "cpus": "^1.0.3", 72 | "d3-array": "^3.2.4", 73 | "electron-better-ipc": "^2.0.1", 74 | "electron-log": "^4.4.8", 75 | "electron-progressbar": "^2.2.1", 76 | "electron-store": "^8.1.0", 77 | "electron-updater": "^5.2.4", 78 | "filenamify": "^4.3.0", 79 | "lodash": "^4.17.21", 80 | "mobx": "^5.15.7", 81 | "mobx-react": "^6.3.1", 82 | "mobx-react-lite": "^2.2.2", 83 | "mobx-utils": "^5.6.2", 84 | "parse-filepath": "^1.0.2", 85 | "patch-package": "^6.4.7", 86 | "postinstall-postinstall": "^2.1.0", 87 | "prismjs": "^1.30.0", 88 | "prismjs-bibtex": "^2.1.0", 89 | "prop-types": "^15.8.1", 90 | "react": "^18.3.1", 91 | "react-dom": "^18.3.1", 92 | "react-dropzone": "14.2.10", 93 | "react-scripts": "^5.0.1", 94 | "react-split-pane": "^0.1.92", 95 | "serialize-error": "^8.1.0", 96 | "source-map-support": "^0.5.21", 97 | "yup": "^0.32.11" 98 | }, 99 | "devDependencies": { 100 | "@babel/plugin-proposal-class-properties": "^7.18.6", 101 | "@babel/preset-env": "^7.19.0", 102 | "@electron/notarize": "^2.5.0", 103 | "@sentry/cli": "^2.5.2", 104 | "@sentry/webpack-plugin": "^1.19.0", 105 | "cross-env": "^7.0.3", 106 | "dotenv": "^16.5.0", 107 | "download": "^8.0.0", 108 | "electron": "^36.2.1", 109 | "electron-builder": "^24.13.3", 110 | "electron-download": "^4.1.1", 111 | "electron-webpack": "^2.8.2", 112 | "nodemon": "^3.1.9", 113 | "npm-run-all": "^4.1.5", 114 | "prettier": "^2.8.8", 115 | "shx": "^0.4.0", 116 | "typescript": "^4.9.5", 117 | "wait-on": "^8.0.3" 118 | }, 119 | "browserslist": [ 120 | ">0.2%", 121 | "not dead", 122 | "not ie <= 11", 123 | "not op_mini all" 124 | ], 125 | "electronWebpack": { 126 | "commonSourceDirectory": "src/common", 127 | "staticSourceDirectory": "static", 128 | "main": { 129 | "sourceDirectory": "src/main", 130 | "webpackConfig": "webpack.config.js" 131 | }, 132 | "renderer": { 133 | "sourceDirectory": null, 134 | "webpackConfig": "webpack.config.js" 135 | } 136 | }, 137 | "build": { 138 | "appId": "org.jtklein.raxmlGUI2", 139 | "productName": "raxmlGUI", 140 | "afterSign": "./scripts/notarize.js", 141 | "directories": { 142 | "buildResources": "build", 143 | "output": "dist" 144 | }, 145 | "files": [ 146 | "src/main/*" 147 | ], 148 | "extraResources": [ 149 | "assets/" 150 | ], 151 | "dmg": { 152 | "icon": "build/disk-image.icns", 153 | "sign": false 154 | }, 155 | "mac": { 156 | "mergeASARs": false, 157 | "target": [ 158 | { 159 | "target": "dmg", 160 | "arch": [ 161 | "universal" 162 | ] 163 | }, 164 | { 165 | "target": "zip", 166 | "arch": [ 167 | "universal" 168 | ] 169 | } 170 | ], 171 | "x64ArchFiles": "**/static/bin/*", 172 | "category": "public.app-category.education", 173 | "hardenedRuntime": true, 174 | "entitlements": "public/entitlements.mac.inherit.plist", 175 | "entitlementsInherit": "public/entitlements.mac.inherit.plist", 176 | "extraResources": [ 177 | { 178 | "from": "static/bin/Mac", 179 | "to": "static/bin" 180 | }, 181 | { 182 | "from": "static/example-files/fasta", 183 | "to": "static/example-files", 184 | "filter": [ 185 | "*.txt" 186 | ] 187 | } 188 | ] 189 | }, 190 | "win": { 191 | "target": [ 192 | "nsis" 193 | ], 194 | "extraResources": [ 195 | { 196 | "from": "static/bin/Windows", 197 | "to": "static/bin" 198 | } 199 | ] 200 | }, 201 | "linux": { 202 | "target": [ 203 | "AppImage" 204 | ], 205 | "category": "Education", 206 | "extraResources": [ 207 | { 208 | "from": "static/bin/Linux", 209 | "to": "static/bin" 210 | } 211 | ] 212 | }, 213 | "publish": { 214 | "provider": "github" 215 | } 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /patches/electron-webpack+2.8.2.patch: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/electron-webpack/out/targets/BaseTarget.js b/node_modules/electron-webpack/out/targets/BaseTarget.js 2 | index e4c6b00..8eea68c 100644 3 | --- a/node_modules/electron-webpack/out/targets/BaseTarget.js 4 | +++ b/node_modules/electron-webpack/out/targets/BaseTarget.js 5 | @@ -156,7 +156,7 @@ class BaseTarget { 6 | plugins.push(new (_WebpackRemoveOldAssetsPlugin().WebpackRemoveOldAssetsPlugin)(dllManifest)); 7 | } 8 | 9 | - optimization.noEmitOnErrors = true; 10 | + optimization.emitOnErrors = false; 11 | const additionalEnvironmentVariables = Object.keys(process.env).filter(it => it.startsWith("ELECTRON_WEBPACK_")); 12 | 13 | if (additionalEnvironmentVariables.length > 0) { 14 | @@ -185,7 +185,7 @@ function isAncestor(file, dir) { 15 | 16 | function configureDevelopmentPlugins(configurator) { 17 | const plugins = configurator.plugins; 18 | - configurator.config.optimization.namedModules = true; 19 | + configurator.config.optimization.moduleIds = "named"; 20 | plugins.push(new (_webpack().DefinePlugin)({ 21 | __static: `"${path.join(configurator.projectDir, configurator.staticSourceDirectory).replace(/\\/g, "\\\\")}"`, 22 | "process.env.NODE_ENV": configurator.isProduction ? "\"production\"" : "\"development\"" 23 | diff --git a/node_modules/electron-webpack/readme.md b/node_modules/electron-webpack/readme.md 24 | deleted file mode 100644 25 | index 2504278..0000000 26 | --- a/node_modules/electron-webpack/readme.md 27 | +++ /dev/null 28 | @@ -1,45 +0,0 @@ 29 | -# electron-webpack [![npm version](https://img.shields.io/npm/v/electron-webpack.svg)](https://npmjs.org/package/electron-webpack) 30 | - 31 | -> Because setting up `webpack` in the `electron` environment shouldn't be difficult. 32 | - 33 | -## Overview 34 | -Modern web development practices today require a lot of setup with things like `webpack` to bundle your code, `babel` for transpiling, `eslint` for linting, and so much more that the list just goes on. Unfortunately when creating `electron` applications, all of that setup just became much more difficult. The primary aim of `electron-webpack` is to eliminate all preliminary setup with one simple install so you can get back to developing your application. 35 | - 36 | -> Why create a module and not a full boilerplate? 37 | - 38 | -If you've been in the JavaScript world for even a short period of time, you are very aware that things are always changing, and development setup is no exclusion. Putting all development scripts into a single **updatable** module just makes sense. Sure a full featured boilerplate works too, but doing also involves needing to manually update those pesky `webpack` configuration files that some may call *magic* when something new comes out. 39 | - 40 | -Here are some of the awesome features you'll find using `electron-webpack`... 41 | - 42 | -* Detailed [documentation](https://webpack.electron.build) 43 | -* Use of [`webpack`](https://webpack.js.org/) for source code bundling 44 | -* Use of [`webpack-dev-server`](https://github.com/webpack/webpack-dev-server) for development 45 | -* HMR for both `renderer` and `main` processes 46 | -* Use of [`@babel/preset-env`](https://github.com/babel/babel/tree/master/packages/babel-preset-env) that is automatically configured based on your `electron` version 47 | -* Ability to add custom `webpack` loaders, plugins, etc. 48 | -* [Add-ons](https://webpack.electron.build/add-ons) to support items like [TypeScript](http://www.typescriptlang.org/), [Less](http://lesscss.org/), [EJS](http://www.embeddedjs.com/), etc. 49 | - 50 | -## Quick Start 51 | -Get started fast with [electron-webpack-quick-start](https://github.com/electron-userland/electron-webpack-quick-start). 52 | -```bash 53 | -# create a directory of your choice, and copy template using curl 54 | -mkdir my-project && cd my-project 55 | -curl -fsSL https://github.com/electron-userland/electron-webpack-quick-start/archive/master.tar.gz | tar -xz --strip-components 1 56 | - 57 | -# or copy template using git clone 58 | -git clone https://github.com/electron-userland/electron-webpack-quick-start.git 59 | -cd electron-webpack-quick-start 60 | -rm -rf .git 61 | - 62 | -# install dependencies 63 | -yarn 64 | -``` 65 | - 66 | -If you already have an existing project, or are looking for a custom approach outside of the quick start template, make sure to read over the [Core Concepts](https://webpack.electron.build/core-concepts), [Project Structure](https://webpack.electron.build/project-structure), and [Development](https://webpack.electron.build/development) sections of `electron-webpack`'s documentation. 67 | - 68 | -### Next Steps 69 | -Make sure to take advantage of the detailed [documentation](https://webpack.electron.build) that `electron-webpack` provides. It covers everything from how things work internally, adding custom configurations, and building your application. 70 | - 71 | -### Contributing 72 | -Feel free to grab an issue and fix it or to share your features and improvements - PRs are always welcome! 73 | -However, in order for your contribution to be property included in the automatically generated release notes, please use our [standard format](https://gist.github.com/develar/273e2eb938792cf5f86451fbac2bcd51) for your commit messages. 74 | -------------------------------------------------------------------------------- /public/disk-image.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonelliLab/raxmlGUI/f5b59126ea6c34e84e89a1c2c07b966e07afd216/public/disk-image.icns -------------------------------------------------------------------------------- /public/entitlements.mac.inherit.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.cs.allow-jit 6 | 7 | com.apple.security.cs.allow-unsigned-executable-memory 8 | 9 | com.apple.security.cs.allow-dyld-environment-variables 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonelliLab/raxmlGUI/f5b59126ea6c34e84e89a1c2c07b966e07afd216/public/favicon.ico -------------------------------------------------------------------------------- /public/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonelliLab/raxmlGUI/f5b59126ea6c34e84e89a1c2c07b966e07afd216/public/icon.icns -------------------------------------------------------------------------------- /public/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonelliLab/raxmlGUI/f5b59126ea6c34e84e89a1c2c07b966e07afd216/public/icon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 15 | 16 | 17 | 26 | raxmlGUI 2.0 27 | 28 | 29 | 32 |
33 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /scripts/download-binaries.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs').promises; 2 | const path = require('path'); 3 | const download = require('download'); 4 | 5 | const osName = (() => { 6 | switch (process.platform) { 7 | case 'darwin': 8 | return 'Mac'; 9 | case 'win32': 10 | return 'Windows'; 11 | default: 12 | return 'Linux'; 13 | } 14 | })(); 15 | 16 | const binariesBaseDir = 17 | 'https://github.com/AntonelliLab/raxmlGUI-binaries/releases/download/v24.09.28'; 18 | const binariesUrl = `${binariesBaseDir}/${osName}.zip`; 19 | 20 | const binPath = path.join(__dirname, '..', 'static', 'bin'); 21 | const raxmlNgPath = path.join(binPath, 'raxml-ng'); 22 | 23 | (async () => { 24 | console.log('Check binaries...'); 25 | let exist = true; 26 | try { 27 | await fs.access(raxmlNgPath); 28 | } catch (_) { 29 | exist = false; 30 | } 31 | 32 | if (exist) { 33 | console.log('Binaries exist!'); 34 | return; 35 | } 36 | 37 | console.log(`Binaries missing, downloading from '${binariesUrl}'...`); 38 | 39 | await download(binariesUrl, binPath, { 40 | extract: true, 41 | }); 42 | console.log('Done!'); 43 | })(); 44 | -------------------------------------------------------------------------------- /scripts/notarize.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | const { notarize } = require('@electron/notarize'); 3 | 4 | exports.default = async function notarizing(context) { 5 | const { electronPlatformName, appOutDir } = context; 6 | if (electronPlatformName !== 'darwin') { 7 | return; 8 | } 9 | 10 | const appleId = process.env.APPLEID; 11 | const appleIdPassword = process.env.APPLEIDPASS; 12 | const teamId = process.env.APPLEIDTEAM; 13 | 14 | if (!appleId) { 15 | console.log( 16 | 'Johannes: Skipping notarization of app because no AppleID is given.' 17 | ); 18 | console.log('Johannes: This binary is not ready for release.'); 19 | return; 20 | } 21 | if (!appleIdPassword) { 22 | console.log( 23 | 'Johannes: Skipping notarization of app because no AppleID password is given.' 24 | ); 25 | console.log('Johannes: This binary is not ready for release.'); 26 | return; 27 | } 28 | if (!teamId) { 29 | console.log( 30 | 'Johannes: Skipping notarization of app because no AppleID team number is given.' 31 | ); 32 | console.log('Johannes: This binary is not ready for release.'); 33 | return; 34 | } 35 | 36 | const appName = context.packager.appInfo.productFilename; 37 | console.log(`Notarizing ${appName} found at ${appOutDir}`); 38 | 39 | return await notarize({ 40 | appBundleId: 'org.jtklein.raxmlGUI2', 41 | appPath: `${appOutDir}/${appName}.app`, 42 | appleId, 43 | appleIdPassword, 44 | teamId, 45 | }); 46 | }; 47 | -------------------------------------------------------------------------------- /sentry-symbols.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | let SentryCli; 4 | let download; 5 | 6 | try { 7 | SentryCli = require('@sentry/cli'); 8 | download = require('electron-download'); 9 | } catch (e) { 10 | console.error('ERROR: Missing required packages, please run:'); 11 | console.error('npm install --save-dev @sentry/cli electron-download'); 12 | process.exit(1); 13 | } 14 | 15 | const VERSION = /\bv?(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[\da-z-]+(?:\.[\da-z-]+)*)?(?:\+[\da-z-]+(?:\.[\da-z-]+)*)?\b/i; 16 | const SYMBOL_CACHE_FOLDER = '.electron-symbols'; 17 | const package = require('./package.json'); 18 | const sentryCli = new SentryCli('./sentry.properties'); 19 | 20 | async function main() { 21 | let version = getElectronVersion(); 22 | if (!version) { 23 | console.error('Cannot detect electron version, check package.json'); 24 | return; 25 | } 26 | 27 | console.log('We are starting to download all possible electron symbols'); 28 | console.log('We need it in order to symbolicate native crashes'); 29 | console.log( 30 | 'This step is only needed once whenever you update your electron version', 31 | ); 32 | console.log('Just call this script again it should do everything for you.'); 33 | 34 | let zipPath = await downloadSymbols({ 35 | version, 36 | platform: 'darwin', 37 | arch: 'x64', 38 | dsym: true, 39 | }); 40 | await sentryCli.execute(['upload-dif', '-t', 'dsym', zipPath], true); 41 | 42 | zipPath = await downloadSymbols({ 43 | version, 44 | platform: 'win32', 45 | arch: 'ia32', 46 | symbols: true, 47 | }); 48 | await sentryCli.execute(['upload-dif', '-t', 'breakpad', zipPath], true); 49 | 50 | zipPath = await downloadSymbols({ 51 | version, 52 | platform: 'win32', 53 | arch: 'x64', 54 | symbols: true, 55 | }); 56 | await sentryCli.execute(['upload-dif', '-t', 'breakpad', zipPath], true); 57 | 58 | zipPath = await downloadSymbols({ 59 | version, 60 | platform: 'linux', 61 | arch: 'x64', 62 | symbols: true, 63 | }); 64 | await sentryCli.execute(['upload-dif', '-t', 'breakpad', zipPath], true); 65 | 66 | console.log('Finished downloading and uploading to Sentry'); 67 | console.log(`Feel free to delete the ${SYMBOL_CACHE_FOLDER}`); 68 | } 69 | 70 | function getElectronVersion() { 71 | if (!package) { 72 | return false; 73 | } 74 | 75 | let electronVersion = 76 | (package.dependencies && package.dependencies.electron) || 77 | (package.devDependencies && package.devDependencies.electron); 78 | 79 | if (!electronVersion) { 80 | return false; 81 | } 82 | 83 | const matches = VERSION.exec(electronVersion); 84 | return matches ? matches[0] : false; 85 | } 86 | 87 | async function downloadSymbols(options) { 88 | return new Promise((resolve, reject) => { 89 | download( 90 | { 91 | ...options, 92 | cache: SYMBOL_CACHE_FOLDER, 93 | }, 94 | (err, zipPath) => { 95 | if (err) { 96 | reject(err); 97 | } else { 98 | resolve(zipPath); 99 | } 100 | }, 101 | ); 102 | }); 103 | } 104 | 105 | main().catch(e => console.error(e)); 106 | -------------------------------------------------------------------------------- /src/app/App.css: -------------------------------------------------------------------------------- 1 | 2 | .AppContent { 3 | display: flex; 4 | flex-direction: row; 5 | justify-content: space-between; 6 | height: 100vh; 7 | overflow-y: auto; 8 | } 9 | 10 | .alignment { 11 | width: 550px; 12 | height: 200px; 13 | } 14 | 15 | .alignment + .alignment { 16 | margin-left: 10px; 17 | } 18 | 19 | .Resizer { 20 | background: #000; 21 | opacity: .2; 22 | z-index: 1; 23 | -moz-box-sizing: border-box; 24 | -webkit-box-sizing: border-box; 25 | box-sizing: border-box; 26 | -moz-background-clip: padding; 27 | -webkit-background-clip: padding; 28 | background-clip: padding-box; 29 | } 30 | 31 | .Resizer:hover { 32 | -webkit-transition: all 2s ease; 33 | transition: all 2s ease; 34 | } 35 | 36 | .Resizer.horizontal { 37 | height: 11px; 38 | margin: -5px 0; 39 | border-top: 5px solid rgba(255, 255, 255, 0); 40 | border-bottom: 5px solid rgba(255, 255, 255, 0); 41 | cursor: row-resize; 42 | width: 100%; 43 | } 44 | 45 | .Resizer.horizontal:hover { 46 | border-top: 5px solid rgba(0, 0, 0, 0.5); 47 | border-bottom: 5px solid rgba(0, 0, 0, 0.5); 48 | } 49 | 50 | .Resizer.vertical { 51 | width: 11px; 52 | margin: 0 -5px; 53 | border-left: 5px solid rgba(255, 255, 255, 0); 54 | border-right: 5px solid rgba(255, 255, 255, 0); 55 | cursor: col-resize; 56 | } 57 | 58 | .Resizer.vertical:hover { 59 | border-left: 5px solid rgba(0, 0, 0, 0.5); 60 | border-right: 5px solid rgba(0, 0, 0, 0.5); 61 | } 62 | .Resizer.disabled { 63 | cursor: not-allowed; 64 | } 65 | .Resizer.disabled:hover { 66 | border-color: transparent; 67 | } 68 | -------------------------------------------------------------------------------- /src/app/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | }); 9 | -------------------------------------------------------------------------------- /src/app/AstralTreeCard.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { observer } from 'mobx-react'; 3 | import PropTypes from 'prop-types'; 4 | import { makeStyles } from '@mui/styles'; 5 | import IconButton from '@mui/material/IconButton'; 6 | import MoreVertIcon from '@mui/icons-material/MoreVert'; 7 | import DeleteForeverIcon from '@mui/icons-material/DeleteForever'; 8 | import classNames from 'classnames'; 9 | import CircularProgress from '@mui/material/CircularProgress'; 10 | import Chip from '@mui/material/Chip'; 11 | import Menu from '@mui/material/Menu'; 12 | import MenuItem from '@mui/material/MenuItem'; 13 | import Tooltip from '@mui/material/Tooltip'; 14 | import Card from '@mui/material/Card'; 15 | import CardHeader from '@mui/material/CardHeader'; 16 | import CardContent from '@mui/material/CardContent'; 17 | import CardActions from '@mui/material/CardActions'; 18 | import Box from '@mui/material/Box'; 19 | 20 | // const useStyles = makeStyles(theme => ({ 21 | const useStyles = makeStyles((theme) => { 22 | return { 23 | AstralTreeCard: { 24 | backgroundColor: theme.palette.input.light, 25 | border: `1px solid ${theme.palette.input.border}`, 26 | }, 27 | cardHeaderRoot: { 28 | overflow: "hidden" 29 | }, 30 | cardHeaderContent: { 31 | overflow: "hidden" 32 | }, 33 | content: { 34 | display: 'flex', 35 | alignItems: 'center', 36 | marginLeft: '-10px', 37 | }, 38 | chip: { 39 | height: '30px', 40 | color: theme.palette.input.contrastText, 41 | backgroundColor: theme.palette.input.main, 42 | border: `1px solid ${theme.palette.input.darker}`, 43 | }, 44 | }; 45 | }); 46 | 47 | function AstralTreeCard({ className, astralTree }) { 48 | const { } = astralTree; 49 | 50 | const classes = useStyles(); 51 | const [anchorEl, setAnchorEl] = React.useState(null); 52 | 53 | function handleMenuClick(event) { 54 | setAnchorEl(event.currentTarget); 55 | } 56 | 57 | function handleMenuClose() { 58 | setAnchorEl(null); 59 | } 60 | 61 | function closeMenuAndRun(callback) { 62 | return () => { 63 | callback(); 64 | setAnchorEl(null); 65 | }; 66 | } 67 | 68 | const Content = ( 69 |
70 |
71 | 72 | 73 | 74 |
75 |
76 | ); 77 | 78 | return ( 79 | 80 | 91 | } 92 | action={ 93 |
94 | 95 | 96 | 97 | 98 | 99 | 100 | 105 | 106 | 107 | 108 | 114 | 115 | Open input trees 116 | 117 | 118 | Show in folder 119 | 120 | 121 | Remove input trees 122 | 123 | 124 |
125 | } 126 | title={astralTree.filename} 127 | subheader={'Input trees'} 128 | style={{ paddingBottom: 4 }} 129 | /> 130 | {Content} 131 | 132 |
133 | ); 134 | } 135 | 136 | AstralTreeCard.propTypes = { 137 | astralTree: PropTypes.object.isRequired, 138 | className: PropTypes.string, 139 | }; 140 | 141 | const AstralTreeCardObserver = observer(AstralTreeCard); 142 | 143 | export default AstralTreeCardObserver; 144 | -------------------------------------------------------------------------------- /src/app/CitationModal.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { observer } from 'mobx-react'; 3 | import PropTypes from 'prop-types'; 4 | import { makeStyles } from '@mui/styles'; 5 | import Button from '@mui/material/Button'; 6 | import Card from '@mui/material/Card'; 7 | import CardContent from '@mui/material/CardContent'; 8 | import CardActions from '@mui/material/CardActions'; 9 | import Typography from '@mui/material/Typography'; 10 | import Box from '@mui/material/Box'; 11 | import ToggleButton from '@mui/material/ToggleButton'; 12 | import ToggleButtonGroup from '@mui/material/ToggleButtonGroup'; 13 | 14 | import CodeHighlight from './components/CodeHighlight'; 15 | 16 | const useStyles = makeStyles(theme => ({ 17 | CitationModal: { 18 | backgroundColor: theme.palette.output.background, 19 | display: 'flex', 20 | flexDirection: 'column', 21 | alignItems: 'center', 22 | maxWidth: '700px' 23 | }, 24 | content: { 25 | maxHeight: '600px', 26 | overflowY: 'auto' 27 | }, 28 | code: { 29 | backgroundColor: theme.palette.console.background, 30 | borderRadius: '4px', 31 | padding: '4px' 32 | } 33 | })); 34 | 35 | function CitationModal({ citation }) { 36 | const classes = useStyles(); 37 | 38 | return ( 39 | 40 | 41 | How to cite? 42 | 43 | Please include the following references in your preferred format: 44 | 45 | 46 | citation.setFormat(format)} 50 | aria-label="text format" 51 | size="small" 52 | > 53 | {citation.formats.map(format => ( 54 | 59 | {format.name} 60 | 61 | ))} 62 | 63 | 64 | {citation.content.map(article => ( 65 | 66 | {article.name} 67 | 72 | 73 | ))} 74 | 75 | 76 | 77 | 86 | 89 | 90 | 91 | 92 | ); 93 | } 94 | 95 | CitationModal.propTypes = { 96 | citation: PropTypes.object.isRequired 97 | }; 98 | 99 | export default observer(CitationModal); 100 | -------------------------------------------------------------------------------- /src/app/Console.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { observer } from 'mobx-react'; 3 | import PropTypes from 'prop-types'; 4 | import { withStyles } from '@mui/styles'; 5 | import clsx from 'clsx'; 6 | 7 | 8 | const styles = theme => ({ 9 | Console: { 10 | color: theme.palette.console.contrastText, 11 | background: theme.palette.console.background, 12 | // flexGrow: 1, 13 | // padding: '0 4px', 14 | padding: '10px', 15 | width: '100% ', 16 | height: '100%', 17 | }, 18 | stdoutContainer: { 19 | overflowY: 'auto', 20 | height: '100%', 21 | position: 'relative', 22 | }, 23 | code: { 24 | color: theme.palette.console.contrastText, 25 | fontFamily: 'Consolas, "Liberation Mono", Menlo, Courier, monospace', 26 | fontSize: '12px', 27 | height: '100%', 28 | position: 'absolute', 29 | width: '100%', 30 | // overflowWrap: 'anywhere', // currently not available in Chrome 31 | whiteSpace: 'pre-wrap', 32 | wordBreak: 'break-all', 33 | } 34 | }); 35 | 36 | @observer 37 | class Console extends React.Component { 38 | keepToBottom = true; 39 | 40 | onMountStdoutContainer = el => { 41 | this.stdoutContainer = el; 42 | }; 43 | 44 | componentDidUpdate() { 45 | if (this.keepToBottom) { 46 | this.scrollConsoleToBottom(); 47 | } 48 | } 49 | 50 | isAtBottom = () => { 51 | const { scrollTop, scrollHeight, clientHeight } = this.stdoutContainer; 52 | const diff = scrollHeight - clientHeight; 53 | const scrollIsAtBottom = scrollTop === diff; 54 | return scrollIsAtBottom; 55 | }; 56 | 57 | scrollConsoleToBottom = () => { 58 | const { scrollHeight, clientHeight } = this.stdoutContainer; 59 | const diff = scrollHeight - clientHeight; 60 | this.stdoutContainer.scrollTop = diff; 61 | }; 62 | 63 | render() { 64 | const { run, classes } = this.props; 65 | return ( 66 |
70 |
71 | {run.stdout && {run.stdout}} 72 | {run.stderr && {run.stderr}} 73 |
74 |
75 | ); 76 | } 77 | } 78 | 79 | Console.propTypes = { 80 | run: PropTypes.object.isRequired 81 | }; 82 | 83 | export default withStyles(styles)(Console); 84 | -------------------------------------------------------------------------------- /src/app/Model.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { observer } from 'mobx-react'; 3 | import PropTypes from 'prop-types'; 4 | import { makeStyles } from '@mui/styles'; 5 | import Box from '@mui/material/Box'; 6 | import OptionSelect from './components/OptionSelect'; 7 | import OptionCheck from './components/OptionCheck'; 8 | import TextField from '@mui/material/TextField'; 9 | import Typography from '@mui/material/Typography'; 10 | 11 | const useStyles = makeStyles(theme => ({ 12 | Model: { 13 | padding: '10px', 14 | display: 'flex', 15 | flexDirection: 'column', 16 | }, 17 | form: { 18 | '& > *': { 19 | marginRight: '10px', 20 | } 21 | }, 22 | })); 23 | 24 | const Model = ({ run }) => { 25 | 26 | const classes = useStyles(); 27 | 28 | // TODO: Check marginTop: 2 hack, doesn't seem exactly aligned to top 29 | if (run.usesModeltestNg) { 30 | return ( 31 |
32 | 33 | Select the best-fit model of evolution for a single DNA or protein 34 | alignment 35 | 36 |
37 | ); 38 | } 39 | if (run.usesAstral) { 40 | return ( 41 |
42 | 43 | Calculate species tree from a set of gene trees 44 | 45 |
46 | ); 47 | } 48 | return ( 49 |
50 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 79 | 80 | {run.haveRandomSeed ? ( 81 | run.setRandomSeed(e.target.value)} /> 88 | ) : null} 89 | 90 | 100 | 101 | 102 | 103 | 113 | 114 | 115 | 116 | 117 | 118 | 119 |
120 | ); 121 | }; 122 | 123 | 124 | Model.propTypes = { 125 | run: PropTypes.object.isRequired, 126 | }; 127 | 128 | export default observer(Model); 129 | -------------------------------------------------------------------------------- /src/app/Output.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { observer } from 'mobx-react'; 3 | import PropTypes from 'prop-types'; 4 | import { makeStyles } from '@mui/styles'; 5 | import Box from '@mui/material/Box'; 6 | import TextField from '@mui/material/TextField'; 7 | import Button from '@mui/material/Button'; 8 | import { Link, Typography } from '@mui/material'; 9 | import FileIcon from '@mui/icons-material/InsertDriveFileSharp'; 10 | import { join } from 'path'; 11 | 12 | const useStyles = makeStyles((theme) => ({ 13 | Output: { 14 | width: '100%', 15 | padding: '10px', 16 | }, 17 | form: { 18 | width: '100%', 19 | '& > *:not(:first-child)': { 20 | marginTop: theme.spacing(3), 21 | }, 22 | }, 23 | formItem: {}, 24 | result: { 25 | // maxHeight: 200, 26 | // overflowY: 'auto', 27 | }, 28 | resultFilenameRow: { 29 | color: theme.palette.primary.contrastText, 30 | display: 'flex', 31 | alignItems: 'flex-end', 32 | cursor: 'pointer', 33 | }, 34 | resultFilename: { 35 | color: theme.palette.primary.contrastText, 36 | }, 37 | })); 38 | 39 | const Output = ({ run }) => { 40 | 41 | const classes = useStyles(); 42 | 43 | const { resultFilenames } = run; 44 | const haveResult = resultFilenames.length > 0; 45 | 46 | return ( 47 | (
48 | 49 | 62 | run.setOutputName(e.target.value)} 70 | error={!run.outputNameOk} /> 71 | 72 | 73 | { haveResult ? Result for output id '{run.outputName}' : null } 74 | { resultFilenames.map(filename => 75 | run.openFile(join(run.outputDir, filename))} 79 | underline="hover"> 80 | 81 | {filename} 82 | 83 | )} 84 | 85 | { run.haveAlignments || haveResult ? ( 86 | 87 | 88 | 89 | ) : null } 90 |
) 91 | ); 92 | }; 93 | 94 | Output.propTypes = { 95 | run: PropTypes.object.isRequired, 96 | }; 97 | 98 | export default observer(Output); 99 | -------------------------------------------------------------------------------- /src/app/PartitionFileCard.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { observer } from 'mobx-react'; 3 | import PropTypes from 'prop-types'; 4 | import { makeStyles } from '@mui/styles'; 5 | import DeleteForeverIcon from '@mui/icons-material/DeleteForever'; 6 | import classNames from 'classnames'; 7 | import Chip from '@mui/material/Chip'; 8 | import Card from '@mui/material/Card'; 9 | import CardHeader from '@mui/material/CardHeader'; 10 | import CardContent from '@mui/material/CardContent'; 11 | 12 | // const useStyles = makeStyles(theme => ({ 13 | const useStyles = makeStyles((theme) => { 14 | return { 15 | PartitionFileCard: { 16 | backgroundColor: theme.palette.input.light, 17 | border: `1px solid ${theme.palette.input.border}`, 18 | height: '200px', 19 | display: 'flex', 20 | flexDirection: 'column', 21 | }, 22 | chip: { 23 | height: '30px', 24 | color: theme.palette.input.contrastText, 25 | backgroundColor: theme.palette.input.main, 26 | border: `1px solid ${theme.palette.input.darker}`, 27 | }, 28 | deleteChip: { 29 | backgroundColor: 'transparent', 30 | border: 'none', 31 | marginRight: -5, 32 | }, 33 | deleteChipIcon: { 34 | opacity: 1, 35 | }, 36 | partitionFileContainer: { 37 | overflowY: 'auto', 38 | height: '150px', 39 | }, 40 | partitionFileContent: { 41 | color: theme.palette.primary.contrastText, 42 | fontFamily: 'Consolas, "Liberation Mono", Menlo, Courier, monospace', 43 | fontSize: '12px', 44 | height: '100%', 45 | overflowWrap: 'break-word', 46 | whiteSpace: 'pre-wrap', 47 | }, 48 | path: { 49 | cursor: 'pointer', 50 | color: theme.palette.secondary.main, 51 | marginLeft: 4, 52 | }, 53 | }; 54 | }); 55 | 56 | 57 | function PartitionFileCard({ className, run }) { 58 | const classes = useStyles(); 59 | 60 | if (!run.havePartitionFile) { 61 | return null; 62 | } 63 | 64 | return ( 65 | 66 | 73 | } 74 | action={ 75 |
76 | } 82 | onDelete={run.removePartitionFile} 83 | title="Remove partition" 84 | /> 85 |
86 | } 87 | title={run.partitionFileName} 88 | style={{ paddingBottom: 4 }} 89 | /> 90 | 91 |
92 | 93 | { run.partitionFileContent } 94 | 95 |
96 |
97 |
98 | ); 99 | } 100 | 101 | PartitionFileCard.propTypes = { 102 | run: PropTypes.object.isRequired, 103 | className: PropTypes.string, 104 | }; 105 | 106 | const PartitionFileCardObserver = observer(PartitionFileCard); 107 | 108 | export default PartitionFileCardObserver; 109 | -------------------------------------------------------------------------------- /src/app/Raxml.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { clipboard } from 'electron'; 3 | import { observer } from 'mobx-react'; 4 | import PropTypes from 'prop-types'; 5 | import Button from '@mui/material/Button'; 6 | import { withStyles } from '@mui/styles'; 7 | import OptionSelect from './components/OptionSelect'; 8 | import Box from '@mui/material/Box'; 9 | import Typography from '@mui/material/Typography'; 10 | import Tooltip from '@mui/material/Tooltip'; 11 | import IconButton from '@mui/material/IconButton'; 12 | import FileCopyIcon from '@mui/icons-material/FileCopy'; 13 | import { FormHelperText } from '@mui/material'; 14 | 15 | const styles = (theme) => ({ 16 | Raxml: { 17 | padding: '10px', 18 | width: '100%', 19 | flexShrink: 0, 20 | }, 21 | form: { 22 | // '& > *:not(:first-child)': { 23 | '& > *+*': { 24 | marginLeft: '20px', 25 | }, 26 | }, 27 | formItem: { 28 | // marginRight: '20px', 29 | }, 30 | button: { 31 | marginRight: theme.spacing(1), 32 | }, 33 | run: { 34 | marginTop: '20px', 35 | display: 'flex', 36 | alignItems: 'center', 37 | }, 38 | code: { 39 | color: theme.palette.console.contrastText, 40 | fontFamily: 'Consolas, "Liberation Mono", Menlo, Courier, monospace', 41 | fontSize: '12px', 42 | height: '100%', 43 | width: '100%', 44 | // overflowWrap: 'anywhere', // currently not available in Chrome 45 | whiteSpace: 'pre-wrap', 46 | wordBreak: 'break-all', 47 | }, 48 | }); 49 | 50 | @observer 51 | class Raxml extends React.Component { 52 | copyCommand = () => { 53 | const { run, store } = this.props; 54 | clipboard.writeText(run.command); 55 | store.setAppSnack(); 56 | }; 57 | 58 | render() { 59 | const { classes, run } = this.props; 60 | 61 | return ( 62 |
63 | 73 | 74 | 75 | {run.modelTestIsRunningOnAlignment ? ( 76 | 83 | ) : null} 84 | {run.running ? ( 85 | 88 | ) : null} 89 | 99 | 100 | 101 | 102 | 103 | 104 | 109 | 110 | 111 | 112 | {run.command} 113 | 114 | Command 115 | 116 |
117 | ); 118 | } 119 | } 120 | 121 | Raxml.propTypes = { 122 | classes: PropTypes.object.isRequired, 123 | run: PropTypes.object.isRequired, 124 | }; 125 | 126 | export default withStyles(styles)(Raxml); 127 | -------------------------------------------------------------------------------- /src/app/TreeCard.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { observer } from 'mobx-react'; 3 | import PropTypes from 'prop-types'; 4 | import { makeStyles } from '@mui/styles'; 5 | import IconButton from '@mui/material/IconButton'; 6 | import MoreVertIcon from '@mui/icons-material/MoreVert'; 7 | import classNames from 'classnames'; 8 | import CircularProgress from "@mui/material/CircularProgress"; 9 | import Chip from "@mui/material/Chip"; 10 | import Menu from '@mui/material/Menu'; 11 | import MenuItem from '@mui/material/MenuItem'; 12 | import Card from '@mui/material/Card'; 13 | import CardHeader from '@mui/material/CardHeader'; 14 | import CardContent from '@mui/material/CardContent'; 15 | 16 | const useStyles = makeStyles(theme => ({ 17 | TreeCard: { 18 | backgroundColor: theme.palette.input.main, 19 | border: `1px solid ${theme.palette.input.light}`, 20 | }, 21 | heading: { 22 | display: 'flex', 23 | alignItems: 'center', 24 | }, 25 | content: { 26 | display: 'flex', 27 | alignItems: 'center', 28 | }, 29 | name: { 30 | marginRight: theme.spacing(1), 31 | }, 32 | chip: { 33 | height: '30px', 34 | backgroundColor: theme.palette.input.dark, 35 | border: `1px solid ${theme.palette.input.light}`, 36 | }, 37 | link: { 38 | cursor: 'pointer', 39 | color: theme.palette.secondary.main 40 | }, 41 | secondaryText: { 42 | color: theme.palette.input.secondaryText, 43 | }, 44 | divider: { 45 | margin: '0 4px', 46 | }, 47 | fileInfo: { 48 | color: '#ccc', 49 | fontSize: '0.75em', 50 | marginTop: '0.25em', 51 | overflowWrap: 'break-word', 52 | }, 53 | path: { 54 | cursor: 'pointer', 55 | color: theme.palette.secondary.main, 56 | marginLeft: 4, 57 | }, 58 | button: { 59 | margin: theme.spacing(1), 60 | }, 61 | rightIcon: { 62 | marginLeft: theme.spacing(1), 63 | }, 64 | iconSmall: { 65 | fontSize: 20, 66 | }, 67 | outputButton: { 68 | marginLeft: theme.spacing(1), 69 | }, 70 | loading: { 71 | marginLeft: '10px', 72 | }, 73 | remove: { 74 | flexGrow: 1, 75 | display: 'flex', 76 | justifyContent: 'flex-end', 77 | } 78 | 79 | })); 80 | 81 | function TreeCard({ className, tree }) { 82 | 83 | const classes = useStyles(); 84 | const [anchorEl, setAnchorEl] = React.useState(null); 85 | 86 | function handleMenuClick(event) { 87 | setAnchorEl(event.currentTarget); 88 | } 89 | 90 | function handleMenuClose() { 91 | setAnchorEl(null); 92 | } 93 | 94 | function closeMenuAndRun(callback) { 95 | return () => { 96 | callback(); 97 | setAnchorEl(null); 98 | } 99 | } 100 | 101 | return ( 102 | 103 | 106 | } 107 | action={ 108 |
109 | 114 | 115 | 116 | 117 | 118 | Show tree 119 | Show folder 120 | Remove 121 | 122 |
123 | } 124 | title={ tree.name } 125 | subheader={ '' } 126 | /> 127 |
128 | { tree.loading ? ( 129 |
130 | 131 |
132 | ) : null } 133 |
134 | 135 | 136 |
137 | ); 138 | }; 139 | // {tree.name} 140 | 141 | 142 | TreeCard.propTypes = { 143 | tree: PropTypes.object.isRequired, 144 | className: PropTypes.string, 145 | }; 146 | 147 | export default observer(TreeCard); 148 | -------------------------------------------------------------------------------- /src/app/bootstrap.js: -------------------------------------------------------------------------------- 1 | import { ipcRenderer } from 'electron'; 2 | import * as ipc from '../constants/ipc'; 3 | import store from './store'; 4 | import path from 'path'; 5 | 6 | if (process.env.NODE_ENV === 'development') { 7 | console.log('\n========= Bootstrapping initial state... =========\n'); 8 | ipcRenderer.send(ipc.ALIGNMENT_EXAMPLE_FILES_GET_REQUEST); 9 | } 10 | 11 | ipcRenderer.on(ipc.ALIGNMENT_EXAMPLE_FILES_GET_SUCCESS, (event, exampleFiles) => { 12 | initDev(exampleFiles); 13 | }); 14 | 15 | function initDev(exampleFiles) { 16 | // if (exampleFiles.length === 0) { 17 | // return; 18 | // } 19 | // const exampleFilesDir = path.dirname(exampleFiles[0].path); 20 | const exampleFilesDir = exampleFiles.dir; 21 | // const useFiles = exampleFiles.filter(file => exampleFilenames.includes(file.name)); 22 | const useFastaFiles = [ 23 | // 'aminoacid.txt', 24 | // 'bin1.txt', 25 | // 'bin2.txt', 26 | // 'binary.txt', 27 | // 'dna.txt', 28 | // 'mixed_data.txt', 29 | // 'multistate.txt', 30 | 'nucleotide.txt', 31 | ].map(filename => ({ path: path.join(exampleFilesDir, 'fasta', filename) })); 32 | const usePhylipFiles = [ 33 | // 'AA.txt', 34 | // 'align_allvariant.txt', 35 | // 'aminoacid.txt', 36 | // 'binary.txt', 37 | // 'dna_interleaved_relaxed.txt', 38 | // 'dna_interleaved.txt', 39 | // 'dna_sequential_relaxed.txt', 40 | // 'dna_sequential.txt', 41 | // 'mixed_data.txt', 42 | // 'multistate.txt', 43 | // 'nucleotide.txt', 44 | // 'fail_duplicate_taxon.txt', 45 | // 'fail_bad_base_at_site.txt', 46 | // 'fail_bad_name.txt', 47 | // 'test_invariant_sites.txt', 48 | // 'test_lower_case_bases.txt', 49 | ].map(filename => ({ path: path.join(exampleFilesDir, 'phylip', filename) })); 50 | const useFiles = [].concat(useFastaFiles, usePhylipFiles); 51 | store.activeRun.addAlignments(useFiles); 52 | store.activeRun.setOutputDir(exampleFiles.outdir); 53 | setTimeout(() => { 54 | // store.activeRun.alignments[0].setShowPartition(); 55 | // store.citation.show(); 56 | }, 1000); 57 | } 58 | -------------------------------------------------------------------------------- /src/app/components/CodeHighlight.js: -------------------------------------------------------------------------------- 1 | import React, { useRef, useEffect } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { makeStyles } from '@mui/styles'; 4 | import Prism from 'prismjs'; 5 | import 'prismjs-bibtex'; 6 | import 'prismjs/themes/prism.css'; 7 | import 'prismjs/themes/prism-okaidia.css'; // coy, dark, funky, okaidia, solarizedlight, tomorrow, twilight 8 | 9 | const useStyles = makeStyles(() => ({ 10 | code: { 11 | fontSize: 10, 12 | overflowWrap: 'break-word', 13 | whiteSpace: 'pre-wrap', 14 | } 15 | })); 16 | 17 | function CodeHighlight({ code, language, className }) { 18 | const codeNode = useRef(null); 19 | const classes = useStyles(); 20 | 21 | useEffect(() => { 22 | // const code = codeNode.current.textContent; 23 | if (Prism.languages.hasOwnProperty(language)) { 24 | const highlightHTML = Prism.highlight(code, Prism.languages[language], language); 25 | codeNode.current.innerHTML = highlightHTML; 26 | } 27 | }, [code, language]); 28 | 29 | return ( 30 |
31 |       
32 |         { code }
33 |       
34 |     
35 | ); 36 | } 37 | 38 | CodeHighlight.propTypes = { 39 | code: PropTypes.string.isRequired, 40 | language: PropTypes.string.isRequired, 41 | className: PropTypes.string, 42 | }; 43 | 44 | export default CodeHighlight; 45 | -------------------------------------------------------------------------------- /src/app/components/ErrorBoundary.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Box } from '@mui/material'; 3 | import Typography from '@mui/material/Typography'; 4 | import ErrorDialog from './ErrorDialog'; 5 | 6 | class ErrorBoundary extends React.Component { 7 | constructor(props) { 8 | super(props); 9 | 10 | this.state = { 11 | error: null, 12 | }; 13 | } 14 | 15 | static getDerivedStateFromError(error) { 16 | return { error }; 17 | } 18 | 19 | componentDidCatch(error, info) { 20 | console.log('Error catched at React boundary:', error, info); 21 | } 22 | 23 | handleClose = () => { 24 | this.setState({ error: null }); 25 | } 26 | 27 | render() { 28 | const { error } = this.state; 29 | // const error = new Error(`Minified React error #31; visit https://reactjs.org/docs/error-decoder.html?invariant=31&args[]=object%20with%20keys%20%7Bcmd%2C%20code%2C%20killed%2C%20message%2C%20name%2C%20signal%2C%20stack%2C%20stderr%2C%20stdout%7D&args[]= for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`); 30 | if (!error) { 31 | return this.props.children; 32 | } 33 | 34 | return ( 35 | 36 | 37 | Oops! Something went wrong. 38 | 39 | 40 | 41 | ); 42 | } 43 | } 44 | 45 | export default ErrorBoundary; 46 | -------------------------------------------------------------------------------- /src/app/components/ErrorDialog.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Box } from '@mui/material'; 4 | import Dialog from '@mui/material/Dialog'; 5 | import DialogTitle from '@mui/material/DialogTitle'; 6 | import DialogContent from '@mui/material/DialogContent'; 7 | import DialogActions from '@mui/material/DialogActions'; 8 | import DialogContentText from '@mui/material/DialogContentText'; 9 | import Accordion from '@mui/material/Accordion'; 10 | import AccordionSummary from '@mui/material/AccordionSummary'; 11 | import AccordionDetails from '@mui/material/AccordionDetails'; 12 | import Typography from '@mui/material/Typography'; 13 | import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; 14 | import Button from '@mui/material/Button'; 15 | import Alert from '@mui/material/Alert'; 16 | import { ipcRenderer } from 'electron'; 17 | import { reportIssueToGitHub, getMailtoLinkToReportError } from '../../common/utils'; 18 | import * as ipc from '../../constants/ipc'; 19 | 20 | const handleReload = () => { 21 | ipcRenderer.send(ipc.RELOAD); 22 | } 23 | 24 | export default function ErrorDialog({ error, onClose, needReload, title }) { 25 | const [reported, setReported] = React.useState(false); 26 | 27 | if (!error) { 28 | return null; 29 | } 30 | 31 | const handleReportToGithub = () => { 32 | reportIssueToGitHub(error); 33 | setReported(true); 34 | } 35 | 36 | const handleReportToMail = () => { 37 | setReported(true); 38 | } 39 | 40 | const mailtoContent = getMailtoLinkToReportError(error); 41 | 42 | const closeMessage = needReload ? ( 43 | reported ? 'Reload' : 'Ignore and reload' 44 | ) : 'Close'; 45 | 46 | const resetAndClose = () => { 47 | setReported(false); 48 | onClose(); 49 | }; 50 | 51 | const closeHandler = needReload ? handleReload : resetAndClose; 52 | 53 | const CloseAction = ( 54 | 55 | 58 | 59 | ); 60 | 61 | const Actions = reported ? ( 62 | CloseAction 63 | ) : ( 64 | 65 | 74 | 82 | 85 | 86 | ); 87 | 88 | const Message = !reported ? ( 89 | 90 | Please help us solve the issue by reporting it. 91 | 92 | ) : ( 93 | 97 | Thanks for reporting the issue! 98 | 99 | ); 100 | 101 | const GenericErrorDialog = ( 102 | 107 | 108 | {title || 'Unexpected error'} 109 | 110 | 111 | 112 | 113 | } 115 | aria-controls="error-panel-content" 116 | id="error-panel-header" 117 | > 118 | Details 119 | 120 | 121 | 122 | {error.name} 123 | 127 | {error.message} 128 | 129 | 130 | 131 | 132 | 133 | {Message} 134 | 135 | {Actions} 136 | 137 | ); 138 | 139 | const UserFixErrorDialog = ( 140 | 145 | {title || 'Error'} 146 | 147 | { 148 | 'RaxmlGUI2 encountered an error that you need to fix before you can continue.' 149 | } 150 | 151 | {error.message} 152 | 153 | 154 | {CloseAction} 155 | 156 | ); 157 | 158 | let returnDialog = GenericErrorDialog; 159 | if (error.isUserFix) { 160 | returnDialog = UserFixErrorDialog; 161 | } 162 | 163 | return returnDialog; 164 | } 165 | 166 | ErrorDialog.propTypes = { 167 | error: PropTypes.object, 168 | onClose: PropTypes.func.isRequired, 169 | needReload: PropTypes.bool, 170 | title: PropTypes.string, 171 | } 172 | -------------------------------------------------------------------------------- /src/app/components/ModifiedDialog.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Box } from '@mui/material'; 4 | import Dialog from '@mui/material/Dialog'; 5 | import DialogTitle from '@mui/material/DialogTitle'; 6 | import DialogContent from '@mui/material/DialogContent'; 7 | import DialogActions from '@mui/material/DialogActions'; 8 | import DialogContentText from '@mui/material/DialogContentText'; 9 | import Accordion from '@mui/material/Accordion'; 10 | import AccordionSummary from '@mui/material/AccordionSummary'; 11 | import AccordionDetails from '@mui/material/AccordionDetails'; 12 | import Typography from '@mui/material/Typography'; 13 | import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; 14 | import Button from '@mui/material/Button'; 15 | 16 | export default function ModifiedDialog({ show, onClose, messages }) { 17 | if (!show) { 18 | return null; 19 | } 20 | 21 | const GenericDialog = ( 22 | 23 | {'Attention'} 24 | 25 | {'This will be using a copy of your input file, because there were some issues!'} 26 | 27 | 28 | } 30 | aria-controls="error-panel-content" 31 | id="error-panel-header" 32 | > 33 | Details 34 | 35 | 36 | 37 | {messages.map((message) => ( 38 | 39 | {message} 40 | 41 | ))} 42 | 43 | 44 | 45 | 46 | 47 | 48 | 51 | 52 | 53 | ); 54 | 55 | let returnDialog = GenericDialog; 56 | return returnDialog; 57 | } 58 | 59 | ModifiedDialog.propTypes = { 60 | error: PropTypes.object, 61 | onClose: PropTypes.func.isRequired, 62 | } 63 | -------------------------------------------------------------------------------- /src/app/components/OptionCheck.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { observer } from 'mobx-react'; 3 | import PropTypes from 'prop-types'; 4 | import FormControlLabel from '@mui/material/FormControlLabel'; 5 | import Checkbox from '@mui/material/Checkbox'; 6 | import { FormControl } from '@mui/material'; 7 | 8 | 9 | const OptionCheck = observer(({ option, className }) => { 10 | if (option.notAvailable) { 11 | return null; 12 | } 13 | return ( 14 | 15 | option.setValue(e.target.checked)} 21 | value={option.title} 22 | color="primary" 23 | /> 24 | } 25 | label={option.title} 26 | /> 27 | 28 | ); 29 | }); 30 | 31 | OptionCheck.propTypes = { 32 | option: PropTypes.object.isRequired, 33 | className: PropTypes.string, 34 | }; 35 | 36 | export default OptionCheck; 37 | -------------------------------------------------------------------------------- /src/app/components/OptionSelect.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { observer } from 'mobx-react'; 3 | import PropTypes from 'prop-types'; 4 | import FormControl from '@mui/material/FormControl'; 5 | import FormHelperText from '@mui/material/FormHelperText'; 6 | import Select from '@mui/material/Select'; 7 | import MenuItem from '@mui/material/MenuItem'; 8 | import TextField from '@mui/material/TextField'; 9 | 10 | 11 | const OptionSelect = observer(({ option, className }) => { 12 | if (option.notAvailable || option.options.length === 0) { 13 | return null; 14 | } 15 | if (option.options.length === 1) { 16 | // No options to change to, render as a text field instead. 17 | return ( 18 | () 31 | ); 32 | } 33 | 34 | return ( 35 | 36 | 51 | {option.title} 52 | 53 | ); 54 | }); 55 | 56 | OptionSelect.propTypes = { 57 | option: PropTypes.object.isRequired, 58 | className: PropTypes.string, 59 | }; 60 | 61 | export default OptionSelect; 62 | -------------------------------------------------------------------------------- /src/app/components/OptionTextField.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { observer } from 'mobx-react'; 3 | import PropTypes from 'prop-types'; 4 | import TextField from '@mui/material/TextField'; 5 | 6 | const OptionTextField = observer(({ option, className }) => { 7 | if (option.notAvailable) { 8 | return null; 9 | } 10 | return ( 11 | option.setValue(e.target.value)} 21 | error={option.haveError} /> 22 | ); 23 | }); 24 | 25 | OptionTextField.propTypes = { 26 | option: PropTypes.object.isRequired, 27 | className: PropTypes.string, 28 | }; 29 | 30 | export default OptionTextField; 31 | -------------------------------------------------------------------------------- /src/app/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { observer } from 'mobx-react'; 3 | import { StyledEngineProvider, ThemeProvider } from '@mui/material/styles'; 4 | import * as Sentry from '@sentry/electron/renderer'; 5 | 6 | import theme from './theme'; 7 | import App from './App'; 8 | import ErrorBoundary from './components/ErrorBoundary'; 9 | import store from './store'; 10 | import { is } from '../common/utils'; 11 | 12 | import './bootstrap'; 13 | 14 | is.development ? null : Sentry.init({ 15 | dsn: 'https://d92efa46c2ba43f38250b202c791a2c2@o117148.ingest.sentry.io/6517975', 16 | }); 17 | 18 | const Index = () => { 19 | const { light, dark } = theme; 20 | const muiTheme = store.config.isDarkMode ? dark : light; 21 | return ( 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ); 30 | } 31 | 32 | export default observer(Index); 33 | 34 | -------------------------------------------------------------------------------- /src/app/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "experimentalDecorators": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/app/store/AppStore.js: -------------------------------------------------------------------------------- 1 | import { observable, computed, action } from 'mobx'; 2 | import StoreBase from './StoreBase'; 3 | import Citation from './Citation'; 4 | import Config from './Config'; 5 | 6 | class AppStore extends StoreBase { 7 | citation = new Citation(); 8 | config = new Config(); 9 | 10 | @observable version = undefined; 11 | 12 | @observable showAppSnack = false; 13 | 14 | @action setAppSnack = () => { 15 | this.showAppSnack = true; 16 | }; 17 | 18 | @action clearAppSnack = () => { 19 | this.showAppSnack = false; 20 | }; 21 | 22 | constructor() { 23 | super(); 24 | } 25 | } 26 | 27 | export default AppStore; 28 | -------------------------------------------------------------------------------- /src/app/store/AstralTree.js: -------------------------------------------------------------------------------- 1 | import { observable, computed, action, runInAction } from 'mobx'; 2 | 3 | import InputFile from './InputFile'; 4 | 5 | 6 | class AstralTree extends InputFile { 7 | constructor(run, path) { 8 | super(run, path); 9 | } 10 | 11 | @action 12 | remove = () => { 13 | this.run.removeAstralTree(); 14 | }; 15 | } 16 | 17 | export default AstralTree; -------------------------------------------------------------------------------- /src/app/store/Citation.js: -------------------------------------------------------------------------------- 1 | import { observable, action, computed } from 'mobx'; 2 | import { clipboard } from 'electron'; 3 | 4 | export default class Citation { 5 | @observable visible = false; 6 | 7 | formats = [ 8 | { value: 'txt', name: 'Plain text' }, 9 | { value: 'ris', name: 'RIS/EndNote' }, 10 | { value: 'bib', name: 'BibTeX' }, 11 | ]; 12 | 13 | @observable format = 'txt'; 14 | @action setFormat = (format) => { 15 | this.format = format; 16 | }; 17 | 18 | content = [ 19 | { 20 | name: 'raxmlGUI', 21 | bib: `@article{https://doi.org/10.1111/2041-210X.13512, 22 | author = {Edler, Daniel and Klein, Johannes and Antonelli, Alexandre and Silvestro, Daniele}, 23 | title = {raxmlGUI 2.0: A graphical interface and toolkit for phylogenetic analyses using RAxML}, 24 | journal = {Methods in Ecology and Evolution}, 25 | volume = {12}, 26 | number = {2}, 27 | pages = {373-377}, 28 | keywords = {bioinformatics, evolutionary biology, molecular biology, phylogenetics, software}, 29 | doi = {https://doi.org/10.1111/2041-210X.13512}, 30 | url = {https://besjournals.onlinelibrary.wiley.com/doi/abs/10.1111/2041-210X.13512}, 31 | eprint = {https://besjournals.onlinelibrary.wiley.com/doi/pdf/10.1111/2041-210X.13512}, 32 | year = {2021} 33 | }`, 34 | ris: ` 35 | TY - JOUR 36 | T1 - raxmlGUI 2.0: A graphical interface and toolkit for phylogenetic analyses using RAxML 37 | AU - Edler, Daniel 38 | AU - Klein, Johannes 39 | AU - Antonelli, Alexandre 40 | AU - Silvestro, Daniele 41 | Y1 - 2021/02/01 42 | PY - 2021 43 | DA - 2021/02/01 44 | N1 - https://doi.org/10.1111/2041-210X.13512 45 | DO - https://doi.org/10.1111/2041-210X.13512 46 | T2 - Methods in Ecology and Evolution 47 | JF - Methods in Ecology and Evolution 48 | JO - Methods in Ecology and Evolution 49 | JA - Methods Ecol Evol 50 | SP - 373 51 | EP - 377 52 | VL - 12 53 | IS - 2 54 | KW - bioinformatics 55 | KW - evolutionary biology 56 | KW - molecular biology 57 | KW - phylogenetics 58 | KW - software 59 | PB - John Wiley & Sons, Ltd 60 | SN - 2041-210X 61 | M3 - https://doi.org/10.1111/2041-210X.13512 62 | UR - https://doi.org/10.1111/2041-210X.13512 63 | Y2 - 2021/02/18 64 | ER - 65 | `, 66 | txt: `Edler, D, Klein, J, Antonelli, A, Silvestro, D. raxmlGUI 2.0: A graphical interface and toolkit for phylogenetic analyses using RAxML. Methods Ecol Evol. 2021; 12: 373– 377. https://doi.org/10.1111/2041-210X.13512`, 67 | }, 68 | { 69 | name: 'RAxML', 70 | bib: `@article{10.1093/bioinformatics/btu033, 71 | author = {Stamatakis, Alexandros}, 72 | title = "{RAxML version 8: a tool for phylogenetic analysis and post-analysis of large phylogenies}", 73 | journal = {Bioinformatics}, 74 | volume = {30}, 75 | number = {9}, 76 | pages = {1312-1313}, 77 | year = {2014}, 78 | month = {01}, 79 | issn = {1367-4803}, 80 | doi = {10.1093/bioinformatics/btu033}, 81 | url = {https://doi.org/10.1093/bioinformatics/btu033}, 82 | eprint = {http://oup.prod.sis.lan/bioinformatics/article-pdf/30/9/1312/17345185/btu033.pdf}, 83 | }`, 84 | ris: `Provider: Silverchair 85 | Database: Oxford University Press 86 | Content: text/plain; charset="UTF-8" 87 | 88 | TY - JOUR 89 | AU - Stamatakis, Alexandros 90 | T1 - RAxML version 8: a tool for phylogenetic analysis and post-analysis of large phylogenies 91 | T2 - Bioinformatics 92 | PY - 2014 93 | Y1 - 2014/01/21/ 94 | DO - 10.1093/bioinformatics/btu033 95 | JO - Bioinformatics 96 | JA - bioinformatics 97 | VL - 30 98 | IS - 9 99 | SP - 1312 100 | EP - 1313 101 | SN - 1367-4803 102 | Y2 - 10/17/2019 103 | UR - https://doi.org/10.1093/bioinformatics/btu033 104 | ER - `, 105 | txt: `Alexandros Stamatakis, RAxML version 8: a tool for phylogenetic analysis and post-analysis of large phylogenies, Bioinformatics, Volume 30, Issue 9, 1 May 2014, Pages 1312–1313, https://doi.org/10.1093/bioinformatics/btu033`, 106 | }, 107 | { 108 | name: 'RAxML-NG', 109 | bib: `@article{10.1093/bioinformatics/btz305, 110 | author = {Kozlov, Alexey M and Darriba, Diego and Flouri, Tomáš and Morel, Benoit and Stamatakis, Alexandros}, 111 | title = "{RAxML-NG: a fast, scalable and user-friendly tool for maximum likelihood phylogenetic inference}", 112 | journal = {Bioinformatics}, 113 | volume = {35}, 114 | number = {21}, 115 | pages = {4453-4455}, 116 | year = {2019}, 117 | month = {05}, 118 | issn = {1367-4803}, 119 | doi = {10.1093/bioinformatics/btz305}, 120 | url = {https://doi.org/10.1093/bioinformatics/btz305}, 121 | eprint = {https://academic.oup.com/bioinformatics/article-pdf/35/21/4453/30330793/btz305.pdf}, 122 | }`, 123 | ris: `Provider: Silverchair 124 | Database: Oxford University Press 125 | Content: text/plain; charset="UTF-8" 126 | 127 | TY - JOUR 128 | AU - Kozlov, Alexey M 129 | AU - Darriba, Diego 130 | AU - Flouri, Tomáš 131 | AU - Morel, Benoit 132 | AU - Stamatakis, Alexandros 133 | T1 - RAxML-NG: a fast, scalable and user-friendly tool for maximum likelihood phylogenetic inference 134 | PY - 2019 135 | Y1 - 2019/05/09/ 136 | DO - 10.1093/bioinformatics/btz305 137 | JO - Bioinformatics 138 | JA - Bioinformatics 139 | VL - 35 140 | IS - 21 141 | SP - 4453 142 | EP - 4455 143 | SN - 1367-4803 144 | Y2 - 7/17/2020 145 | UR - https://doi.org/10.1093/bioinformatics/btz305 146 | ER - `, 147 | txt: `Alexey M Kozlov, Diego Darriba, Tomáš Flouri, Benoit Morel, Alexandros Stamatakis, RAxML-NG: a fast, scalable and user-friendly tool for maximum likelihood phylogenetic inference, Bioinformatics, Volume 35, Issue 21, 1 November 2019, Pages 4453–4455, https://doi.org/10.1093/bioinformatics/btz305`, 148 | }, 149 | { 150 | name: 'ModelTest-NG', 151 | bib: `@article{10.1093/molbev/msz189, 152 | author = {Darriba, Diego and Posada, David and Kozlov, Alexey M and Stamatakis, Alexandros and Morel, Benoit and Flouri, Tomas}, 153 | title = "{ModelTest-NG: A New and Scalable Tool for the Selection of DNA and Protein Evolutionary Models}", 154 | journal = {Molecular Biology and Evolution}, 155 | volume = {37}, 156 | number = {1}, 157 | pages = {291-294}, 158 | year = {2019}, 159 | month = {08}, 160 | issn = {0737-4038}, 161 | doi = {10.1093/molbev/msz189}, 162 | url = {https://doi.org/10.1093/molbev/msz189}, 163 | eprint = {https://academic.oup.com/mbe/article-pdf/37/1/291/32085561/msz189.pdf}, 164 | }`, 165 | ris: `Provider: Silverchair 166 | Database: Oxford University Press 167 | Content: text/plain; charset="UTF-8" 168 | 169 | TY - JOUR 170 | AU - Darriba, Diego 171 | AU - Posada, David 172 | AU - Kozlov, Alexey M 173 | AU - Stamatakis, Alexandros 174 | AU - Morel, Benoit 175 | AU - Flouri, Tomas 176 | T1 - ModelTest-NG: A New and Scalable Tool for the Selection of DNA and Protein Evolutionary Models 177 | PY - 2020 178 | Y1 - 2020/01/01 179 | DO - 10.1093/molbev/msz189 180 | JO - Molecular Biology and Evolution 181 | JA - Mol Biol Evol 182 | VL - 37 183 | IS - 1 184 | SP - 291 185 | EP - 294 186 | SN - 0737-4038 187 | Y2 - 9/5/2020 188 | UR - https://doi.org/10.1093/molbev/msz189 189 | ER - `, 190 | txt: `Diego Darriba, David Posada, Alexey M Kozlov, Alexandros Stamatakis, Benoit Morel, Tomas Flouri, ModelTest-NG: A New and Scalable Tool for the Selection of DNA and Protein Evolutionary Models, Molecular Biology and Evolution, Volume 37, Issue 1, January 2020, Pages 291–294, https://doi.org/10.1093/molbev/msz189`, 191 | }, 192 | ]; 193 | 194 | @computed 195 | get allText() { 196 | return this.content.map((ref) => ref[this.format]).join('\n'); 197 | } 198 | 199 | @action 200 | show = () => { 201 | this.visible = true; 202 | }; 203 | @action 204 | hide = () => { 205 | this.visible = false; 206 | }; 207 | 208 | copyToClipboard = () => { 209 | clipboard.writeText(this.allText); 210 | console.log('Copied citation to clipboard'); 211 | }; 212 | } 213 | 214 | -------------------------------------------------------------------------------- /src/app/store/Config.js: -------------------------------------------------------------------------------- 1 | import { observable, action } from 'mobx'; 2 | import * as ipc from '../../constants/ipc'; 3 | import StoreBase from './StoreBase'; 4 | import Store from 'electron-store'; 5 | 6 | export const store = new Store(); 7 | 8 | export default class Config extends StoreBase { 9 | 10 | constructor() { 11 | super(); 12 | this.listen(); 13 | } 14 | 15 | @observable isDarkMode = store.get('darkMode') 16 | 17 | @action 18 | setDarkMode = value => { 19 | value = !!value; 20 | store.set('darkMode', value); 21 | this.isDarkMode = value; 22 | } 23 | 24 | onLightMode = () => { 25 | this.setDarkMode(false); 26 | } 27 | 28 | onDarkMode = () => { 29 | this.setDarkMode(true); 30 | } 31 | 32 | listen = () => { 33 | this.listenTo(ipc.LIGHT_MODE, this.onLightMode); 34 | this.listenTo(ipc.DARK_MODE, this.onDarkMode); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/app/store/InputFile.js: -------------------------------------------------------------------------------- 1 | import { observable, computed, action, runInAction } from 'mobx'; 2 | import { ipcRenderer } from 'electron'; 3 | import parsePath from 'parse-filepath'; 4 | 5 | import * as ipc from '../../constants/ipc'; 6 | import StoreBase from './StoreBase'; 7 | 8 | class InputFile extends StoreBase { 9 | run = null; 10 | 11 | constructor(run, path) { 12 | super(); 13 | this.run = run; 14 | this.path = path; 15 | } 16 | 17 | // Observable because it may change on correcting errors or reformating of alignments 18 | @observable path = ''; 19 | 20 | @computed 21 | get id() { 22 | return `${this.run.id}_${this.path}`; 23 | } 24 | 25 | @computed 26 | get name() { 27 | return parsePath(this.path).name; 28 | } 29 | 30 | @computed 31 | get dir() { 32 | return parsePath(this.path).dir; 33 | } 34 | 35 | @computed 36 | get base() { 37 | return parsePath(this.path).base; 38 | } 39 | 40 | @computed 41 | get filename() { 42 | return parsePath(this.path).base; 43 | } 44 | 45 | @computed 46 | get ok() { 47 | return this.path !== ''; 48 | } 49 | 50 | @action 51 | openFile = () => { 52 | ipcRenderer.send(ipc.FILE_OPEN, this.path); 53 | }; 54 | 55 | @action 56 | showFileInFolder = () => { 57 | ipcRenderer.send(ipc.FILE_SHOW_IN_FOLDER, this.path); 58 | }; 59 | } 60 | 61 | export default InputFile; -------------------------------------------------------------------------------- /src/app/store/Option.js: -------------------------------------------------------------------------------- 1 | import { observable, computed, action } from 'mobx'; 2 | import { mixed } from 'yup'; 3 | 4 | class Option { 5 | /** 6 | * Reactive option with optional validation 7 | * @param {Object} run 8 | * @param {*} defaultValue 9 | * @param {String} title 10 | * @param {String} description 11 | * @param {String} hoverInfo 12 | * @param {yup|undefined} schema 13 | */ 14 | constructor(run, defaultValue, title, description, hoverInfo, { 15 | schema = undefined, 16 | allowOnlyValidChange = false, 17 | helperText = '', 18 | } = {}) { 19 | this.run = run; 20 | this.defaultValue = defaultValue; 21 | this.title = title; 22 | this.description = description; 23 | this.hoverInfo = hoverInfo; 24 | this.schema = schema ? schema : mixed(); 25 | this.allowOnlyValidChange = allowOnlyValidChange; 26 | this.helperText = helperText; 27 | } 28 | @observable value = this.defaultValue; 29 | @action setValue = (value) => { 30 | const isValid = this.schema.isValidSync(value); 31 | if (!this.allowOnlyValidChange || isValid) { 32 | this.value = isValid ? this.schema.cast(value) : value; 33 | } 34 | } 35 | @action reset() { this.value = this.defaultValue; } 36 | @computed get isDefault() { return this.value === this.defaultValue; } 37 | @computed get error() { 38 | try { 39 | this.schema.validateSync(this.value); 40 | return null; 41 | } catch (err) { 42 | return err; 43 | } 44 | } 45 | @computed get haveError() { return this.error !== null; } 46 | @computed get errorMessage() { return this.haveError ? this.error.message : '' } 47 | } 48 | 49 | export { Option as default }; 50 | -------------------------------------------------------------------------------- /src/app/store/RunList.js: -------------------------------------------------------------------------------- 1 | import { observable, computed, action } from 'mobx'; 2 | import Run from './Run'; 3 | import * as ipc from '../../constants/ipc'; 4 | import AppStore from './AppStore'; 5 | 6 | class RunList extends AppStore { 7 | @observable runs = []; 8 | @observable activeIndex = 0; 9 | 10 | constructor() { 11 | super(); 12 | this.addRun(); 13 | this.listen(); 14 | } 15 | 16 | @observable error = null; 17 | @action 18 | clearError = () => { 19 | this.error = null; 20 | }; 21 | 22 | @computed 23 | get activeRun() { 24 | return this.runs[this.activeIndex]; 25 | } 26 | 27 | @action 28 | addRun = () => { 29 | let maxId = 0; 30 | this.runs.forEach((run) => (maxId = Math.max(run.id, maxId))); 31 | this.runs.push(new Run(this, maxId + 1)); 32 | this.activeIndex = this.runs.length - 1; 33 | }; 34 | 35 | @action 36 | deleteRun = (run) => { 37 | run.dispose(); 38 | const runIndex = this.runs.findIndex((m) => m.id === run.id); 39 | this.runs.splice(runIndex, 1); 40 | if (this.runs.length === 0) { 41 | this.runs.push(new Run(this, 1)); 42 | } 43 | this.activeIndex = Math.min(this.runs.length - 1, this.activeIndex); 44 | }; 45 | 46 | @action 47 | setActive = (index) => { 48 | this.activeIndex = index; 49 | }; 50 | 51 | @action 52 | deleteActive = () => { 53 | this.deleteRun(this.activeRun); 54 | }; 55 | 56 | @action 57 | onError = (error) => { 58 | this.error = error; 59 | }; 60 | 61 | @action 62 | onUnhandledError = (event, { error }) => { 63 | console.log(`Unhandled error:`, error); 64 | this.error = error; 65 | }; 66 | 67 | @action 68 | onBackboneConstraint = (event, params) => { 69 | this.activeRun.useBackboneConstraint = 70 | !this.activeRun.useBackboneConstraint; 71 | }; 72 | 73 | @action 74 | onMultifurcatingConstraint = (event, params) => { 75 | this.activeRun.useMultifurcatingConstraint = 76 | !this.activeRun.useMultifurcatingConstraint; 77 | }; 78 | 79 | listen = () => { 80 | this.listenTo(ipc.UNHANDLED_ERROR, this.onUnhandledError); 81 | this.listenTo(ipc.ADD_RUN, this.addRun); 82 | this.listenTo(ipc.REMOVE_RUN, this.deleteActive); 83 | this.listenTo(ipc.TOGGLE_BACKBONE_CONSTRAINT, this.onBackboneConstraint); 84 | this.listenTo( 85 | ipc.TOGGLE_MULTIFURCATING_CONSTRAINT, 86 | this.onMultifurcatingConstraint 87 | ); 88 | }; 89 | 90 | generateReport = ({ maxStdoutLength = 1000 } = {}) => { 91 | return this.activeRun.generateReport({ maxStdoutLength }); 92 | }; 93 | } 94 | 95 | export default RunList; 96 | -------------------------------------------------------------------------------- /src/app/store/StoreBase.js: -------------------------------------------------------------------------------- 1 | import { ipcRenderer } from 'electron'; 2 | 3 | import * as ipc from '../../constants/ipc'; 4 | 5 | export default class StoreBase { 6 | listeners = []; 7 | 8 | constructor() { 9 | this._init(); 10 | this._listen(); 11 | } 12 | 13 | listenTo = (channel, listener) => { 14 | ipcRenderer.on(channel, listener); 15 | this.listeners.push([channel, listener]); 16 | }; 17 | 18 | unlisten = () => { 19 | while (!this.listeners.length > 0) { 20 | const [channel, listener] = this.listeners.pop(); 21 | ipcRenderer.removeListener(channel, listener); 22 | } 23 | }; 24 | 25 | dispose = () => { 26 | this.unlisten(); 27 | }; 28 | 29 | _init = () => { 30 | ipcRenderer.send(ipc.INIT_APP_STATE); 31 | }; 32 | 33 | _listen = () => { 34 | this.listenTo(ipc.INIT_APP_STATE_RECEIVED, this._initAppState); 35 | }; 36 | 37 | _initAppState = (event, { version }) => { 38 | this.version = version; 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /src/app/store/index.js: -------------------------------------------------------------------------------- 1 | import RunList from './RunList'; 2 | 3 | const store = new RunList(); 4 | 5 | window.store = store; 6 | export default store; 7 | -------------------------------------------------------------------------------- /src/app/theme/index.js: -------------------------------------------------------------------------------- 1 | import { createTheme } from '@mui/material/styles'; 2 | 3 | const darkTheme = { 4 | palette: { 5 | mode: 'dark', 6 | primary: { 7 | background: 'hsl(29, 5%, 5%)', 8 | main: 'hsl(0, 0%, 100%)', 9 | contrastText: '#ddd', 10 | }, 11 | secondary: { 12 | main: 'hsl(0, 0%, 76%)', 13 | contrastText: '#333', 14 | }, 15 | model: { 16 | background: 'hsla(33, 27%, 10%, 1)', 17 | border: 'hsla(33, 27%, 30%, 1)', 18 | lighter: 'hsla(33, 27%, 43%, 1)', 19 | light: 'hsla(33, 27%, 27%, 1)', 20 | main: 'hsla(33, 27%, 23%, 1)', 21 | dark: 'hsla(33, 27%, 18%, 1)', 22 | darker: 'hsla(33, 27%, 12%, 1)', 23 | secondaryText: 'hsla(33, 9%, 54%, 1)', 24 | contrastText: '#fefefe', 25 | shadow: 'hsla(33, 2%, 20%, 1)', 26 | }, 27 | input: { 28 | background: 'hsla(92, 27%, 10%, 1)', 29 | border: 'hsla(92, 27%, 30%, 1)', 30 | lighter: 'hsla(92, 27%, 43%, 1)', 31 | light: 'hsla(92, 27%, 27%, 1)', 32 | main: 'hsla(92, 27%, 23%, 1)', 33 | dark: 'hsla(92, 27%, 18%, 1)', 34 | darker: 'hsla(92, 27%, 12%, 1)', 35 | secondaryText: 'hsla(92, 9%, 54%, 1)', 36 | contrastText: '#fefefe', 37 | shadow: 'hsla(92, 2%, 20%, 1)', 38 | }, 39 | output: { 40 | background: 'hsla(211, 27%, 10%, 1)', 41 | border: 'hsla(211, 27%, 30%, 1)', 42 | lighter: 'hsla(211, 27%, 43%, 1)', 43 | light: 'hsla(211, 27%, 27%, 1)', 44 | main: 'hsla(211, 27%, 23%, 1)', 45 | dark: 'hsla(211, 27%, 18%, 1)', 46 | darker: 'hsla(211, 27%, 12%, 1)', 47 | secondaryText: 'hsla(211, 9%, 54%, 1)', 48 | contrastText: '#fefefe', 49 | shadow: 'hsla(211, 2%, 20%, 1)', 50 | }, 51 | raxml: { 52 | border: 'hsla(211, 0%, 28%, 1)', 53 | background: 'hsla(211, 0%, 10%, 1)', 54 | lighter: 'hsla(211, 0%, 12%, 1)', 55 | light: 'hsla(211, 0%, 18%, 1)', 56 | main: 'hsla(211, 0%, 23%, 1)', 57 | dark: 'hsla(211, 0%, 35%, 1)', 58 | darker: 'hsla(211, 0%, 41%, 1)', 59 | secondaryText: 'hsla(211, 0%, 54%, 1)', 60 | contrastText: '#fefefe', 61 | shadow: 'hsla(211, 2%, 10%, 1)', 62 | }, 63 | console: { 64 | border: 'hsla(211, 0%, 28%, 1)', 65 | background: 'hsla(211, 0%, 10%, 1)', 66 | lighter: 'hsla(211, 0%, 12%, 1)', 67 | light: 'hsla(211, 0%, 18%, 1)', 68 | main: 'hsla(211, 0%, 23%, 1)', 69 | dark: 'hsla(211, 0%, 35%, 1)', 70 | darker: 'hsla(211, 0%, 41%, 1)', 71 | secondaryText: 'hsla(211, 0%, 54%, 1)', 72 | contrastText: '#fefefe', 73 | shadow: 'hsla(211, 2%, 10%, 1)', 74 | }, 75 | status: { 76 | border: 'hsla(211, 0%, 28%, 1)', 77 | background: 'hsla(211, 0%, 10%, 1)', 78 | lighter: 'hsla(211, 0%, 12%, 1)', 79 | light: 'hsla(211, 0%, 18%, 1)', 80 | main: 'hsla(211, 0%, 23%, 1)', 81 | dark: 'hsla(211, 0%, 35%, 1)', 82 | darker: 'hsla(211, 0%, 41%, 1)', 83 | secondaryText: 'hsla(211, 0%, 54%, 1)', 84 | contrastText: '#fefefe', 85 | shadow: 'hsla(211, 2%, 10%, 1)', 86 | }, 87 | // error: amber, 88 | error: { 89 | main: '#f2401b', 90 | }, 91 | // Used by `getContrastText()` to maximize the contrast between the background and 92 | // the text. 93 | contrastThreshold: 3, 94 | // Used by the functions below to shift a color's luminance by approximately 95 | // two indexes within its tonal palette. 96 | // E.g., shift from Red 500 to Red 300 or Red 700. 97 | tonalOffset: 0.2, 98 | }, 99 | // Migration to typography v2 100 | typography: { 101 | useNextVariants: true, 102 | }, 103 | }; 104 | 105 | const lightTheme = { 106 | palette: { 107 | mode: 'light', 108 | primary: { 109 | background: 'hsl(29, 99%, 99%)', 110 | border: 'hsl(0, 0%, 0%)', 111 | main: 'hsl(0, 0%, 0%)', 112 | contrastText: '#333', 113 | }, 114 | secondary: { 115 | main: 'hsl(0, 0%, 76%)', 116 | contrastText: '#333', 117 | }, 118 | model: { 119 | background: 'hsla(33, 34%, 98%, 1)', 120 | border: 'hsla(33, 34%, 73%, 1)', 121 | lighter: 'hsla(33, 34%, 93%, 1)', 122 | light: 'hsla(33, 34%, 87%, 1)', 123 | main: 'hsla(33, 34%, 83%, 1)', 124 | dark: 'hsla(33, 34%, 77%, 1)', 125 | darker: 'hsla(33, 34%, 41%, 1)', 126 | secondaryText: 'hsla(33, 9%, 54%, 1)', 127 | contrastText: '#333', 128 | shadow: 'hsla(33, 2%, 64%, 1)', 129 | }, 130 | input: { 131 | background: 'hsla(92, 34%, 98%, 1)', 132 | border: 'hsla(92, 34%, 73%, 1)', 133 | lighter: 'hsla(92, 34%, 93%, 1)', 134 | light: 'hsla(92, 34%, 87%, 1)', 135 | main: 'hsla(92, 34%, 83%, 1)', 136 | dark: 'hsla(92, 34%, 77%, 1)', 137 | darker: 'hsla(92, 34%, 41%, 1)', 138 | secondaryText: 'hsla(92, 9%, 54%, 1)', 139 | contrastText: '#333', 140 | shadow: 'hsla(92, 2%, 64%, 1)', 141 | }, 142 | output: { 143 | background: 'hsla(211, 34%, 98%, 1)', 144 | border: 'hsla(211, 34%, 73%, 1)', 145 | lighter: 'hsla(211, 34%, 93%, 1)', 146 | light: 'hsla(211, 34%, 87%, 1)', 147 | main: 'hsla(211, 34%, 83%, 1)', 148 | dark: 'hsla(211, 34%, 77%, 1)', 149 | darker: 'hsla(211, 34%, 41%, 1)', 150 | secondaryText: 'hsla(211, 9%, 54%, 1)', 151 | contrastText: '#333', 152 | shadow: 'hsla(211, 2%, 64%, 1)', 153 | }, 154 | raxml: { 155 | border: 'hsla(211, 0%, 10%, 1)', 156 | background: 'hsla(211, 0%, 98%, 1)', 157 | lighter: 'hsla(211, 0%, 96%, 1)', 158 | light: 'hsla(211, 0%, 96%, 1)', 159 | main: 'hsla(211, 0%, 90%, 1)', 160 | dark: 'hsla(211, 0%, 77%, 1)', 161 | darker: 'hsla(211, 0%, 41%, 1)', 162 | secondaryText: 'hsla(211, 0%, 54%, 1)', 163 | contrastText: '#333', 164 | shadow: 'hsla(211, 2%, 64%, 1)', 165 | }, 166 | console: { 167 | border: 'hsla(211, 0%, 10%, 1)', 168 | background: 'hsla(211, 0%, 98%, 1)', 169 | lighter: 'hsla(211, 0%, 96%, 1)', 170 | light: 'hsla(211, 0%, 96%, 1)', 171 | main: 'hsla(211, 0%, 90%, 1)', 172 | dark: 'hsla(211, 0%, 77%, 1)', 173 | darker: 'hsla(211, 0%, 41%, 1)', 174 | secondaryText: 'hsla(211, 0%, 54%, 1)', 175 | contrastText: '#333', 176 | shadow: 'hsla(211, 2%, 64%, 1)', 177 | }, 178 | status: { 179 | border: 'hsla(211, 0%, 73%, 1)', 180 | background: 'hsla(211, 0%, 98%, 1)', 181 | lighter: 'hsla(211, 0%, 96%, 1)', 182 | light: 'hsla(211, 0%, 96%, 1)', 183 | main: 'hsla(211, 0%, 90%, 1)', 184 | dark: 'hsla(211, 0%, 77%, 1)', 185 | darker: 'hsla(211, 0%, 41%, 1)', 186 | secondaryText: 'hsla(211, 0%, 54%, 1)', 187 | contrastText: '#333', 188 | shadow: 'hsla(211, 2%, 64%, 1)', 189 | }, 190 | // error: amber, 191 | error: { 192 | main: '#f2401b', 193 | }, 194 | // Used by `getContrastText()` to maximize the contrast between the background and 195 | // the text. 196 | contrastThreshold: 3, 197 | // Used by the functions below to shift a color's luminance by approximately 198 | // two indexes within its tonal palette. 199 | // E.g., shift from Red 500 to Red 300 or Red 700. 200 | tonalOffset: 0.2 201 | }, 202 | // Migration to typography v2 203 | typography: { 204 | useNextVariants: true 205 | } 206 | }; 207 | 208 | export default { 209 | light: createTheme(lightTheme), 210 | dark: createTheme(darkTheme) 211 | }; 212 | -------------------------------------------------------------------------------- /src/common/errors.js: -------------------------------------------------------------------------------- 1 | export default class UserFixError extends Error { 2 | constructor(message) { 3 | super(message); 4 | this.name = "UserFixError"; 5 | this.isUserFix = true; 6 | } 7 | } 8 | 9 | -------------------------------------------------------------------------------- /src/common/fastaParser.js: -------------------------------------------------------------------------------- 1 | import UserFixError from "./errors"; 2 | 3 | export const isFasta = (lines) => { 4 | for (let i = 0; i < lines.length; ++i) { 5 | const line = lines[0].trim(); 6 | if (line.length === 0 || line[0] === '#') { 7 | continue; 8 | } 9 | if (line[0] === '>') { 10 | return true; 11 | } 12 | } 13 | return false; 14 | } 15 | 16 | export const parse = (lines) => { 17 | 18 | if (!isFasta(lines)) { 19 | throw new Error(`Could not parse the file as a FASTA file`); 20 | } 21 | 22 | let lineIndex = 0; 23 | 24 | const parseTaxon = (line) => { 25 | if (line[0] !== '>') { 26 | throw new Error(`Expected a '>' to start a taxon line`); 27 | } 28 | const taxon = line.substring(1); 29 | if (!taxon) { 30 | throw new Error(`Empty taxon at line ${lineIndex + 1}`); 31 | } 32 | return taxon; 33 | } 34 | const parseCode = (line) => { 35 | const code = line.replace(/\s+/g, ''); 36 | if (!code) { 37 | throw new Error(`Empty sequence at line ${lineIndex + 1}`); 38 | } 39 | return code; 40 | } 41 | 42 | const sequences = []; 43 | let taxon = ''; 44 | let codeLines = []; 45 | 46 | const addSequence = () => { 47 | const code = codeLines.join(''); 48 | sequences.push({ taxon, code }); 49 | codeLines = []; 50 | } 51 | 52 | for (; lineIndex < lines.length; ++lineIndex) { 53 | const line = lines[lineIndex]; 54 | if (line.length === 0 || line[0] === '#') { 55 | continue; 56 | } 57 | if (line[0] === '>') { 58 | if (taxon) { 59 | addSequence(); 60 | codeLines = []; 61 | } 62 | taxon = parseTaxon(line); 63 | } 64 | else { 65 | if (!taxon) { 66 | throw new Error(`'No taxon line found before line ${lineIndex+1} ('${line}')`); 67 | } 68 | codeLines.push(parseCode(line)); 69 | } 70 | } 71 | addSequence(); 72 | 73 | const numSequences = sequences.length; 74 | const length = sequences[0].code.length; 75 | // Check that all sequnces have the same length; 76 | for (let seq of sequences) { 77 | if (seq.code.length !== length) { 78 | throw new UserFixError(`Sequence '${seq.taxon}' has different length (${seq.code.length}) than previous taxons (${length})`); 79 | } 80 | } 81 | 82 | // console.log('Sequences:', sequences); 83 | const alignment = { 84 | sequences, 85 | numSequences, 86 | length, 87 | fileFormat: 'FASTA', 88 | }; 89 | 90 | return alignment; 91 | 92 | } 93 | 94 | export default { 95 | isFasta, 96 | parse, 97 | }; 98 | -------------------------------------------------------------------------------- /src/common/io.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import readline from 'readline'; 3 | import util from 'util'; 4 | 5 | import phylipParser from './phylipParser'; 6 | import fastaParser from './fastaParser'; 7 | import typecheckAlignment from './typecheckAlignment'; 8 | import UserFixError from './errors'; 9 | 10 | export const parseAlignment = async (filePath) => { 11 | 12 | return new Promise((resolve, reject) => { 13 | 14 | const rl = readline.createInterface({ 15 | input: fs.createReadStream(filePath), 16 | terminal: false, 17 | }); 18 | 19 | const lines = []; 20 | let error = null; 21 | let alignment = null; 22 | 23 | rl.on('line', (line) => { 24 | lines.push(line); 25 | 26 | }).on('close', () => { 27 | try { 28 | if (phylipParser.isPhylip(lines)) { 29 | alignment = phylipParser.parse(lines); 30 | } else if (fastaParser.isFasta(lines)) { 31 | alignment = fastaParser.parse(lines); 32 | } else { 33 | throw new UserFixError("Unrecognized input format. RaxmlGUI2 supports the following input types at the moment: 'clustal', 'fasta', 'nbrf', 'nexus', 'mega', 'phylip'."); 34 | } 35 | } 36 | catch (err) { 37 | error = err; 38 | error.message = `Error parsing file ${filePath}: ${error.message}.`; 39 | } 40 | if (error) { 41 | reject(error); 42 | } else { 43 | 44 | if (alignment.sequences.length === 0) { 45 | return reject(new Error(`Couldn't parse any sequences from file ${filePath}`)) 46 | } 47 | 48 | try { 49 | typecheckAlignment(alignment); 50 | } catch (err) { 51 | console.error('Error checking data type:', err); 52 | return reject(err); 53 | } 54 | 55 | const alignmentRestricted = Object.assign({}, alignment, { sequences: alignment.sequences.slice(0,2) }); 56 | console.log('Alignment with first two sequences:', alignmentRestricted); 57 | resolve(alignment); 58 | } 59 | }); 60 | }); 61 | } 62 | 63 | export const writeAlignment = async (filePath, alignment) => { 64 | console.log(`Write alignment in FASTA format to ${filePath}`); 65 | console.log(alignment); 66 | const writeStream = fs.createWriteStream(filePath); 67 | const write = util.promisify(writeStream.write); 68 | const end = util.promisify(writeStream.end); 69 | for (let i = 0; i < alignment.sequences.length; ++i) { 70 | const prefix = i === 0 ? '>' : '\n>'; 71 | const sequence = alignment.sequences[i]; 72 | await write.call(writeStream, `${prefix}${sequence.taxon}\n`); 73 | await write.call(writeStream, sequence.code); 74 | } 75 | await end.call(writeStream); 76 | } 77 | 78 | export default { 79 | parseAlignment, 80 | writeAlignment, 81 | } 82 | -------------------------------------------------------------------------------- /src/common/typecheckAlignment.js: -------------------------------------------------------------------------------- 1 | import UserFixError from './errors'; 2 | 3 | export const getFinalDataType = (dataTypes) => { 4 | const notUndefinedTypes = dataTypes.filter((d) => d !== undefined); 5 | if (notUndefinedTypes.length === 0) { 6 | return undefined; 7 | } 8 | let firstType = notUndefinedTypes[0]; 9 | for (let i = 1; i < notUndefinedTypes.length; ++i) { 10 | const type = notUndefinedTypes[i]; 11 | if (type !== firstType) { 12 | if ( 13 | (type === 'binary' && firstType === 'multistate') || 14 | (type === 'multistate' && firstType === 'binary') 15 | ) { 16 | firstType = 'multistate'; 17 | } else { 18 | return 'mixed'; 19 | } 20 | } 21 | } 22 | return firstType; 23 | }; 24 | 25 | // Valid characters taken from Standard-RAxML (axml.c) 26 | const reInvalidBinary = /[^01-?]/g; 27 | const reInvalidDNA = /[^ABCDGHKMRSTUVWYNOX?-]/gi; 28 | const reInvalidAA = /[^ARNDCQEGHILKMFPSTWYVBZX*?-]/gi; 29 | const reInvalidGeneric = /[^0123456789ABCDEFGHIJKLMNOPQRSTU?-]/gi; 30 | const reInvalidMixed = /[^0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*?-]/gi; 31 | 32 | export function findInvalidCharacter(code, dataType) { 33 | // Returns the index of the invalid character if found, else -1 34 | switch (dataType) { 35 | case 'protein': 36 | return reInvalidAA.test(code) ? reInvalidAA.lastIndex - 1 : -1; 37 | case 'nucleotide': 38 | return reInvalidDNA.test(code) ? reInvalidDNA.lastIndex - 1 : -1; 39 | case 'multistate': 40 | return reInvalidGeneric.test(code) ? reInvalidGeneric.lastIndex - 1 : -1; 41 | case 'binary': 42 | return reInvalidBinary.test(code) ? reInvalidBinary.lastIndex - 1 : -1; 43 | case 'unknown': 44 | case 'mixed': 45 | default: 46 | return reInvalidMixed.test(code) ? reInvalidMixed.lastIndex - 1 : -1; 47 | } 48 | } 49 | 50 | function hasInvariantSites(length, sequences) { 51 | for (let i = 0; i < length; i++) { 52 | const variantsAtPosition = []; 53 | for (const sequence of sequences) { 54 | const site = sequence.code[i]; 55 | if (!variantsAtPosition.includes(site)) { 56 | variantsAtPosition.push(site) 57 | } 58 | } 59 | if (variantsAtPosition.length <= 1) { 60 | return true; 61 | } 62 | } 63 | return false; 64 | } 65 | 66 | export default function typecheckAlignment(alignment) { 67 | const acgMatch = /[ACGN?]/i; // Include 'N' and '?' as symbols for missing characters in DNA 68 | // const proteinMatch = /[RNDEQHILKMFPSWYVXBZJ]/i; 69 | const proteinMatch = /[EFJIJLOPQZX]/i; 70 | const binaryMatch = /[01]/; 71 | const multistateMatch = /2/; 72 | const unknownMatch = /^[N?]+$/i; 73 | const sequenceDataTypes = []; 74 | const dataTypes = new Set(); 75 | let numSequencesTypechecked = 0; 76 | alignment.sequences.forEach((sequence, index) => { 77 | const { code } = sequence; 78 | let dataType = undefined; 79 | if (proteinMatch.test(code)) { 80 | dataType = 'protein'; 81 | } else if (acgMatch.test(code)) { 82 | // const numT = (code.match(/T/ig) || []).length; 83 | // const numU = (code.match(/U/ig) || []).length; 84 | // if (numT > numU) { 85 | // dataType = 'dna'; 86 | // } else { 87 | // dataType = 'rna'; 88 | // } 89 | if (/[ACG]/i.test(code)) { 90 | // Check that it don't have only N or ? 91 | dataType = 'nucleotide'; 92 | } else { 93 | dataType = 'unknown'; 94 | } 95 | } 96 | 97 | if (!dataType || dataType === 'unknown') { 98 | if (multistateMatch.test(code)) { 99 | dataType = 'multistate'; 100 | } else if (binaryMatch.test(code)) { 101 | dataType = 'binary'; 102 | } else if (unknownMatch.test(code)) { 103 | dataType = 'unknown'; 104 | } 105 | } else if (binaryMatch.test(code) || multistateMatch.test(code)) { 106 | dataType = 'mixed'; 107 | } 108 | dataTypes.add(dataType); 109 | sequence.dataType = dataType; 110 | ++numSequencesTypechecked; 111 | sequenceDataTypes.push(sequence.dataType); 112 | }); 113 | 114 | if (dataTypes.delete('unknown')) { 115 | console.log('At least one sequence have only unknown characters'); 116 | if (dataTypes.size === 0) { 117 | throw new Error( 118 | `Invalid alignment: cannot determine data type because all ${numSequencesTypechecked} sequences are of type unknown` 119 | ); 120 | } 121 | } 122 | let dataType = dataTypes.values().next().value; 123 | if (dataTypes.size > 1) { 124 | // Only valid case with different types is binary and multistate as [01] is a subset of [012]. 125 | const isMultistate = !sequenceDataTypes.find( 126 | (type) => type !== 'binary' && type !== 'multistate' 127 | ); 128 | if (isMultistate) { 129 | dataType = 'multistate'; 130 | } else { 131 | dataType = 'invalid'; 132 | console.log( 133 | 'Illegal mix of data types among sequences:', 134 | sequenceDataTypes 135 | ); 136 | throw new UserFixError( 137 | `Your alignment is a mix of different data types, namely = ${Array.from( 138 | dataTypes.keys() 139 | )}. 140 | Please use only the same type for one alignment or combine several files.` 141 | ); 142 | } 143 | } 144 | alignment.sequences.forEach((seq, index) => { 145 | const invalidSiteIndex = findInvalidCharacter(seq.code, dataType); 146 | if (invalidSiteIndex !== -1) { 147 | const sample = 148 | seq.code.length <= 8 149 | ? `'${seq.code}'` 150 | : `'${seq.code.substring(0, 8)}'...`; 151 | throw new UserFixError( 152 | `Invalid character '${seq.code[invalidSiteIndex]}' at site ${ 153 | invalidSiteIndex + 1 154 | } in sequence ${ 155 | index + 1 156 | } (${sample}) for inferred data type '${dataType}'` 157 | ); 158 | } 159 | }); 160 | alignment.hasInvariantSites = hasInvariantSites(alignment.length, alignment.sequences); 161 | alignment.dataType = dataType; 162 | alignment.typecheckingComplete = true; 163 | return alignment; 164 | } 165 | -------------------------------------------------------------------------------- /src/common/utils.js: -------------------------------------------------------------------------------- 1 | import electron from 'electron'; 2 | import { serializeError } from 'serialize-error'; 3 | import cleanStack from 'clean-stack'; 4 | import * as ipc from 'electron-better-ipc'; 5 | 6 | import { activeWindow } from '../main/utils/utils'; 7 | 8 | function newGithubIssueUrl(options = {}) { 9 | let repoUrl; 10 | if (options.repoUrl) { 11 | repoUrl = options.repoUrl; 12 | } else if (options.user && options.repo) { 13 | repoUrl = `https://github.com/${options.user}/${options.repo}`; 14 | } else { 15 | throw new Error( 16 | 'You need to specify either the `repoUrl` option or both the `user` and `repo` options' 17 | ); 18 | } 19 | 20 | const url = new URL(`${repoUrl}/issues/new`); 21 | 22 | const types = [ 23 | 'body', 24 | 'title', 25 | 'labels', 26 | 'template', 27 | 'milestone', 28 | 'assignee', 29 | 'projects', 30 | ]; 31 | 32 | for (const type of types) { 33 | let value = options[type]; 34 | if (value === undefined) { 35 | continue; 36 | } 37 | 38 | if (type === 'labels' || type === 'projects') { 39 | if (!Array.isArray(value)) { 40 | throw new TypeError(`The \`${type}\` option should be an array`); 41 | } 42 | 43 | value = value.join(','); 44 | } 45 | 46 | url.searchParams.set(type, value); 47 | } 48 | 49 | return url.toString(); 50 | } 51 | 52 | export const is = { 53 | macos: process.platform === 'darwin', 54 | linux: process.platform === 'linux', 55 | windows: process.platform === 'win32', 56 | main: process.type === 'browser', 57 | renderer: process.type === 'renderer', 58 | development: process.env.NODE_ENV === 'development', 59 | macAppStore: process.mas === true, 60 | windowsStore: process.windowsStore === true, 61 | }; 62 | 63 | export const platform = (object) => { 64 | let { platform } = process; 65 | if (is.macos) { 66 | platform = 'macos'; 67 | } else if (is.windows) { 68 | platform = 'windows'; 69 | } 70 | const fn = platform in object ? object[platform] : object.default; 71 | return typeof fn === 'function' ? fn() : fn; 72 | }; 73 | 74 | // TODO: Had to replace this debug info on renderer, because electron remote module is no longer available. 75 | // If needed, one would need to use the context bridge 76 | export const debugInfo = () => 77 | is.main 78 | ? `${electron.app.getName()} ${electron.app.getVersion()} 79 | Electron ${node.electronVersion} 80 | ${process.platform} ${os.release()} 81 | Locale: ${electron.app.getLocale()} 82 | `.trim() 83 | : `Debug info not available in renderer.`; 84 | 85 | if (is.renderer) { 86 | ipc.ipcRenderer.answerMain('get-state-report', async () => { 87 | const storeModule = await import('../app/store'); 88 | const store = storeModule.default; 89 | const report = store.generateReport(); 90 | return report; 91 | }); 92 | } 93 | 94 | const getActiveState = async () => { 95 | if (is.renderer) { 96 | return window.store.generateReport(); 97 | } 98 | const win = activeWindow(); 99 | const report = await ipc.ipcMain.callRenderer(win, 'get-state-report'); 100 | return report; 101 | } 102 | 103 | const getActiveStateSync = () => { 104 | if (is.renderer) { 105 | return window.store.generateReport(); 106 | } 107 | return `Current state not available on synchronous call from main`; 108 | } 109 | 110 | const serializeAndCleanError = (error) => { 111 | const err = serializeError(error); 112 | err.stack = cleanStack(error.stack); 113 | return err; 114 | } 115 | 116 | export function timeout(ms) { 117 | return new Promise(resolve => setTimeout(resolve, ms)); 118 | } 119 | 120 | export const quote = dir => is.windows ? `"${dir}"` : dir; 121 | 122 | const stringify = json => JSON.stringify(json, null, ' '); 123 | 124 | const stringifyToGithubMarkdown = (json) => `\`\`\`json 125 | ${stringify(json)} 126 | \`\`\``; 127 | 128 | const createReportBodyForGithub = (error, activeState) => `Autogenerated report: 129 | ${stringifyToGithubMarkdown(serializeAndCleanError(error))} 130 | 131 | Active state: 132 | ${stringifyToGithubMarkdown(activeState)} 133 | 134 | --- 135 | 136 | Process: ${is.renderer ? 'renderer' : 'main'} 137 | ${debugInfo()}`; 138 | 139 | const createReportBodyForMail = (error, activeState) => encodeURI(`Autogenerated report: 140 | ${stringify(serializeAndCleanError(error))} 141 | 142 | Active state: 143 | ${stringify(activeState)} 144 | 145 | --- 146 | 147 | Process: ${is.renderer ? 'renderer' : 'main'} 148 | ${debugInfo()}`); 149 | 150 | const openNewGitHubIssue = (options) => { 151 | const url = newGithubIssueUrl(options); 152 | electron.shell.openExternal(url); 153 | }; 154 | 155 | export const reportIssueToGitHub = async (error) => { 156 | const activeState = await getActiveState(); 157 | openNewGitHubIssue({ 158 | user: 'AntonelliLab', 159 | repo: 'raxmlGUI', 160 | title: error.name, 161 | body: createReportBodyForGithub(error, activeState), 162 | }); 163 | } 164 | 165 | export const getMailtoLinkToReportError = (error) => { 166 | const activeState = getActiveStateSync(); 167 | const mailtoLinkContent = `mailto:raxmlgui.help@googlemail.com?subject=${encodeURI(error.name)}&body=${createReportBodyForMail(error, activeState)}`; 168 | return mailtoLinkContent; 169 | } 170 | -------------------------------------------------------------------------------- /src/constants/ipc.js: -------------------------------------------------------------------------------- 1 | /* 2 | Strings for ipc 3 | */ 4 | export const INIT_APP_STATE = 'INIT_APP_STATE'; 5 | export const INIT_APP_STATE_RECEIVED = 'INIT_APP_STATE_RECEIVED'; 6 | export const OUTPUT_DIR_SELECT = 'OUTPUT_DIR_SELECT'; 7 | export const OUTPUT_DIR_SELECTED = 'OUTPUT_DIR_SELECTED'; 8 | export const TREE_SELECT = 'TREE_SELECT'; 9 | export const TREE_SELECTED = 'TREE_SELECTED'; 10 | export const PARTITION_FILE_SELECT = 'PARTITION_FILE_SELECT'; 11 | export const PARTITION_FILE_SELECTED = 'PARTITION_FILE_SELECTED'; 12 | export const RUN_START = 'RUN_START'; 13 | export const RUN_STDOUT = 'RUN_STDOUT'; 14 | export const RUN_STDERR = 'RUN_STDERR'; 15 | export const RUN_FINISHED = 'RUN_FINISHED'; 16 | export const RUN_ERROR = 'RUN_ERROR'; 17 | export const RUN_CANCEL = 'RUN_CANCEL'; 18 | export const FILE_OPEN = 'FILE_OPEN'; 19 | export const FILE_SHOW_IN_FOLDER = 'FILE_SHOW_IN_FOLDER'; 20 | export const FOLDER_OPEN = 'FOLDER_OPEN'; 21 | export const OUTPUT_CHECK = 'OUTPUT_CHECK'; 22 | export const OUTPUT_CHECKED = 'OUTPUT_CHECKED'; 23 | export const ALIGNMENT_SELECT = 'ALIGNMENT_SELECT'; 24 | export const ALIGNMENT_SELECTED = 'ALIGNMENT_SELECTED'; 25 | export const ALIGNMENT_PARSE_REQUEST = 'ALIGNMENT_PARSE_REQUEST'; 26 | export const ALIGNMENT_PARSE_SUCCESS = 'ALIGNMENT_PARSE_SUCCESS'; 27 | export const ALIGNMENT_PARSE_FAILURE = 'ALIGNMENT_PARSE_FAILURE'; 28 | export const ALIGNMENT_PARSE_CHANGED_PATH = 'ALIGNMENT_PARSE_CHANGED_PATH'; 29 | export const ALIGNMENT_EXAMPLE_FILES_GET_REQUEST = 'ALIGNMENT_EXAMPLE_FILES_GET_REQUEST'; 30 | export const ALIGNMENT_EXAMPLE_FILES_GET_SUCCESS = 'ALIGNMENT_EXAMPLE_FILES_GET_SUCCESS'; 31 | export const ALIGNMENT_MODEL_SELECTION_REQUEST = 'ALIGNMENT_MODEL_SELECTION_REQUEST'; 32 | export const ALIGNMENT_MODEL_SELECTION_CANCEL = 'ALIGNMENT_MODEL_SELECTION_CANCEL'; 33 | export const ALIGNMENT_MODEL_SELECTION_SUCCESS = 'ALIGNMENT_MODEL_SELECTION_SUCCESS'; 34 | export const ALIGNMENT_MODEL_SELECTION_FAILURE = 'ALIGNMENT_MODEL_SELECTION_FAILURE'; 35 | export const UNHANDLED_ERROR = 'UNHANDLED_ERROR'; 36 | export const TOGGLE_BACKBONE_CONSTRAINT = 'TOGGLE_BACKBONE_CONSTRAINT'; 37 | export const TOGGLE_MULTIFURCATING_CONSTRAINT = 'TOGGLE_MULTIFURCATING_CONSTRAINT'; 38 | export const ADD_RUN = 'ADD_RUN'; 39 | export const REMOVE_RUN = 'REMOVE_RUN'; 40 | export const LIGHT_MODE = 'LIGHT_MODE'; 41 | export const DARK_MODE = 'DARK_MODE'; 42 | export const RELOAD = 'RELOAD'; 43 | export const ASTRAL_REQUEST = 'ASTRAL_REQUEST'; 44 | export const ASTRAL_SUCCESS = 'ASTRAL_SUCCESS'; 45 | export const ASTRAL_FILE_SELECT = 'ASTRAL_FILE_SELECT'; 46 | export const ASTRAL_FILE_SELECTED = 'ASTRAL_FILE_SELECTED'; 47 | -------------------------------------------------------------------------------- /src/electron.js: -------------------------------------------------------------------------------- 1 | const electron = require('electron'); 2 | const proc = require('child_process'); 3 | 4 | // spawn Electron 5 | const child = proc.spawn(electron, process.argv.slice(2), { stdio: 'inherit' }); 6 | 7 | child.on('close', (code) => { 8 | console.log(`Electron child process exited with code ${code}`); 9 | }); 10 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | padding: 0; 4 | overflow: hidden; 5 | height: 100% 6 | } 7 | body { 8 | font-family: Roboto, sans-serif; 9 | } 10 | pre, code, .pre, .code { 11 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace !important; 12 | } 13 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import App from './app/'; 5 | import registerServiceWorker from './registerServiceWorker'; 6 | import './index.css'; 7 | 8 | const container = document.getElementById('root'); 9 | const root = createRoot(container); 10 | root.render(); 11 | 12 | registerServiceWorker(); 13 | -------------------------------------------------------------------------------- /src/main/menu/index.js: -------------------------------------------------------------------------------- 1 | import { app, Menu } from 'electron'; 2 | 3 | import subMenuFile from './subMenuFile'; 4 | import subMenuAnalysis from './subMenuAnalysis'; 5 | import subMenuDeveloper from './subMenuDeveloper'; 6 | import saveScreenshot from '../utils/saveScreenshot'; 7 | 8 | const menuTemplate = [ 9 | subMenuFile, 10 | subMenuAnalysis, 11 | { 12 | role: 'window', 13 | submenu: [ 14 | { role: 'minimize' }, 15 | { role: 'close' }, 16 | { 17 | label: 'Save screenshot', 18 | accelerator: 'CmdOrCtrl+S', 19 | click() { 20 | saveScreenshot(); 21 | } 22 | }, 23 | ] 24 | }, 25 | ]; 26 | 27 | export default class MenuBuilder { 28 | constructor(mainWindow) { 29 | this.mainWindow = mainWindow; 30 | } 31 | 32 | buildMenu() { 33 | if ( 34 | process.env.NODE_ENV === 'development' || 35 | process.env.DEBUG_PROD === 'true' 36 | ) { 37 | menuTemplate.push(subMenuDeveloper); 38 | this.setupDevelopmentEnvironment(); 39 | } 40 | 41 | if (process.platform === 'darwin') { 42 | menuTemplate.unshift({ 43 | label: app.name, 44 | submenu: [ 45 | { role: 'about' }, 46 | { type: 'separator' }, 47 | { role: 'services' }, 48 | { type: 'separator' }, 49 | { role: 'hide' }, 50 | { role: 'hideothers' }, 51 | { role: 'unhide' }, 52 | { type: 'separator' }, 53 | { role: 'quit' } 54 | ] 55 | }); 56 | } 57 | 58 | const menu = Menu.buildFromTemplate(menuTemplate); 59 | Menu.setApplicationMenu(menu); 60 | 61 | return menu; 62 | } 63 | 64 | setupDevelopmentEnvironment() { 65 | this.mainWindow.openDevTools(); 66 | this.mainWindow.webContents.on('context-menu', (e, props) => { 67 | const { x, y } = props; 68 | Menu.buildFromTemplate([ 69 | { 70 | label: 'Inspect element', 71 | click: () => { 72 | this.mainWindow.inspectElement(x, y); 73 | } 74 | } 75 | ]).popup(this.mainWindow); 76 | }); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/menu/subMenuAnalysis.js: -------------------------------------------------------------------------------- 1 | import { BrowserWindow } from 'electron'; 2 | 3 | import * as ipc from '../../constants/ipc'; 4 | 5 | const subMenuAnalysis = { 6 | label: 'Analysis', 7 | submenu: [ 8 | { 9 | label: 'Enforce constraint...', 10 | submenu: [ 11 | { 12 | label: 'Use backbone constraint', 13 | type: 'checkbox', 14 | checked: false, 15 | click() { 16 | BrowserWindow.getFocusedWindow().webContents.send( 17 | ipc.TOGGLE_BACKBONE_CONSTRAINT 18 | ); 19 | } 20 | }, 21 | { 22 | label: 'Use multifurcating constraint', 23 | type: 'checkbox', 24 | checked: false, 25 | click() { 26 | BrowserWindow.getFocusedWindow().webContents.send( 27 | ipc.TOGGLE_MULTIFURCATING_CONSTRAINT 28 | ); 29 | } 30 | } 31 | ] 32 | } 33 | ] 34 | }; 35 | 36 | export default subMenuAnalysis; 37 | -------------------------------------------------------------------------------- /src/main/menu/subMenuDeveloper.js: -------------------------------------------------------------------------------- 1 | const subMenuDeveloper = { 2 | // If you see this menu in production sth is wrong 3 | label: 'DEVELOPER!!!', 4 | submenu: [ 5 | { 6 | label: 'Force Error', 7 | click() { 8 | throw new Error('Testing Error'); 9 | } 10 | }, 11 | { type: 'separator' }, 12 | { role: 'toggledevtools' }, 13 | { role: 'reload' }, 14 | { role: 'forcereload' }, 15 | { type: 'separator' }, 16 | { role: 'resetzoom' }, 17 | { role: 'zoomin' }, 18 | { role: 'zoomout' }, 19 | { type: 'separator' }, 20 | { role: 'togglefullscreen' } 21 | ] 22 | }; 23 | 24 | export default subMenuDeveloper; 25 | -------------------------------------------------------------------------------- /src/main/menu/subMenuFile.js: -------------------------------------------------------------------------------- 1 | import { BrowserWindow } from 'electron'; 2 | 3 | import * as ipc from '../../constants/ipc'; 4 | import { store } from '../../app/store/Config'; 5 | 6 | const subMenuFile = { 7 | label: 'File', 8 | submenu: [ 9 | { 10 | label: 'New Tab', 11 | accelerator: 'CmdOrCtrl+T', 12 | click() { 13 | BrowserWindow.getFocusedWindow().webContents.send(ipc.ADD_RUN); 14 | } 15 | }, 16 | { 17 | label: 'Close Tab', 18 | accelerator: 'CmdOrCtrl+W', 19 | click() { 20 | BrowserWindow.getFocusedWindow().webContents.send(ipc.REMOVE_RUN); 21 | } 22 | }, 23 | { 24 | label: 'Theme', 25 | submenu: [ 26 | { 27 | label: 'Light mode', 28 | type: 'radio', 29 | checked: !store.get('darkMode'), 30 | click() { 31 | BrowserWindow.getFocusedWindow().webContents.send(ipc.LIGHT_MODE); 32 | } 33 | }, 34 | { 35 | label: 'Dark mode', 36 | type: 'radio', 37 | checked: store.get('darkMode'), 38 | click() { 39 | BrowserWindow.getFocusedWindow().webContents.send(ipc.DARK_MODE); 40 | } 41 | } 42 | ] 43 | } 44 | ], 45 | }; 46 | 47 | export default subMenuFile; 48 | -------------------------------------------------------------------------------- /src/main/utils/saveScreenshot.js: -------------------------------------------------------------------------------- 1 | import { BrowserWindow, dialog } from 'electron'; 2 | import fs from 'fs'; 3 | import util from 'util'; 4 | const writeFile = util.promisify(fs.writeFile); 5 | 6 | const saveScreenshot = async () => { 7 | console.log('Save screenshot...'); 8 | const win = BrowserWindow.getFocusedWindow(); 9 | const img = await win.webContents.capturePage() 10 | try { 11 | const file = await dialog.showSaveDialog({ 12 | title: "Select the File Path to save", 13 | buttonLabel: "Save", 14 | // Restricting the user to only Image Files. 15 | filters: [ 16 | { 17 | name: "Image Files", 18 | extensions: ["png", "jpeg", "jpg"], 19 | }, 20 | ], 21 | properties: [], 22 | }); 23 | 24 | if (!file.canceled) { 25 | console.log(`Save screenshot to '${file.filePath}'...`); 26 | // Creating and Writing to the image.png file 27 | // Can save the File as a jpeg file as well, 28 | // by simply using img.toJPEG(100); 29 | await writeFile(file.filePath.toString(), img.toPNG(), "base64"); 30 | console.log('Saved!'); 31 | } 32 | } 33 | catch (err) { 34 | console.log(err); 35 | } 36 | } 37 | 38 | export default saveScreenshot; 39 | -------------------------------------------------------------------------------- /src/main/utils/utils.js: -------------------------------------------------------------------------------- 1 | import electron from 'electron'; 2 | 3 | export const activeWindow = () => electron.BrowserWindow.getFocusedWindow(); 4 | -------------------------------------------------------------------------------- /src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | const isLocalhost = Boolean( 12 | window.location.hostname === 'localhost' || 13 | // [::1] is the IPv6 localhost address. 14 | window.location.hostname === '[::1]' || 15 | // 127.0.0.1/8 is considered localhost for IPv4. 16 | window.location.hostname.match( 17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 18 | ) 19 | ); 20 | 21 | export default function register() { 22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 23 | // The URL constructor is available in all browsers that support SW. 24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location); 25 | if (publicUrl.origin !== window.location.origin) { 26 | // Our service worker won't work if PUBLIC_URL is on a different origin 27 | // from what our page is served on. This might happen if a CDN is used to 28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 29 | return; 30 | } 31 | 32 | window.addEventListener('load', () => { 33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 34 | 35 | if (isLocalhost) { 36 | // This is running on localhost. Lets check if a service worker still exists or not. 37 | checkValidServiceWorker(swUrl); 38 | } else { 39 | // Is not local host. Just register service worker 40 | registerValidSW(swUrl); 41 | } 42 | }); 43 | } 44 | } 45 | 46 | function registerValidSW(swUrl) { 47 | navigator.serviceWorker 48 | .register(swUrl) 49 | .then(registration => { 50 | registration.onupdatefound = () => { 51 | const installingWorker = registration.installing; 52 | installingWorker.onstatechange = () => { 53 | if (installingWorker.state === 'installed') { 54 | if (navigator.serviceWorker.controller) { 55 | // At this point, the old content will have been purged and 56 | // the fresh content will have been added to the cache. 57 | // It's the perfect time to display a "New content is 58 | // available; please refresh." message in your web app. 59 | console.log('New content is available; please refresh.'); 60 | } else { 61 | // At this point, everything has been precached. 62 | // It's the perfect time to display a 63 | // "Content is cached for offline use." message. 64 | console.log('Content is cached for offline use.'); 65 | } 66 | } 67 | }; 68 | }; 69 | }) 70 | .catch(error => { 71 | console.error('Error during service worker registration:', error); 72 | }); 73 | } 74 | 75 | function checkValidServiceWorker(swUrl) { 76 | // Check if the service worker can be found. If it can't reload the page. 77 | fetch(swUrl) 78 | .then(response => { 79 | // Ensure service worker exists, and that we really are getting a JS file. 80 | if ( 81 | response.status === 404 || 82 | response.headers.get('content-type').indexOf('javascript') === -1 83 | ) { 84 | // No service worker found. Probably a different app. Reload the page. 85 | navigator.serviceWorker.ready.then(registration => { 86 | registration.unregister().then(() => { 87 | window.location.reload(); 88 | }); 89 | }); 90 | } else { 91 | // Service worker found. Proceed as normal. 92 | registerValidSW(swUrl); 93 | } 94 | }) 95 | .catch(() => { 96 | console.log( 97 | 'No internet connection found. App is running in offline mode.' 98 | ); 99 | }); 100 | } 101 | 102 | export function unregister() { 103 | if ('serviceWorker' in navigator) { 104 | navigator.serviceWorker.ready.then(registration => { 105 | registration.unregister(); 106 | }); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/settings/raxmlng.js: -------------------------------------------------------------------------------- 1 | // --model 2 | export const binarySubstitutionModelOptions = { 3 | default: 'BIN', 4 | options: [ 5 | 'BIN' 6 | ] 7 | }; 8 | 9 | // --model 10 | export const nucleotideSubstitutionModelOptions = { 11 | default: 'GTR', 12 | options: [ 13 | 'JC', 14 | 'K80', 15 | 'F81', 16 | 'HKY', 17 | 'TN93ef', 18 | 'TN93', 19 | 'K81', 20 | 'K81uf', 21 | 'TPM2', 22 | 'TPM2uf', 23 | 'TPM3', 24 | 'TPM3uf', 25 | 'TIM1', 26 | 'TIM1uf', 27 | 'TIM2', 28 | 'TIM2uf', 29 | 'TIM3', 30 | 'TIM3uf', 31 | 'TVMef', 32 | 'TVM', 33 | 'SYM', 34 | 'GTR' 35 | ] 36 | }; 37 | 38 | // --model 39 | export const multistateSubstitutionModelOptions = { 40 | default: 'MULTIx_GTR', 41 | options: [ 42 | 'MULTIx_MK', 43 | 'MULTIx_GTR' 44 | ] 45 | }; 46 | 47 | // --model 48 | export const aminoAcidSubstitutionModelOptions = { 49 | default: 'Blosum62', 50 | options: [ 51 | 'Blosum62', 52 | 'cpREV', 53 | 'Dayhoff', 54 | 'DCMut', 55 | 'DEN', 56 | 'FLU', 57 | 'HIVb', 58 | 'HIVw', 59 | 'JTT', 60 | 'JTT-DCMut', 61 | 'LG', 62 | 'mtART', 63 | 'mtMAM', 64 | 'mtREV', 65 | 'mtZOA', 66 | 'PMB', 67 | 'rtREV', 68 | 'stmtREV', 69 | 'VT', 70 | 'WAG', 71 | 'LG4M', 72 | 'LG4X', 73 | 'PROTGTR' 74 | ] 75 | }; 76 | 77 | // --model 78 | export const stationaryFrequenciesOptions = { 79 | options: [ 80 | { 81 | value: '+F', 82 | label: '+F (empirical)' 83 | }, 84 | { 85 | value: '+FO', 86 | label: '+FO (ML estimate)' 87 | }, 88 | { 89 | value: '+FE', 90 | label: '+FE (equal)' 91 | }, 92 | // Also posibble are user defined values 93 | // +FU{f1/f2/../fn} (user-defined: f1 f2 ... fn) 94 | // +FU{freqs.txt} (user-defined from file) 95 | ] 96 | }; 97 | 98 | // --model 99 | export const proportionOfInvariantSitesOptions = { 100 | options: [ 101 | { 102 | value: '+I', 103 | label: '+I (ML estimate)' 104 | }, 105 | { 106 | value: '+IC', 107 | label: '+IC (empirical)' 108 | }, 109 | // Also posibble are user defined values 110 | // +IU{p} (user-defined: p) 111 | ] 112 | }; 113 | 114 | // --model 115 | export const amongsiteRateHeterogeneityModelOptions = { 116 | options: [ 117 | { 118 | value: '+G', 119 | label: 120 | '+GAMMA (mean)' 121 | }, 122 | { 123 | value: '+GA', 124 | label: 125 | '+GAMMA (median)' 126 | } 127 | // Also posibble are user defined values 128 | // +Gn (discrete GAMMA with n categories', 'ML estimate of alpha) 129 | // +Gn{a} (discrete GAMMA with n categories and user-defined alpha a) 130 | // +Rn (FreeRate with n categories', 'ML estimate of rates and weights) 131 | // +Rn{r1/r2/../rn}{w1/w2/../wn} (FreeRate with n categories', 'user-defined rates r1 r2 ... rn and weights w1 w2 ... wn) 132 | ] 133 | }; 134 | 135 | // --model 136 | export const ascertainmentBiasCorrectionOptions = { 137 | options: [ 138 | { 139 | value: '+ASC_LEWIS', 140 | label: "Lewis' method" 141 | }, 142 | // Also posibble are user defined values 143 | // +ASC_FELS{w} (Felsenstein's method with total number of invariable sites w) 144 | // +ASC_STAM{w1/w2/../wn} (Stamatakis' method with per-state invariable site numbers w1 w2 ... wn) 145 | ] 146 | }; 147 | 148 | 149 | export const modelOptions = { 150 | 'protein': aminoAcidSubstitutionModelOptions, 151 | 'binary': binarySubstitutionModelOptions, 152 | 'multistate': multistateSubstitutionModelOptions, 153 | 'dna': nucleotideSubstitutionModelOptions, 154 | 'rna': nucleotideSubstitutionModelOptions, 155 | 'nucleotide': nucleotideSubstitutionModelOptions, 156 | }; 157 | -------------------------------------------------------------------------------- /static/example-files/example_data_raxmlGUI.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntonelliLab/raxmlGUI/f5b59126ea6c34e84e89a1c2c07b966e07afd216/static/example-files/example_data_raxmlGUI.zip -------------------------------------------------------------------------------- /static/example-files/fasta/aminoacid.txt: -------------------------------------------------------------------------------- 1 | >TAXON_1 2 | VPPYRWVAGVFITQYMNNIVYDDRISDLCKPVFLINPCHCAPFSGKTIGQ 3 | >TAXON_2 4 | WKEPTYIISEFFYVKTAWYWEVESSSSNFIKECIEACEQPYNHSGCKKFE 5 | >TAXON_3 6 | EGPRSPINHSAEHMVSQLISDCKMWEHPYTTCRGKEVFWFTIKPWACKIH 7 | >TAXON_4 8 | GRHFCWCSTRDAANPVRLCHKVQNCDDVKGQANSCLWSIMEKFERMIIEP 9 | >TAXON_5 10 | DEDCSHPPVYDSPDDSISDHQDGNNEFDTLGMWGMVYPRWSCAWMIAKKN 11 | >TAXON_6 12 | CAWCKDKPWPRSHTISKLYHHDFYKHFMTRSWTIILCQYSEAKPSFTQIS 13 | >TAXON_7 14 | YCINQMANLHEWNVVGNARSKRSCRIGRCNSKEMRSKAREMESESGFRVQ 15 | >TAXON_8 16 | QQPMSHMLWFTHEECWDHVGSHTPRYEKKRPQCTVPHLDKIDPLRLALHG 17 | >TAXON_9 18 | PAQNMDTFQKGRLAWRMFDYQWNQKGDIHKASTVGAKLGESGTAGGFSYP 19 | >TAXON_10 20 | YENFLWSGCWGHLFGATWMRGEKKMDHQVDYHHHLPCFFPDTIWFVDEEF 21 | >TAXON_11 22 | LEYHMCCMAHESGKCCTIAKWAHCSSIIWMQPGQLSANHFDEEKSVIADQ 23 | >TAXON_13 24 | TVNYNLFWIFVFWLYASDNYYTPFLNEKPQEFQGAWYGYHWFDYQPHIVP 25 | >TAXON_14 26 | FAKVELIGVKILDFYGKFMDFFNDCDDEITQRFLTLHSVHPQASSIHKWH 27 | >TAXON_15 28 | GNARGVCQKKCSFMRMVEHIQFDKTFMALSVRRECLLDAATSRLIDAPFM 29 | >TAXON_16 30 | ICYAEFTKIVKGINGVDDWYKGQWCGMVRTPKMHPHNGLSWCKMNRGNEH 31 | >TAXON_17 32 | ACPYEMRHNGVWKIHDYRICMMRVTWPTHNTRFDFPKFEYQESPGAQFQE 33 | >TAXON_18 34 | IEVWKEVRYDYLLFPEIANCTQGWFSHHYIKDIGCKPGISIACHMDSLSD 35 | >TAXON_19 36 | LVTKVVQEYKNYTRMFTYDVLQQYCMTEWTYDLFNHYGWVFYTASSFKWI -------------------------------------------------------------------------------- /static/example-files/fasta/bin1.txt: -------------------------------------------------------------------------------- 1 | >TAXON_1 2 | 1010101011010 3 | >TAXON_2 4 | 1010101010110 5 | >TAXON_3 6 | 1010101010110 7 | >TAXON_4 8 | 1010101010110 9 | >TAXON_5 10 | 1010101010110 11 | >TAXON_6 12 | 1010101010110 13 | >TAXON_7 14 | 1010101010111 15 | >TAXON_8 16 | 1010101010111 17 | >TAXON_9 18 | 1010101010110 19 | >TAXON_10 20 | 1010101011011 21 | -------------------------------------------------------------------------------- /static/example-files/fasta/bin2.txt: -------------------------------------------------------------------------------- 1 | >TAXON_11 2 | 1011110111 3 | >TAXON_2 4 | 1010110111 5 | >TAXON_23 6 | 1010101111 7 | >TAXON_4 8 | 1010011111 9 | >TAXON_15 10 | 1010011110 11 | >TAXON_6 12 | 1001011110 13 | >TAXON_27 14 | 1101011110 15 | >TAXON_8 16 | 1101011110 17 | >TAXON_19 18 | 1001011110 19 | >TAXON_10 20 | 1101011110 21 | -------------------------------------------------------------------------------- /static/example-files/fasta/binary.txt: -------------------------------------------------------------------------------- 1 | >TAXON_1 2 | 1010101011010111101110110011010111111010110101011110 3 | >TAXON_2 4 | 1010101010110101101110110110110110111010110100111110 5 | >TAXON_3 6 | 1010101010110101011110110110101110111010110100111101 7 | >TAXON_4 8 | 1010101010110100111110110110101110111010110010111100 9 | >TAXON_5 10 | 1010101010110100111101010110101101101010111010111100 11 | >TAXON_6 12 | 1010101010110010111100110110100100011010111010111100 13 | >TAXON_7 14 | 1010101010111010111100110110100010111010111101101101 15 | >TAXON_8 16 | 1010101010111010111100101110100010111001111101101101 17 | >TAXON_9 18 | 1010101010110010111100101110100001011001111010101101 19 | >TAXON_10 20 | 1010101011011010111100101110100010110101111001101101 21 | >TAXON_11 22 | 1010101010110101010111101101101011101101101101011101 23 | >TAXON_13 24 | 1010101010110101001111101101101011101101101101011101 25 | >TAXON_14 26 | 1010101010110101001111010101101011011010101101011011 27 | >TAXON_15 28 | 1010101010010111101111001101101001000001101101001000 29 | >TAXON_16 30 | 1010101010010111101111001101101000101001101101000101 31 | >TAXON_17 32 | 1010101010010111101111001011101000101001011101000101 33 | >TAXON_18 34 | 1010101010010111101111001011101000010001011101000010 35 | >TAXON_19 36 | 1010101010010111101111001011101000101001011101000101 -------------------------------------------------------------------------------- /static/example-files/fasta/dna.txt: -------------------------------------------------------------------------------- 1 | >Turkey 2 | AAGCTNGGGC ATTTCAGGGT GAGCCCGGGC AATACAGGGT AT 3 | >Salmo gair 4 | AAGCCTTGGC AGTGCAGGGT GAGCCGTGGC CGGGCACGGT AT 5 | >H. Sapiens 6 | ACCGGTTGGC CGTTCAGGGT ACAGGTTGGC CGTTCAGGGT AA 7 | >Chimp 8 | AAACCCTTGC CGTTACGCTT AAACCGAGGC CGGGACACTC AT 9 | >Gorilla 10 | AAACCCTTGC CGGTACGCTT AAACCATTGC CGGTACGCTT AA 11 | -------------------------------------------------------------------------------- /static/example-files/fasta/multistate.txt: -------------------------------------------------------------------------------- 1 | >TAXON_1 2 | 10101010110101111011102222210131311110101101010111 3 | >TAXON_2 4 | 10101010101101011011102222210131301110101101001111 5 | >TAXON_3 6 | 12222210101101010111102222201131301110101101001111 7 | >TAXON_4 8 | 12222210101101001111102222201131301110101100101111 9 | >TAXON_5 10 | 12222210101101001111012222201130311010101110101111 11 | >TAXON_6 12 | 12222210101100101111002222200130300110101110101111 13 | >TAXON_7 14 | 12222210101110101111002222200031301110101111011011 15 | >TAXON_8 16 | 12222210101110101111002222200031301110011111011011 17 | >TAXON_9 18 | 12222210101100101111002222200030310110011110121011 19 | >TAXON_10 20 | 12222210110110101111002222200021201101011110021011 21 | >TAXON_11 22 | 12222210101101010101112222201021211011011011020111 23 | >TAXON_13 24 | 12333310101101010011112222201021211011011011020111 25 | >TAXON_14 26 | 12333310101101010011110101011010110110101011020110 27 | >TAXON_15 28 | 12333310100101111011110011011010010000011011020010 29 | >TAXON_16 30 | 12333310100101111011110011011010001010011011020001 31 | >TAXON_17 32 | 12333310100101111011110010111010001010010111020001 33 | >TAXON_18 34 | 10101010100101111011110010111010000100010111010000 35 | >TAXON_19 36 | 10101010100101111011110010111010001010010111010001 -------------------------------------------------------------------------------- /static/example-files/fasta/partition_file.txt: -------------------------------------------------------------------------------- 1 | DNA, gene1 = 1-3676 2 | BIN, morph = 3677-3851 -------------------------------------------------------------------------------- /static/example-files/fasta/test.fa: -------------------------------------------------------------------------------- 1 | >Cow 2 | ATGGCATATCCCATACAACTAGGATTCCAAGATGCAACATCACCAATCATAGAAGAACTA 3 | CTTCACTTTCATGACCACACGCTAATAATTGTCTTCTTAATTAGCTCATTAGTACTTTAC 4 | ATTATTTCACTAATACTAACGACAAAGCTGACCCATACAAGCACGATAGATGCACAAGAA 5 | GTAGAGACAATCTGAACCATTCTGCCCGCCATCATCTTAATTCTAATTGCTCTTCCTTCT 6 | TTACGAATTCTATACATAATAGATGAAATCAATAACCCATCTCTTACAGTAAAAACCATA 7 | GGACATCAGTGATACTGAAGCTATGAGTATACAGATTATGAGGACTTAAGCTTCGACTCC 8 | TACATAATTCCAACATCAGAATTAAAGCCAGGGGAGCTACGACTATTAGAAGTCGATAAT 9 | CGAGTTGTACTACCAATAGAAATAACAATCCGAATGTTAGTCTCCTCTGAAGACGTATTA 10 | CACTCATGAGCTGTGCCCTCTCTAGGACTAAAAACAGACGCAATCCCAGGCCGTCTAAAC 11 | CAAACAACCCTTATATCGTCCCGTCCAGGCTTATATTACGGTCAATGCTCAGAAATTTGC 12 | GGGTCAAACCACAGTTTCATACCCATTGTCCTTGAGTTAGTCCCACTAAAGTACTTTGAA 13 | AAATGATCTGCGTCAATATTA---------------------TAA 14 | >Chicken 15 | ATGGCCAACCACTCCCAACTAGGCTTTCAAGACGCCTCATCCCCCATCATAGAAGAGCTC 16 | GTTGAATTCCACGACCACGCCCTGATAGTCGCACTAGCAATTTGCAGCTTAGTACTCTAC 17 | CTTCTAACTCTTATACTTATAGAAAAACTATCA---TCAAACACCGTAGATGCCCAAGAA 18 | GTTGAACTAATCTGAACCATCCTACCCGCTATTGTCCTAGTCCTGCTTGCCCTCCCCTCC 19 | CTCCAAATCCTCTACATAATAGACGAAATCGACGAACCTGATCTCACCCTAAAAGCCATC 20 | GGACACCAATGATACTGAACCTATGAATACACAGACTTCAAGGACCTCTCATTTGACTCC 21 | TACATAACCCCAACAACAGACCTCCCCCTAGGCCACTTCCGCCTACTAGAAGTCGACCAT 22 | CGCATTGTAATCCCCATAGAATCCCCCATTCGAGTAATCATCACCGCTGATGACGTCCTC 23 | CACTCATGAGCCGTACCCGCCCTCGGGGTAAAAACAGACGCAATCCCTGGACGACTAAAT 24 | CAAACCTCCTTCATCACCACTCGACCAGGAGTGTTTTACGGACAATGCTCAGAAATCTGC 25 | GGAGCTAACCACAGCTACATACCCATTGTAGTAGAGTCTACCCCCCTAAAACACTTTGAA 26 | GCCTGATCCTCACTA------------------CTGTCATCTTAA 27 | >Human 28 | ATGGCACATGCAGCGCAAGTAGGTCTACAAGACGCTACTTCCCCTATCATAGAAGAGCTT 29 | ATCACCTTTCATGATCACGCCCTCATAATCATTTTCCTTATCTGCTTCCTAGTCCTGTAT 30 | GCCCTTTTCCTAACACTCACAACAAAACTAACTAATACTAACATCTCAGACGCTCAGGAA 31 | ATAGAAACCGTCTGAACTATCCTGCCCGCCATCATCCTAGTCCTCATCGCCCTCCCATCC 32 | CTACGCATCCTTTACATAACAGACGAGGTCAACGATCCCTCCCTTACCATCAAATCAATT 33 | GGCCACCAATGGTACTGAACCTACGAGTACACCGACTACGGCGGACTAATCTTCAACTCC 34 | TACATACTTCCCCCATTATTCCTAGAACCAGGCGACCTGCGACTCCTTGACGTTGACAAT 35 | CGAGTAGTACTCCCGATTGAAGCCCCCATTCGTATAATAATTACATCACAAGACGTCTTG 36 | CACTCATGAGCTGTCCCCACATTAGGCTTAAAAACAGATGCAATTCCCGGACGTCTAAAC 37 | CAAACCACTTTCACCGCTACACGACCGGGGGTATACTACGGTCAATGCTCTGAAATCTGT 38 | GGAGCAAACCACAGTTTCATGCCCATCGTCCTAGAATTAATTCCCCTAAAAATCTTTGAA 39 | ATA---------------------GGGCCCGTATTTACCCTATAG 40 | >Loach 41 | ATGGCACATCCCACACAATTAGGATTCCAAGACGCGGCCTCACCCGTAATAGAAGAACTT 42 | CTTCACTTCCATGACCATGCCCTAATAATTGTATTTTTGATTAGCGCCCTAGTACTTTAT 43 | GTTATTATTACAACCGTCTCAACAAAACTCACTAACATATATATTTTGGACTCACAAGAA 44 | ATTGAAATCGTATGAACTGTGCTCCCTGCCCTAATCCTCATTTTAATCGCCCTCCCCTCA 45 | CTACGAATTCTATATCTTATAGACGAGATTAATGACCCCCACCTAACAATTAAGGCCATG 46 | GGGCACCAATGATACTGAAGCTACGAGTATACTGATTATGAAAACTTAAGTTTTGACTCC 47 | TACATAATCCCCACCCAGGACCTAACCCCTGGACAATTCCGGCTACTAGAGACAGACCAC 48 | CGAATGGTTGTTCCCATAGAATCCCCTATTCGCATTCTTGTTTCCGCCGAAGATGTACTA 49 | CACTCCTGGGCCCTTCCAGCCATGGGGGTAAAGATAGACGCGGTCCCAGGACGCCTTAAC 50 | CAAACCGCCTTTATTGCCTCCCGCCCCGGGGTATTCTATGGGCAATGCTCAGAAATCTGT 51 | GGAGCAAACCACAGCTTTATACCCATCGTAGTAGAAGCGGTCCCACTATCTCACTTCGAA 52 | AACTGGTCCACCCTTATACTAAAAGACGCCTCACTAGGAAGCTAA 53 | >Mouse 54 | ATGGCCTACCCATTCCAACTTGGTCTACAAGACGCCACATCCCCTATTATAGAAGAGCTA 55 | ATAAATTTCCATGATCACACACTAATAATTGTTTTCCTAATTAGCTCCTTAGTCCTCTAT 56 | ATCATCTCGCTAATATTAACAACAAAACTAACACATACAAGCACAATAGATGCACAAGAA 57 | GTTGAAACCATTTGAACTATTCTACCAGCTGTAATCCTTATCATAATTGCTCTCCCCTCT 58 | CTACGCATTCTATATATAATAGACGAAATCAACAACCCCGTATTAACCGTTAAAACCATA 59 | GGGCACCAATGATACTGAAGCTACGAATATACTGACTATGAAGACCTATGCTTTGATTCA 60 | TATATAATCCCAACAAACGACCTAAAACCTGGTGAACTACGACTGCTAGAAGTTGATAAC 61 | CGAGTCGTTCTGCCAATAGAACTTCCAATCCGTATATTAATTTCATCTGAAGACGTCCTC 62 | CACTCATGAGCAGTCCCCTCCCTAGGACTTAAAACTGATGCCATCCCAGGCCGACTAAAT 63 | CAAGCAACAGTAACATCAAACCGACCAGGGTTATTCTATGGCCAATGCTCTGAAATTTGT 64 | GGATCTAACCATAGCTTTATGCCCATTGTCCTAGAAATGGTTCCACTAAAATATTTCGAA 65 | AACTGATCTGCTTCAATAATT---------------------TAA 66 | >Seal 67 | ATGGCATACCCCCTACAAATAGGCCTACAAGATGCAACCTCTCCCATTATAGAGGAGTTA 68 | CTACACTTCCATGACCACACATTAATAATTGTGTTCCTAATTAGCTCATTAGTACTCTAC 69 | ATTATCTCACTTATACTAACCACGAAACTCACCCACACAAGTACAATAGACGCACAAGAA 70 | GTGGAAACGGTGTGAACGATCCTACCCGCTATCATTTTAATTCTCATTGCCCTACCATCA 71 | TTACGAATCCTCTACATAATGGACGAGATCAATAACCCTTCCTTGACCGTAAAAACTATA 72 | GGACATCAGTGATACTGAAGCTATGAGTACACAGACTACGAAGACCTGAACTTTGACTCA 73 | TATATGATCCCCACACAAGAACTAAAGCCCGGAGAACTACGACTGCTAGAAGTAGACAAT 74 | CGAGTAGTCCTCCCAATAGAAATAACAATCCGCATACTAATCTCATCAGAAGATGTACTC 75 | CACTCATGAGCCGTACCGTCCCTAGGACTAAAAACTGATGCTATCCCAGGACGACTAAAC 76 | CAAACAACCCTAATAACCATACGACCAGGACTGTACTACGGTCAATGCTCAGAAATCTGT 77 | GGTTCAAACCACAGCTTCATACCTATTGTCCTCGAATTGGTCCCACTATCCCACTTCGAG 78 | AAATGATCTACCTCAATGCTT---------------------TAA 79 | >Whale 80 | ATGGCATATCCATTCCAACTAGGTTTCCAAGATGCAGCATCACCCATCATAGAAGAGCTC 81 | CTACACTTTCACGATCATACACTAATAATCGTTTTTCTAATTAGCTCTTTAGTTCTCTAC 82 | ATTATTACCCTAATGCTTACAACCAAATTAACACATACTAGTACAATAGACGCCCAAGAA 83 | GTAGAAACTGTCTGAACTATCCTCCCAGCCATTATCTTAATTTTAATTGCCTTGCCTTCA 84 | TTACGGATCCTTTACATAATAGACGAAGTCAATAACCCCTCCCTCACTGTAAAAACAATA 85 | GGTCACCAATGATATTGAAGCTATGAGTATACCGACTACGAAGACCTAAGCTTCGACTCC 86 | TATATAATCCCAACATCAGACCTAAAGCCAGGAGAACTACGATTATTAGAAGTAGATAAC 87 | CGAGTTGTCTTACCTATAGAAATAACAATCCGAATATTAGTCTCATCAGAAGACGTACTC 88 | CACTCATGGGCCGTACCCTCCTTGGGCCTAAAAACAGATGCAATCCCAGGACGCCTAAAC 89 | CAAACAACCTTAATATCAACACGACCAGGCCTATTTTATGGACAATGCTCAGAGATCTGC 90 | GGCTCAAACCACAGTTTCATACCAATTGTCCTAGAACTAGTACCCCTAGAAGTCTTTGAA 91 | AAATGATCTGTATCAATACTA---------------------TAA 92 | >Frog 93 | ATGGCACACCCATCACAATTAGGTTTTCAAGACGCAGCCTCTCCAATTATAGAAGAATTA 94 | CTTCACTTCCACGACCATACCCTCATAGCCGTTTTTCTTATTAGTACGCTAGTTCTTTAC 95 | ATTATTACTATTATAATAACTACTAAACTAACTAATACAAACCTAATGGACGCACAAGAG 96 | ATCGAAATAGTGTGAACTATTATACCAGCTATTAGCCTCATCATAATTGCCCTTCCATCC 97 | CTTCGTATCCTATATTTAATAGATGAAGTTAATGATCCACACTTAACAATTAAAGCAATC 98 | GGCCACCAATGATACTGAAGCTACGAATATACTAACTATGAGGATCTCTCATTTGACTCT 99 | TATATAATTCCAACTAATGACCTTACCCCTGGACAATTCCGGCTGCTAGAAGTTGATAAT 100 | CGAATAGTAGTCCCAATAGAATCTCCAACCCGACTTTTAGTTACAGCCGAAGACGTCCTC 101 | CACTCGTGAGCTGTACCCTCCTTGGGTGTCAAAACAGATGCAATCCCAGGACGACTTCAT 102 | CAAACATCATTTATTGCTACTCGTCCGGGAGTATTTTACGGACAATGTTCAGAAATTTGC 103 | GGAGCAAACCACAGCTTTATACCAATTGTAGTTGAAGCAGTACCGCTAACCGACTTTGAA 104 | AACTGATCTTCATCAATACTA---GAAGCATCACTA------AGA -------------------------------------------------------------------------------- /static/example-files/nexus/aminoacid.nex: -------------------------------------------------------------------------------- 1 | #NEXUS 2 | 3 | Begin data; 4 | Dimensions ntax=10 nchar=234; 5 | Format datatype=protein gap=- interleave; 6 | Matrix 7 | Cow MAYPMQLGFQDATSPIMEELLHFHDHTLMIVFLISSLVLYIISLMLTTKLTHTSTMDAQE 8 | Carp MAHPTQLGFKDAAMPVMEELLHFHDHALMIVLLISTLVLYIITAMVSTKLTNKYILDSQE 9 | Chicken MANHSQLGFQDASSPIMEELVEFHDHALMVALAICSLVLYLLTLMLMEKLS-SNTVDAQE 10 | Human MAHAAQVGLQDATSPIMEELITFHDHALMIIFLICFLVLYALFLTLTTKLTNTNISDAQE 11 | Loach MAHPTQLGFQDAASPVMEELLHFHDHALMIVFLISALVLYVIITTVSTKLTNMYILDSQE 12 | Mouse MAYPFQLGLQDATSPIMEELMNFHDHTLMIVFLISSLVLYIISLMLTTKLTHTSTMDAQE 13 | Rat MAYPFQLGLQDATSPIMEELTNFHDHTLMIVFLISSLVLYIISLMLTTKLTHTSTMDAQE 14 | Seal MAYPLQMGLQDATSPIMEELLHFHDHTLMIVFLISSLVLYIISLMLTTKLTHTSTMDAQE 15 | Whale MAYPFQLGFQDAASPIMEELLHFHDHTLMIVFLISSLVLYIITLMLTTKLTHTSTMDAQE 16 | Frog MAHPSQLGFQDAASPIMEELLHFHDHTLMAVFLISTLVLYIITIMMTTKLTNTNLMDAQE 17 | 18 | Cow VETIWTILPAIILILIALPSLRILYMMDEINNPSLTVKTMGHQWYWSYEYTDYEDLSFDS 19 | Carp IEIVWTILPAVILVLIALPSLRILYLMDEINDPHLTIKAMGHQWYWSYEYTDYENLGFDS 20 | Chicken VELIWTILPAIVLVLLALPSLQILYMMDEIDEPDLTLKAIGHQWYWTYEYTDFKDLSFDS 21 | Human METVWTILPAIILVLIALPSLRILYMTDEVNDPSLTIKSIGHQWYWTYEYTDYGGLIFNS 22 | Loach IEIVWTVLPALILILIALPSLRILYLMDEINDPHLTIKAMGHQWYWSYEYTDYENLSFDS 23 | Mouse VETIWTILPAVILIMIALPSLRILYMMDEINNPVLTVKTMGHQWYWSYEYTDYEDLCFDS 24 | Rat VETIWTILPAVILILIALPSLRILYMMDEINNPVLTVKTMGHQWYWSYEYTDYEDLCFDS 25 | Seal VETVWTILPAIILILIALPSLRILYMMDEINNPSLTVKTMGHQWYWSYEYTDYEDLNFDS 26 | Whale VETVWTILPAIILILIALPSLRILYMMDEVNNPSLTVKTMGHQWYWSYEYTDYEDLSFDS 27 | Frog IEMVWTIMPAISLIMIALPSLRILYLMDEVNDPHLTIKAIGHQWYWSYEYTNYEDLSFDS 28 | 29 | Cow YMIPTSELKPGELRLLEVDNRVVLPMEMTIRMLVSSEDVLHSWAVPSLGLKTDAIPGRLN 30 | Carp YMVPTQDLAPGQFRLLETDHRMVVPMESPVRVLVSAEDVLHSWAVPSLGVKMDAVPGRLN 31 | Chicken YMTPTTDLPLGHFRLLEVDHRIVIPMESPIRVIITADDVLHSWAVPALGVKTDAIPGRLN 32 | Human YMLPPLFLEPGDLRLLDVDNRVVLPIEAPIRMMITSQDVLHSWAVPTLGLKTDAIPGRLN 33 | Loach YMIPTQDLTPGQFRLLETDHRMVVPMESPIRILVSAEDVLHSWALPAMGVKMDAVPGRLN 34 | Mouse YMIPTNDLKPGELRLLEVDNRVVLPMELPIRMLISSEDVLHSWAVPSLGLKTDAIPGRLN 35 | Rat YMIPTNDLKPGELRLLEVDNRVVLPMELPIRMLISSEDVLHSWAIPSLGLKTDAIPGRLN 36 | Seal YMIPTQELKPGELRLLEVDNRVVLPMEMTIRMLISSEDVLHSWAVPSLGLKTDAIPGRLN 37 | Whale YMIPTSDLKPGELRLLEVDNRVVLPMEMTIRMLVSSEDVLHSWAVPSLGLKTDAIPGRLN 38 | Frog YMIPTNDLTPGQFRLLEVDNRMVVPMESPTRLLVTAEDVLHSWAVPSLGVKTDAIPGRLH 39 | 40 | Cow QTTLMSSRPGLYYGQCSEICGSNHSFMPIVLELVPLKYFEKWSASML------- 41 | Carp QAAFIASRPGVFYGQCSEICGANHSFMPIVVEAVPLEHFENWSSLMLEDASLGS 42 | Chicken QTSFITTRPGVFYGQCSEICGANHSYMPIVVESTPLKHFEAWSSL------LSS 43 | Human QTTFTATRPGVYYGQCSEICGANHSFMPIVLELIPLKIFEM-------GPVFTL 44 | Loach QTAFIASRPGVFYGQCSEICGANHSFMPIVVEAVPLSHFENWSTLMLKDASLGS 45 | Mouse QATVTSNRPGLFYGQCSEICGSNHSFMPIVLEMVPLKYFENWSASMI------- 46 | Rat QATVTSNRPGLFYGQCSEICGSNHSFMPIVLEMVPLKYFENWSASMI------- 47 | Seal QTTLMTMRPGLYYGQCSEICGSNHSFMPIVLELVPLSHFEKWSTSML------- 48 | Whale QTTLMSTRPGLFYGQCSEICGSNHSFMPIVLELVPLEVFEKWSVSML------- 49 | Frog QTSFIATRPGVFYGQCSEICGANHSFMPIVVEAVPLTDFENWSSSML-EASL-- 50 | ; 51 | End; 52 | -------------------------------------------------------------------------------- /static/example-files/phylip/AA.txt: -------------------------------------------------------------------------------- 1 | 20 100 2 | taxon_1 VPPYRWVAGVFITQYMNNIVYDDRISDLCKPVFLINPCHCAPFSGKTIGQ 3 | taxon_2 WKEPTYIISEFFYVKTAWYWEVESSSSNFIKECIEACEQPYNHSGCKKFE 4 | taxon_3 EGPRSPINHSAEHMVSQLISDCKMWEHPYTTCRGKEVFWFTIKPWACKIH 5 | taxon_4 GRHFCWCSTRDAANPVRLCHKVQNCDDVKGQANSCLWSIMEKFERMIIEP 6 | taxon_5 DEDCSHPPVYDSPDDSISDHQDGNNEFDTLGMWGMVYPRWSCAWMIAKKN 7 | taxon_6 CAWCKDKPWPRSHTISKLYHHDFYKHFMTRSWTIILCQYSEAKPSFTQIS 8 | taxon_7 YCINQMANLHEWNVVGNARSKRSCRIGRCNSKEMRSKAREMESESGFRVQ 9 | taxon_8 QQPMSHMLWFTHEECWDHVGSHTPRYEKKRPQCTVPHLDKIDPLRLALHG 10 | taxon_9 PAQNMDTFQKGRLAWRMFDYQWNQKGDIHKASTVGAKLGESGTAGGFSYP 11 | taxon_10 YENFLWSGCWGHLFGATWMRGEKKMDHQVDYHHHLPCFFPDTIWFVDEEF 12 | taxon_11 LEYHMCCMAHESGKCCTIAKWAHCSSIIWMQPGQLSANHFDEEKSVIADQ 13 | taxon_12 TVNYNLFWIFVFWLYASDNYYTPFLNEKPQEFQGAWYGYHWFDYQPHIVP 14 | taxon_13 FAKVELIGVKILDFYGKFMDFFNDCDDEITQRFLTLHSVHPQASSIHKWH 15 | taxon_14 GNARGVCQKKCSFMRMVEHIQFDKTFMALSVRRECLLDAATSRLIDAPFM 16 | taxon_15 ICYAEFTKIVKGINGVDDWYKGQWCGMVRTPKMHPHNGLSWCKMNRGNEH 17 | taxon_16 ACPYEMRHNGVWKIHDYRICMMRVTWPTHNTRFDFPKFEYQESPGAQFQE 18 | taxon_17 IEVWKEVRYDYLLFPEIANCTQGWFSHHYIKDIGCKPGISIACHMDSLSD 19 | taxon_18 LVTKVVQEYKNYTRMFTYDVLQQYCMTEWTYDLFNHYGWVFYTASSFKWI 20 | taxon_19 YYVKYPMNWSRATHDHNKWSSTVQIVAMGHIWIQFFQRDSRFVHIAVMRD 21 | taxon_20 KVIHKWKKHLVNEKYHSEMYLAIGTSSWVTFWEDCMWQFDCCFPDNGTVC 22 | 23 | DLSSTILQGDMTIDDSWINSDRGEMMFVRIRRCNDIWVFAMRMYYQWSSQ 24 | ESCVKFVTYEADWPKVGFSQCKESKAVTAVHIPCNQIVQGNKPIHLHWEF 25 | QWYICIIREHNFSWQWCMNLFNKNWWCNVVKRSCWHAHGFPRCNACNWRI 26 | GNETAMNKVGTNGKGATQKKFRNNLYNFFFAWQSMCHMHMLTAYHTYCAY 27 | FNNHPHLGIHFCEPIGLDTNANFNVQGHIRMLLTHPMIDSVQTDFSPCTW 28 | HIAMDPNTPVYLCIAEGTTIKANCNEFWWWSVRDLRFKMATPYHQQSPKK 29 | EACHEIEFALFGAQGHEVGNYLMCFIWKGMWFERLWNKHQIYKGCDTSAP 30 | GDWKMCWRNTYGGEISHVGKEFPKPLPYYSIYEGSDHKSTQILKHIELTC 31 | RSKTDKFLRLFANIPYSEWCDIAEEEDSGCCHAHTPYGMFLFAITESFTL 32 | VQASVIAFYPHMRCGHPRVPTIGSNCCWVGAFDPTREPRLRYILYSYIDF 33 | GYPMVECCSCKIIAGDEWKDSLQRPGSSFGDYLTSVRGVTGNCQWNNCFY 34 | SWFHGKFMKRGGKNLVNSQISRNVIRFMHHSGLCKIDFMSVEFVSMATNW 35 | GTVTQINPISLQRKMNTIFSIEDHTIDSFVQHASPINLPVGWVNTDTYKA 36 | LNNKHPLNERTDFMLKLKYNQDCSPEWGYADGAGIKRVAFEYIAHRPPNQ 37 | AVAIINTKWEWCIELECYKHQRYLHTEVQLRIQMKQAIAHKMKITWFRRA 38 | SHRGMVQHDRVTPYNQFSVPVDYVKFRTMALEDNYGELRTIPMMLCEFNK 39 | LWEEMKHQIMYHESEFEYGIIYKPVECIWYCTLWTRDMNSYRFSDLAVYP 40 | DCNNSAYGAANDENQSSDRAVMCTHVGQNMHERCACHGWCGKMNCLFYCG 41 | PYFKQGFIQIRVMHARFAHCILWAMATWKEAHLHKSNWHGLYEQPLMKCM 42 | RHLQYPWDDCLYMSLMADQFPVGMQMQLWQIFAVVCERDHGYCGTHNARV 43 | -------------------------------------------------------------------------------- /static/example-files/phylip/aminoacid.txt: -------------------------------------------------------------------------------- 1 | 18 50 2 | 3 | TAXON_1 VPPYRWVAGVFITQYMNNIVYDDRISDLCKPVFLINPCHCAPFSGKTIGQ 4 | TAXON_2 WKEPTYIISEFFYVKTAWYWEVESSSSNFIKECIEACEQPYNHSGCKKFE 5 | TAXON_3 EGPRSPINHSAEHMVSQLISDCKMWEHPYTTCRGKEVFWFTIKPWACKIH 6 | TAXON_4 GRHFCWCSTRDAANPVRLCHKVQNCDDVKGQANSCLWSIMEKFERMIIEP 7 | TAXON_5 DEDCSHPPVYDSPDDSISDHQDGNNEFDTLGMWGMVYPRWSCAWMIAKKN 8 | TAXON_6 CAWCKDKPWPRSHTISKLYHHDFYKHFMTRSWTIILCQYSEAKPSFTQIS 9 | TAXON_7 YCINQMANLHEWNVVGNARSKRSCRIGRCNSKEMRSKAREMESESGFRVQ 10 | TAXON_8 QQPMSHMLWFTHEECWDHVGSHTPRYEKKRPQCTVPHLDKIDPLRLALHG 11 | TAXON_9 PAQNMDTFQKGRLAWRMFDYQWNQKGDIHKASTVGAKLGESGTAGGFSYP 12 | TAXON_10 YENFLWSGCWGHLFGATWMRGEKKMDHQVDYHHHLPCFFPDTIWFVDEEF 13 | TAXON_11 LEYHMCCMAHESGKCCTIAKWAHCSSIIWMQPGQLSANHFDEEKSVIADQ 14 | TAXON_13 TVNYNLFWIFVFWLYASDNYYTPFLNEKPQEFQGAWYGYHWFDYQPHIVP 15 | TAXON_14 FAKVELIGVKILDFYGKFMDFFNDCDDEITQRFLTLHSVHPQASSIHKWH 16 | TAXON_15 GNARGVCQKKCSFMRMVEHIQFDKTFMALSVRRECLLDAATSRLIDAPFM 17 | TAXON_16 ICYAEFTKIVKGINGVDDWYKGQWCGMVRTPKMHPHNGLSWCKMNRGNEH 18 | TAXON_17 ACPYEMRHNGVWKIHDYRICMMRVTWPTHNTRFDFPKFEYQESPGAQFQE 19 | TAXON_18 IEVWKEVRYDYLLFPEIANCTQGWFSHHYIKDIGCKPGISIACHMDSLSD 20 | TAXON_19 LVTKVVQEYKNYTRMFTYDVLQQYCMTEWTYDLFNHYGWVFYTASSFKWI 21 | -------------------------------------------------------------------------------- /static/example-files/phylip/binary.txt: -------------------------------------------------------------------------------- 1 | 18 52 2 | TAXON_1 1010101011010111101110110011010111111010110101011110 3 | TAXON_2 1010101010110101101110110110110110111010110100111110 4 | TAXON_3 1010101010110101011110110110101110111010110100111101 5 | TAXON_4 1010101010110100111110110110101110111010110010111100 6 | TAXON_5 1010101010110100111101010110101101101010111010111100 7 | TAXON_6 1010101010110010111100110110100100011010111010111100 8 | TAXON_7 1010101010111010111100110110100010111010111101101101 9 | TAXON_8 1010101010111010111100101110100010111001111101101101 10 | TAXON_9 1010101010110010111100101110100001011001111010101101 11 | TAXON_10 1010101011011010111100101110100010110101111001101101 12 | TAXON_11 1010101010110101010111101101101011101101101101011101 13 | TAXON_13 1010101010110101001111101101101011101101101101011101 14 | TAXON_14 1010101010110101001111010101101011011010101101011011 15 | TAXON_15 1010101010010111101111001101101001000001101101001000 16 | TAXON_16 1010101010010111101111001101101000101001101101000101 17 | TAXON_17 1010101010010111101111001011101000101001011101000101 18 | TAXON_18 1010101010010111101111001011101000010001011101000010 19 | TAXON_19 1010101010010111101111001011101000101001011101000101 20 | -------------------------------------------------------------------------------- /static/example-files/phylip/dna_interleaved.txt: -------------------------------------------------------------------------------- 1 | 5 42 2 | Turkey AAGCTNGGGC ATTTCAGGGT 3 | Salmo_gairAAGCCTTGGC AGTGCAGGGT 4 | H_Sapiens ACCGGTTGGC CGTTCAGGGT 5 | Chimp AAACCCTTGC CGTTACGCTT 6 | Gorilla AAACCCTTGC CGGTACGCTT 7 | 8 | GAGCCCGGGC AATACAGGGT AT 9 | GAGCCGTGGC CGGGCACGGT AT 10 | ACAGGTTGGC CGTTCAGGGT AA 11 | AAACCGAGGC CGGGACACTC AT 12 | AAACCATTGC CGGTACGCTT AA 13 | -------------------------------------------------------------------------------- /static/example-files/phylip/dna_interleaved_relaxed.txt: -------------------------------------------------------------------------------- 1 | 5 42 2 | Turkey AAGCTNGGGC ATTTCAGGGT 3 | Salmo_gair AAGCCTTGGC AGTGCAGGGT 4 | H_Sapiens ACCGGTTGGC CGTTCAGGGT 5 | Chimp AAACCCTTGC CGTTACGCTT 6 | Gorilla AAACCCTTGC CGGTACGCTT 7 | 8 | GAGCCCGGGC AATACAGGGT AT 9 | GAGCCGTGGC CGGGCACGGT AT 10 | ACAGGTTGGC CGTTCAGGGT AA 11 | AAACCGAGGC CGGGACACTC AT 12 | AAACCATTGC CGGTACGCTT AA 13 | -------------------------------------------------------------------------------- /static/example-files/phylip/dna_sequential.txt: -------------------------------------------------------------------------------- 1 | 5 42 2 | Turkey AAGCTNGGGC ATTTCAGGGT 3 | GAGCCCGGGC AATACAGGGT AT 4 | Salmo gairAAGCCTTGGC AGTGCAGGGT 5 | GAGCCGTGGC CGGGCACGGT AT 6 | H. SapiensACCGGTTGGC CGTTCAGGGT 7 | ACAGGTTGGC CGTTCAGGGT AA 8 | Chimp AAACCCTTGC CGTTACGCTT 9 | AAACCGAGGC CGGGACACTC AT 10 | Gorilla AAACCCTTGC CGGTACGCTT 11 | AAACCATTGC CGGTACGCTT AA 12 | -------------------------------------------------------------------------------- /static/example-files/phylip/dna_sequential_relaxed.txt: -------------------------------------------------------------------------------- 1 | 5 42 2 | Turkey AAGCTNGGGC ATTTCAGGGT 3 | GAGCCCGGGC AATACAGGGT AT 4 | Salmo_gair AAGCCTTGGC AGTGCAGGGT 5 | GAGCCGTGGC CGGGCACGGT AT 6 | H_Sapiens ACCGGTTGGC CGTTCAGGGT 7 | ACAGGTTGGC CGTTCAGGGT AA 8 | Chimp AAACCCTTGC CGTTACGCTT 9 | AAACCGAGGC CGGGACACTC AT 10 | Gorilla AAACCCTTGC CGGTACGCTT 11 | AAACCATTGC CGGTACGCTT AA 12 | -------------------------------------------------------------------------------- /static/example-files/phylip/multistate.txt: -------------------------------------------------------------------------------- 1 | 18 50 2 | TAXON_1 10101010110101111011102222210131311110101101010111 3 | TAXON_2 10101010101101011011102222210131301110101101001111 4 | TAXON_3 12222210101101010111102222201131301110101101001111 5 | TAXON_4 12222210101101001111102222201131301110101100101111 6 | TAXON_5 12222210101101001111012222201130311010101110101111 7 | TAXON_6 12222210101100101111002222200130300110101110101111 8 | TAXON_7 12222210101110101111002222200031301110101111011011 9 | TAXON_8 12222210101110101111002222200031301110011111011011 10 | TAXON_9 12222210101100101111002222200030310110011110121011 11 | TAXON_10 12222210110110101111002222200021201101011110021011 12 | TAXON_11 12222210101101010101112222201021211011011011020111 13 | TAXON_13 12333310101101010011112222201021211011011011020111 14 | TAXON_14 12333310101101010011110101011010110110101011020110 15 | TAXON_15 12333310100101111011110011011010010000011011020010 16 | TAXON_16 12333310100101111011110011011010001010011011020001 17 | TAXON_17 12333310100101111011110010111010001010010111020001 18 | TAXON_18 10101010100101111011110010111010000100010111010000 19 | TAXON_19 10101010100101111011110010111010001010010111010001 20 | -------------------------------------------------------------------------------- /static/example-files/phylip/partition_file.txt: -------------------------------------------------------------------------------- 1 | DNA, gene1 = 1-3676 2 | BIN, morph = 3677-3851 -------------------------------------------------------------------------------- /static/example-files/tree/backboneConstraint/backboneConstraint.txt: -------------------------------------------------------------------------------- 1 | (Mouse, Rat, (Human, Whale)); 2 | -------------------------------------------------------------------------------- /static/example-files/tree/backboneConstraint/dna.phy: -------------------------------------------------------------------------------- 1 | 10 60 2 | Cow ATGGCATATCCCATACAACTAGGATTCCAAGATGCAACATCACCAATCATAGAAGAACTA 3 | Carp ATGGCACACCCAACGCAACTAGGTTTCAAGGACGCGGCCATACCCGTTATAGAGGAACTT 4 | Chicken ATGGCCAACCACTCCCAACTAGGCTTTCAAGACGCCTCATCCCCCATCATAGAAGAGCTC 5 | Human ATGGCACATGCAGCGCAAGTAGGTCTACAAGACGCTACTTCCCCTATCATAGAAGAGCTT 6 | Loach ATGGCACATCCCACACAATTAGGATTCCAAGACGCGGCCTCACCCGTAATAGAAGAACTT 7 | Mouse ATGGCCTACCCATTCCAACTTGGTCTACAAGACGCCACATCCCCTATTATAGAAGAGCTA 8 | Rat ATGGCTTACCCATTTCAACTTGGCTTACAAGACGCTACATCACCTATCATAGAAGAACTT 9 | Seal ATGGCATACCCCCTACAAATAGGCCTACAAGATGCAACCTCTCCCATTATAGAGGAGTTA 10 | Whale ATGGCATATCCATTCCAACTAGGTTTCCAAGATGCAGCATCACCCATCATAGAAGAGCTC 11 | Frog ATGGCACACCCATCACAATTAGGTTTTCAAGACGCAGCCTCTCCAATTATAGAAGAATTA 12 | -------------------------------------------------------------------------------- /static/example-files/tree/multifurcatingConstraint/dna.phy: -------------------------------------------------------------------------------- 1 | 10 60 2 | Cow ATGGCATATCCCATACAACTAGGATTCCAAGATGCAACATCACCAATCATAGAAGAACTA 3 | Carp ATGGCACACCCAACGCAACTAGGTTTCAAGGACGCGGCCATACCCGTTATAGAGGAACTT 4 | Chicken ATGGCCAACCACTCCCAACTAGGCTTTCAAGACGCCTCATCCCCCATCATAGAAGAGCTC 5 | Human ATGGCACATGCAGCGCAAGTAGGTCTACAAGACGCTACTTCCCCTATCATAGAAGAGCTT 6 | Loach ATGGCACATCCCACACAATTAGGATTCCAAGACGCGGCCTCACCCGTAATAGAAGAACTT 7 | Mouse ATGGCCTACCCATTCCAACTTGGTCTACAAGACGCCACATCCCCTATTATAGAAGAGCTA 8 | Rat ATGGCTTACCCATTTCAACTTGGCTTACAAGACGCTACATCACCTATCATAGAAGAACTT 9 | Seal ATGGCATACCCCCTACAAATAGGCCTACAAGATGCAACCTCTCCCATTATAGAGGAGTTA 10 | Whale ATGGCATATCCATTCCAACTAGGTTTCCAAGATGCAGCATCACCCATCATAGAAGAGCTC 11 | Frog ATGGCACACCCATCACAATTAGGTTTTCAAGACGCAGCCTCTCCAATTATAGAAGAATTA 12 | -------------------------------------------------------------------------------- /static/example-files/tree/multifurcatingConstraint/multifurcatingConstraint.txt: -------------------------------------------------------------------------------- 1 | (Mouse, Rat, Frog, Loach, (Human, Whale,Carp)); 2 | -------------------------------------------------------------------------------- /static/example-files/tree/test.tre: -------------------------------------------------------------------------------- 1 | ((Seal:0.100000,Cow:0.100000):0.100000,(Mouse:0.100000,(((Frog:0.100000,Whale:0.100000):0.100000,Loach:0.100000):0.100000,Chicken:0.100000):0.100000):0.100000,Human:0.100000):0.0; 2 | -------------------------------------------------------------------------------- /static/test-files/fail_bad_base_at_site.txt: -------------------------------------------------------------------------------- 1 | 5 52 2 | TAXON_1 1010101011010111101110110011010111111010110101011110 3 | TAXON_2 1010101,101_0101101110110110110110111010110100111110 4 | TAXON_3 10101010!!!10101011110110110101110111010110100111101 5 | TAXON_4 1010101010110100111110110110101110111010110010111100 6 | TAXON_5 1010101010110100111101010110101101101010111010111100 7 | -------------------------------------------------------------------------------- /static/test-files/fail_bad_name.txt: -------------------------------------------------------------------------------- 1 | 5 20 2 | Turkey AAGCTNGGGC ATTTCAGGGT 3 | Salmo_gair AAGCCTTGGC AGTGCAGGGT 4 | H.Sapiens. ACCGGTTGGC CGTTCAGGGT 5 | Chimp: AAACCCTTGC CGTTACGCTT 6 | Gorilla AAACCCTTGC CGGTACGCTT 7 | -------------------------------------------------------------------------------- /static/test-files/fail_duplicate_taxon.fas: -------------------------------------------------------------------------------- 1 | >TAXON_1 2 | 1010101011010111101110110011010111111010110101011110 3 | >TAXON_2 4 | 1010101010110101101110110110110110111010110100111110 5 | >TAXON_2 6 | 1010101010110101011110110110101110111010110100111101 7 | >TAXON_4 8 | 1010101010110100111110110110101110111010110010111100 9 | >TAXON_5 10 | 1010101010110100111101010110101101101010111010111100 11 | -------------------------------------------------------------------------------- /static/test-files/fail_duplicate_taxon.phy: -------------------------------------------------------------------------------- 1 | 5 52 2 | TAXON_1 1010101011010111101110110011010111111010110101011110 3 | TAXON_2 1010101010110101101110110110110110111010110100111110 4 | TAXON_2 1010101010110101011110110110101110111010110100111101 5 | TAXON_4 1010101010110100111110110110101110111010110010111100 6 | TAXON_5 1010101010110100111101010110101101101010111010111100 7 | -------------------------------------------------------------------------------- /static/test-files/fail_too_few_sequences_modeltest.txt: -------------------------------------------------------------------------------- 1 | 2 20 2 | H_Sapiens ACCGGTTGGC CGTTCAGGGT 3 | Chimp AAACCCTTGC CGTTACGCTT 4 | -------------------------------------------------------------------------------- /static/test-files/fail_too_few_sequences_raxml.txt: -------------------------------------------------------------------------------- 1 | 3 20 2 | H_Sapiens ACCGGTTGGC CGTTCAGGGT 3 | Chimp AAACCCTTGC CGTTACGCTT 4 | Gorilla AAACCCTTGC CGGTACGCTT 5 | -------------------------------------------------------------------------------- /static/test-files/fail_unequal_sequence_length.fas: -------------------------------------------------------------------------------- 1 | >TAXON_1 2 | 1010101011010111101110110011010111111010110101011110 3 | >TAXON_2 4 | 1010101010110101101110110110110110111010110100111110 5 | >TAXON_3 6 | 101010101011010101111011011010111011101011010011110 7 | >TAXON_4 8 | 1010101010110100111110110110101110111010110010111100 9 | >TAXON_5 10 | 1010101010110100111101010110101101101010111010111100 11 | -------------------------------------------------------------------------------- /static/test-files/fail_unequal_sequence_length.phy: -------------------------------------------------------------------------------- 1 | 5 52 2 | TAXON_1 1010101011010111101110110011010111111010110101011110 3 | TAXON_2 1010101010110101101110110110110110111010110100111110 4 | TAXON_3 101010101011010101111011011010111011101011010011110 5 | TAXON_4 1010101010110100111110110110101110111010110010111100 6 | TAXON_5 1010101010110100111101010110101101101010111010111100 7 | -------------------------------------------------------------------------------- /static/test-files/test_ambiguous_nucleotide.txt: -------------------------------------------------------------------------------- 1 | 5 20 2 | Turkey AAGCTYGGGC ATTTCAGGGT 3 | Salmo_gair AAGCCTTGGC AGTGCAGGGT 4 | H_Sapiens ACCGGTTGGC CGTTCAGGGT 5 | Chimp AAACCCTTGC CGTTACGCTT 6 | Gorilla AAACCCTTGC CGGTACGCTT 7 | -------------------------------------------------------------------------------- /static/test-files/test_interleaved.txt: -------------------------------------------------------------------------------- 1 | >gi|161085638|dbj|AB305033.1| 2 | ATATGCCTGAAAGTGGCGGACGGGTGAGTAACACGTGGGTGACCTGCCTCGGAGTGGGGGATAACCATGG 3 | GAAACTGTGGCTAATACCGCATGGGCTTGTTGGCTTTGGCGGCCAACGAGTAAAGCTTTAGTGCTTCGAG 4 | AGGGGCCTGCGTCCGATTAGGTAGTTGGTGAGGTAATGGCTCACCAAGCCGATGATCGGTAGCTGGTCTG 5 | >gi|161085638|dbj|AB305644.1| 6 | ATATGCCTGAAAGTGGCGGACGGGTGAGTAACACGTGGGTGACCTGCCTCGGAGTGGGGGATAACCATGG 7 | GAAACTGTGGCTAATACCGCATGGGCTTGTTGGCTTTGGCGGCCAACGAGTAAAGCTTTAGTGCTTCGAG 8 | AGGGGCCTGCGTCCGATTAGGTAGTTGGTGAGGTAATGGCTCACCAAGCCGATGATCGGTAGCTGGTCTG 9 | -------------------------------------------------------------------------------- /static/test-files/test_invariant_sites.txt: -------------------------------------------------------------------------------- 1 | 6 20 2 | Turkey AAGCTNGGGC ATTTCAGGGT 3 | Salmo_gair AAGCCTTGGC AGTGCAGGGT 4 | H_Sapiens ACCGGTTGGC CGTTCAGGGT 5 | Chimp AAACCCTTGC CGTTACGCTT 6 | Gorilla AAACCCTTGC CGGTACGCTT 7 | Invariant GGGGGGGGGG GGGGGGGGGG 8 | -------------------------------------------------------------------------------- /static/test-files/test_lower_case_bases.txt: -------------------------------------------------------------------------------- 1 | 5 20 2 | Turkey AAGCTNGGGC ATTTCAGGGT 3 | Salmo_gair aagccttggc AGTGCAGGGT 4 | H_Sapiens ACCGGTTGGC CGTTCAGGGT 5 | Chimp AAACCCTTGC CGTTACGCTT 6 | Gorilla AAACCCTTGC CGGTACGCTT 7 | -------------------------------------------------------------------------------- /static/test-files/test_questionmark_nucleotide.txt: -------------------------------------------------------------------------------- 1 | 5 20 2 | Turkey AAGCT?GGGC ATTTCAGGGT 3 | Salmo_gair AAGCCTTGGC AGTGCAGGGT 4 | H_Sapiens ACCGGTTGGC CGTTCAGGGT 5 | Chimp AAACCCTTGC CGTTACGCTT 6 | Gorilla AAACCCTTGC CGGTACGCTT 7 | -------------------------------------------------------------------------------- /static/test-files/wrong_site_count.txt: -------------------------------------------------------------------------------- 1 | 5 19 2 | Turkey AAGCTNGGGC ATTTCAGGGT 3 | Salmo_gair AAGCCTTGGC AGTGCAGGGT 4 | H.Sapiens. ACCGGTTGGC CGTTCAGGGT 5 | Chimp: AAACCCTTGC CGTTACGCTT 6 | Gorilla AAACCCTTGC CGGTACGCTT 7 | -------------------------------------------------------------------------------- /static/test-files/wrong_taxa_count.txt: -------------------------------------------------------------------------------- 1 | 6 20 2 | Turkey AAGCTNGGGC ATTTCAGGGT 3 | Salmo_gair AAGCCTTGGC AGTGCAGGGT 4 | H.Sapiens. ACCGGTTGGC CGTTCAGGGT 5 | Chimp: AAACCCTTGC CGTTACGCTT 6 | Gorilla AAACCCTTGC CGGTACGCTT 7 | -------------------------------------------------------------------------------- /static/test-results/ASTRAL_simulated_14taxon.gene.tre: -------------------------------------------------------------------------------- 1 | (9,(5,(((6,(11,0)0.5:0.07283732395226637)0.38:0.0,(2,((1,13)0.6:0.16788087263916016,(12,8)0.62:0.1518805312927191)0.51:0.07878087785311434)0.43:0.05049616401453223)0.46:0.04652001563489282,((10,7)0.92:0.4555629450909413,(4,3)0.79:0.315333603782291)0.51:0.0852051579461301)0.47:0.05548868561765336):0.0); 2 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const SentryWebpackPlugin = require('@sentry/webpack-plugin'); 2 | 3 | const package = require('./package.json'); 4 | 5 | module.exports = { 6 | // other webpack configuration 7 | devtool: 'source-map', 8 | plugins: [ 9 | new SentryWebpackPlugin({ 10 | // sentry-cli configuration - can also be done directly through sentry-cli 11 | // see https://docs.sentry.io/product/cli/configuration/ for details 12 | authToken: process.env.SENTRY_AUTH_TOKEN, 13 | org: process.env.SENTRY_ORG, 14 | project: process.env.SENTRY_PROJECT, 15 | release: `${package.productName}@${package.version}`, 16 | 17 | // other SentryWebpackPlugin configuration 18 | include: '.', 19 | ignore: ['node_modules', 'webpack.config.js'], 20 | }), 21 | ], 22 | }; 23 | --------------------------------------------------------------------------------