diff --git a/.env.production b/.env.production index 1018edd8..f292b18c 100644 --- a/.env.production +++ b/.env.production @@ -3,5 +3,5 @@ VUE_APP_I18N_FALLBACK_LOCALE=en VUE_APP_SERVER_PORT=64064 -VUE_APP_YATT_API_URL="https://api.yatt.ai/v1" +VUE_APP_TESTFIESTA_API_URL="https://api.testfiesta.com/v1" VUE_APP_JIRA_OAUTH_KEY="3tPI6y3UgOxjUUVd2ELL3mhZr6cGAatt" diff --git a/.github/ISSUE_TEMPLATE/01_BUG_REPORT.md b/.github/ISSUE_TEMPLATE/01_BUG_REPORT.md index d422f6ce..f1b29d6e 100644 --- a/.github/ISSUE_TEMPLATE/01_BUG_REPORT.md +++ b/.github/ISSUE_TEMPLATE/01_BUG_REPORT.md @@ -1,6 +1,6 @@ --- name: Bug Report -about: Create a report to help YATTIE to improve +about: Create a report to help Pinata to improve title: "bug: " labels: "bug" assignees: "" @@ -12,7 +12,7 @@ assignees: "" -**YATTIE version:** +**Pinata version:** diff --git a/.github/workflows/publish-action.yml b/.github/workflows/publish-action.yml index 10cc5acf..a167aa0f 100644 --- a/.github/workflows/publish-action.yml +++ b/.github/workflows/publish-action.yml @@ -30,7 +30,7 @@ jobs: run: npm run publish publish_on_x64_mac: - runs-on: macos-latest + runs-on: macos-13 strategy: matrix: os: [macos-latest] @@ -56,15 +56,23 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} CSC_LINK: ${{ secrets.mac_csc_link }} CSC_KEY_PASSWORD: ${{ secrets.mac_csc_key_password }} - APPLE_API_KEY: ${{ secrets.api_key_id }} + APPLE_API_KEY: "~/private_keys/AuthKey_${{ secrets.api_key_id }}.p8" APPLE_API_KEY_ID: ${{ secrets.api_key_id }} APPLE_API_KEY_ISSUER: ${{ secrets.api_key_issuer_id }} - APPLE_TEAM_ID: ${{ secrets.team_id }} run: | npm run publish + - if: ${{ failure() }} + run: | + echo "###########################################"; + echo "Printing logs from failure"; + echo "###########################################"; + echo ""; + echo "###########"; + cat notarization-error.log; + echo "###########"; publish_on_arm64_mac: - runs-on: flyci-macos-large-latest-m2 + runs-on: macos-latest strategy: matrix: os: [macos-latest] @@ -90,12 +98,20 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} CSC_LINK: ${{ secrets.mac_csc_link }} CSC_KEY_PASSWORD: ${{ secrets.mac_csc_key_password }} - APPLE_API_KEY: ${{ secrets.api_key_id }} + APPLE_API_KEY: "~/private_keys/AuthKey_${{ secrets.api_key_id }}.p8" APPLE_API_KEY_ID: ${{ secrets.api_key_id }} APPLE_API_KEY_ISSUER: ${{ secrets.api_key_issuer_id }} - APPLE_TEAM_ID: ${{ secrets.team_id }} run: | npm run publish + - if: ${{ failure() }} + run: | + echo "###########################################"; + echo "Printing logs from failure"; + echo "###########################################"; + echo ""; + echo "###########"; + cat notarization-error.log; + echo "###########"; publish_on_win: runs-on: windows-latest diff --git a/README.md b/README.md index 06492c8e..3f50e72e 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,30 @@

- + Logo

- YATTIE + Piñata
Explore the screenshots »

- Report a Bug + Report a Bug · - Request a Feature + Request a Feature . - Ask a Question + Ask a Question

-[![Project license](https://img.shields.io/github/license/yatt-ai/yattie.svg?style=flat-square)](LICENSE) +[![Project license](https://img.shields.io/github/license/testfiesta/pinata.svg?style=flat-square)](LICENSE) -[![Pull Requests welcome](https://img.shields.io/badge/PRs-welcome-ff69b4.svg?style=flat-square)](https://github.com/yatt-ai/yattie/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) -[![code with love by dacoaster](https://img.shields.io/badge/%3C%2F%3E%20with%20%E2%99%A5%20by-dacoaster-ff1414.svg?style=flat-square)](https://github.com/dacoaster) +[![Pull Requests welcome](https://img.shields.io/badge/PRs-welcome-ff69b4.svg?style=flat-square)](https://github.com/testfiesta/pinata/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) + +[![code with love by dacoaster](https://img.shields.io/badge/%3C%2F%3E%20with%20%E2%99%A5%20by-testfiesta-ff1414.svg?style=flat-square)](https://github.com/testfiesta)
@@ -52,26 +53,27 @@ ## About -**BETA** - *YATTIE is just getting started - please report any and all bugs you find. Likewise, contributions to the code to fix issues are always appreciated!* +**BETA** - _Piñata is just getting started - please report any and all bugs you find. Likewise, contributions to the code to fix issues are always appreciated!_ -YATTIE exists to help make tester's lives easier. Ideally, it should remove friction from the exploratory process - everywhere from gathering evidence to submitting reports. +Piñata exists to help make tester's lives easier. Ideally, it should remove friction from the exploratory process - everywhere from gathering evidence to submitting reports. -Our view is that testing is an art as varied and complex as those who undertake it. So our goal is to create a flexible, extensible toolset to raise the bar for what each member of the testing community can accomplish. +Our view is that testing is an art as varied and complex as those who undertake it. So our goal is to create a flexible, extensible toolset to raise the bar for what each member of the testing community can accomplish. -If you have an idea about how we can better meet that goal, please let us know by [requesting a feature](https://github.com/yatt-ai/yattie/labels/enhancement) or, better yet, [put in a pull request!](docs/CONTRIBUTING.md). +If you have an idea about how we can better meet that goal, please let us know by [requesting a feature](https://github.com/testfiesta/pinata/labels/enhancement) or, better yet, [put in a pull request!](docs/CONTRIBUTING.md).
Screenshots
-| Test Charter | Test Timeline | -| :-------------------------------------------------------------------: | :--------------------------------------------------------------------: | -| | | +| Test Charter | Test Timeline | +| :--------------------------------------------------------------------: | :---------------------------------------------------------------------: | +| | |
### Contributors -Many thanks to all of the testers and developers who have contributed to YATTIE via bug reports, code, ideas, and more! + +Many thanks to all of the testers and developers who have contributed to Piñata via bug reports, code, ideas, and more! [@parwalrahul](https://github.com/parwalrahul) [@narkhedeshubham](https://github.com/narkhedeshubham) @@ -79,7 +81,6 @@ Many thanks to all of the testers and developers who have contributed to YATTIE [@jimholmes](https://github.com/jimholmes) [@dacoaster](https://github.com/dacoaster) - ### Built With @@ -91,71 +92,68 @@ Many thanks to all of the testers and developers who have contributed to YATTIE If you looking to contribute - please checkout the [contributing guidelines](docs/CONTRIBUTING.md). -If you're just looking to take it for a spin, check out the pre-built [packages](https://github.com/yatt-ai/yattie/releases) and find the one built for your platform. Can't find the platform you're looking for? Let us know you'd like a new one supported by submitting a [feature requests](https://github.com/yatt-ai/yattie/labels/enhancement)! +If you're just looking to take it for a spin, check out the pre-built [packages](https://github.com/testfiesta/pinata/releases) and find the one built for your platform. Can't find the platform you're looking for? Let us know you'd like a new one supported by submitting a [feature requests](https://github.com/dacoaster/pinata/labels/enhancement)! ### Installation TODO - This section could use some love (and screenshots!) - ### MacOS settings to allow screen recording and screenshots -To allow Yattie taking screenshots and record your screen please make sure you allowed the app to do that by doing next steps: - -- Choose Apple menu > System Settings, then click Privacy & Security in the sidebar. (You may need to scroll down.) -- Click Screen Recording on the right. Turn screen recording on for Yattie +To allow Piñata taking screenshots and record your screen please make sure you allowed the app to do that by doing next steps: +- Choose Apple menu > System Settings, then click Privacy & Security in the sidebar. (You may need to scroll down.) +- Click Screen Recording on the right. Turn screen recording on for Piñata - *We are working on the solution to make screenshots work also on a dev build. This manual will be updated as soon we will have a solution + \*We are working on the solution to make screenshots work also on a dev build. This manual will be updated as soon we will have a solution ## Usage - You can find a quick waklthrough by the very helpful @parwalrahul at the excellent MoT community [here](https://www.ministryoftesting.com/articles/acfa4d56)! -- Check out our [docs](https://docs.yattie.ai). Note: these docs are rough and need a lot of work. +- Check out our [docs](https://docs.pinata.ai). Note: these docs are rough and need a lot of work. ## Roadmap -See the [open issues](https://github.com/yatt-ai/yattie/issues) for a list of known issues. -See the [open feature requests](https://github.com/yatt-ai/yattie/labels/enhancement) for a list of current feature requests. +See the [open issues](https://github.com/testfiesta/pinata/issues) for a list of known issues. +See the [open feature requests](https://github.com/testfiesta/pinata/labels/enhancement) for a list of current feature requests. -- [Top Feature Requests](https://github.com/yatt-ai/yattie/labels/enhancement) (Add your votes using the a thumbs up or down!) -- [Top Bugs](https://github.com/yatt-ai/yattie/issues?q=is%3Aissue+is%3Aopen+label%3Abug+sort%3Areactions-%2B1-desc) (Add your votes using the 👍 reaction) -- [Newest Bugs](https://github.com/yatt-ai/yattie/issues?q=is%3Aopen+is%3Aissue+label%3Abug) +- [Top Feature Requests](https://github.com/testfiesta/pinata/labels/enhancement) (Add your votes using the a thumbs up or down!) +- [Top Bugs](https://github.com/testfiesta/pinata/issues?q=is%3Aissue+is%3Aopen+label%3Abug+sort%3Areactions-%2B1-desc) (Add your votes using the 👍 reaction) +- [Newest Bugs](https://github.com/testfiesta/pinata/issues?q=is%3Aopen+is%3Aissue+label%3Abug) ## Support Reach out to the maintainer at one of the following places: -- [GitHub issues](https://github.com/yatt-ai/yattie/issues/new?assignees=&labels=question&template=04_SUPPORT_QUESTION.md&title=support%3A+) +- [GitHub issues](https://github.com/testfiesta/pinata/issues/new?assignees=&labels=question&template=04_SUPPORT_QUESTION.md&title=support%3A+) - Contact options listed on [this GitHub profile](https://github.com/dacoaster) ## Project assistance -If you want to say **thank you** or/and support active development of YATTIE: +If you want to say **thank you** or/and support active development of Piñata: -- Add a [GitHub Star](https://github.com/yatt-ai/yattie) to the project. -- Tweet about YATTIE. +- Add a [GitHub Star](https://github.com/testfiesta/pinata) to the project. +- Tweet about Piñata. - Write interesting articles about the project on [Dev.to](https://dev.to/), [Medium](https://medium.com/) or your personal blog. -Together, we can make YATTIE **better**! +Together, we can make Piñata **better**! ## Contributing First off, thanks for taking the time to contribute! Contributions are what make the open-source community such an amazing place to learn, inspire, and create. Any contributions you make will benefit everybody else and are **greatly appreciated**. - Please read [our contribution guidelines](docs/CONTRIBUTING.md), and thank you for being involved! ## Authors & contributors The original setup of this repository is by [David Acosta](https://github.com/dacoaster). -For a full list of all authors and contributors, see [the contributors page](https://github.com/yatt-ai/yattie/contributors). +For a full list of all authors and contributors, see [the contributors page](https://github.com/testfiesta/pinata/contributors). ## Security -YATTIE follows good practices of security, but 100% security cannot be assured. -YATTIE is provided **"as is"** without any **warranty**. Use at your own risk. +Piñata follows good practices of security, but 100% security cannot be assured. +Piñata is provided **"as is"** without any **warranty**. Use at your own risk. _For more information and to report security issues, please refer to our [security documentation](docs/SECURITY.md)._ diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md index 980a82ad..2ed9004a 100644 --- a/docs/CODE_OF_CONDUCT.md +++ b/docs/CODE_OF_CONDUCT.md @@ -8,19 +8,19 @@ In the interest of fostering an open and welcoming environment, we as contributo Examples of behavior that contributes to creating a positive environment include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting +- The use of sexualized language or imagery and unwelcome sexual attention or advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities @@ -34,7 +34,7 @@ This Code of Conduct applies within all project spaces, and it also applies when ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project maintainer using any of the [private contact addresses](https://github.com/dacoaster/yattie#support). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project maintainer using any of the [private contact addresses](https://github.com/dacoaster/pinata#support). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 89d3171c..fe389122 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -10,10 +10,11 @@ To set up a development environment, please follow these steps: 1. Clone the repo ```sh - git clone https://github.com/dacoaster/yattie + git clone https://github.com/dacoaster/pinata ``` 2. Install the deps + ```sh yarn install ``` @@ -23,12 +24,11 @@ To set up a development environment, please follow these steps: yarn dev ``` - ## Issues and feature requests -You've found a bug in the source code or a mistake in the documentation? You can help us by [submitting an issue on GitHub](https://github.com/dacoaster/yattie/issues). Before you create an issue, make sure to search the issue archive -- your issue may have already been addressed! +You've found a bug in the source code or a mistake in the documentation? You can help us by [submitting an issue on GitHub](https://github.com/dacoaster/pinata/issues). Before you create an issue, make sure to search the issue archive -- your issue may have already been addressed! -Or maybe you'd like a new feature? You can check out current feature requests, vote for your favorites, or add your own at [the feature request page](https://features.yattie.ai). +Or maybe you'd like a new feature? You can check out current feature requests, vote for your favorites, or add your own at [the feature request page](https://features.testfiesta.com). Please try to create bug reports that are: @@ -42,10 +42,10 @@ Please try to create bug reports that are: ### How to submit a Pull Request 1. Search our repository for open or closed - [Pull Requests](https://github.com/dacoaster/yattie/pulls) + [Pull Requests](https://github.com/dacoaster/pinata/pulls) that relate to your submission. You don't want to duplicate effort. 2. Fork the project 3. Create your feature branch (`git checkout -b feat/amazing_feature`) -4. Commit your changes (`git commit -m 'feat: add amazing_feature'`) YATTIE tries to use [conventional commits](https://www.conventionalcommits.org), so please follow the specification in your commit messages. +4. Commit your changes (`git commit -m 'feat: add amazing_feature'`) Pinata tries to use [conventional commits](https://www.conventionalcommits.org), so please follow the specification in your commit messages. 5. Push to the branch (`git push origin feat/amazing_feature`) -6. [Open a Pull Request](https://github.com/dacoaster/yattie/compare?expand=1) +6. [Open a Pull Request](https://github.com/dacoaster/pinata/compare?expand=1) diff --git a/docs/SECURITY.md b/docs/SECURITY.md index ad77a8db..e075d50f 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -2,9 +2,9 @@ ## Reporting a Vulnerability -If there are any vulnerabilities in **YATTIE**, don't hesitate to _report them_. +If there are any vulnerabilities in **Pinata**, don't hesitate to _report them_. -1. Use any of the [private contact addresses](https://github.com/dacoaster/yattie#support). +1. Use any of the [private contact addresses](https://github.com/dacoaster/pinata#support). 2. Describe the vulnerability. If you have a fix, that is most welcome -- please attach or summarize it in your message! diff --git a/docs/images/yattie-1.png b/docs/images/pinata-1.png similarity index 100% rename from docs/images/yattie-1.png rename to docs/images/pinata-1.png diff --git a/docs/images/yattie-2.png b/docs/images/pinata-2.png similarity index 100% rename from docs/images/yattie-2.png rename to docs/images/pinata-2.png diff --git a/package.json b/package.json index 0092ddab..9f689b00 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,14 @@ { - "name": "yattie", - "version": "0.10.1", + "name": "pinata", + "version": "0.11.0", "engines": { "npm": ">=8.0.0 <9.0.0", "node": ">=16.0.0 <17.0.0" }, "keywords": [], "author": { - "name": "YATT, Inc", - "email": "contact@yatt.ai" + "name": "TestFiesta, Inc", + "email": "contact@testfiesta.com" }, "license": "GPL-3.0-only", "scripts": { @@ -40,6 +40,7 @@ "d3": "^5.14.2", "dayjs": "^1.11.5", "detect-file-type": "^0.2.8", + "dom-to-image-more": "^3.3.0", "extract-zip": "^2.0.1", "ffmpeg-static": "^5.1.0", "ffprobe-static": "^3.1.0", @@ -47,8 +48,11 @@ "form-data": "^4.0.0", "lodash": "^4.17.21", "node-polyfill-webpack-plugin": "^2.0.1", + "os": "^0.1.2", "simple-json-db": "^2.0.0", "sinon": "^15.0.0", + "systeminformation": "^5.22.1", + "tinycolor2": "^1.6.0", "tui-image-editor": "^3.15.3", "uuid": "3.3.3", "v-emoji-picker": "^2.3.3", @@ -62,6 +66,7 @@ "vuedraggable": "^2.24.3", "vuetify": "^2.6.0", "vuex": "^3.6.2", + "vuex-persist": "^3.1.3", "wavesurfer.js": "^6.3.0" }, "devDependencies": { @@ -79,8 +84,8 @@ "@vue/vue2-jest": "^27.0.0-alpha.2", "babel-jest": "^27.0.6", "electron": "^13.0.0", - "electron-builder-notarize": "yatt-ai/electron-builder-notarize", - "electron-devtools-installer": "^3.1.0", + "electron-builder-notarize": "^1.5.2", + "electron-devtools-installer": "^3.1.1", "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-prettier": "^4.0.0", diff --git a/server/jira_error.html b/server/jira_error.html index d16b0ec0..22d5d855 100644 --- a/server/jira_error.html +++ b/server/jira_error.html @@ -5,7 +5,7 @@ - YATTIE + Pinata diff --git a/server/jira_success.html b/server/jira_success.html index 656c7918..1920717c 100644 --- a/server/jira_success.html +++ b/server/jira_success.html @@ -5,7 +5,7 @@ - YATTIE + Pinata @@ -65,7 +65,7 @@ logo
- You are now connected to JIRA! You can close this window and go back to the YATTIE app to get started + You are now connected to JIRA! You can close this window and go back to the Pinata app to get started testing.
diff --git a/server/package.json b/server/package.json index ec2b098d..b3781411 100644 --- a/server/package.json +++ b/server/package.json @@ -1,7 +1,7 @@ { - "name": "yattie-oauth-backend", + "name": "pinata-oauth-backend", "version": "0.1.0", - "description": "Express backend for YATTIE OAuth", + "description": "Express backend for Pinata OAuth", "main": "server.js", "scripts": { "server": "node server.js", diff --git a/src/App.vue b/src/App.vue index 6b1d19dd..16c52a0d 100644 --- a/src/App.vue +++ b/src/App.vue @@ -5,7 +5,7 @@ import ResetSessionDialog from "@/components/dialogs/ResetSessionDialog.vue"; -import ResetConfirmDialog from "@/components/dialogs/ResetConfirmDialog.vue"; const default_layout = "default"; export default { name: "App", - components: { ResetConfirmDialog, ResetSessionDialog }, + components: { ResetSessionDialog }, data() { return { showRestoreSessionDialog: false, @@ -37,6 +36,10 @@ export default { async created() { if (this.$router.history.current.path === "/") { this.renderRestoreSessionDialog = true; + if (this.$isElectron) { + const { message } = await this.$electronService.deleteSession("old"); + console.log("Session Clear : ", message); + } } const config = await this.$storageService.getConfig(); @@ -44,15 +47,15 @@ export default { const credentials = await this.$storageService.getCredentials(); this.$store.commit("auth/setCredentials", credentials); - if (this.$isElectron) { - // todo remove this check when $integrationHelpers will support REST API - await this.updateAuth(); - } + await this.updateAuth(); }, async mounted() { - if (this.renderRestoreSessionDialog) { + if (this.renderRestoreSessionDialog && this.$isElectron) { this.stateToRestore = await this.$storageService.getState(); - if (Object.keys(this.stateToRestore).length && this.stateToRestore.id) { + if ( + Object.keys(this.stateToRestore).length && + this.stateToRestore.session.sessionID + ) { this.showRestoreSessionDialog = true; } } @@ -62,14 +65,17 @@ export default { await this.$store.commit("restoreState", this.stateToRestore); const currentPath = this.$router.history.current.path; if ( - this.stateToRestore.path && - currentPath !== this.stateToRestore.path + this.stateToRestore.session.path && + currentPath !== this.stateToRestore.session.path ) { - if (this.stateToRestore.path.includes("result") && this.$isElectron) { + if ( + this.stateToRestore.session.path.includes("result") && + this.$isElectron + ) { this.$electronService.setWindowSize({ width: 1440, height: 900 }); } - if (this.stateToRestore.path !== "/authentication/signinJira") { - await this.$router.push({ path: this.stateToRestore.path }); + if (this.stateToRestore.session.path !== "/authentication/signinJira") { + await this.$router.push({ path: this.stateToRestore.session.path }); } } this.showRestoreSessionDialog = false; diff --git a/src/assets/icon/align.svg b/src/assets/icon/align.svg new file mode 100644 index 00000000..aed2ef44 --- /dev/null +++ b/src/assets/icon/align.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/bell.svg b/src/assets/icon/bell.svg new file mode 100644 index 00000000..80276d59 --- /dev/null +++ b/src/assets/icon/bell.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/bold.svg b/src/assets/icon/bold.svg new file mode 100644 index 00000000..fa907216 --- /dev/null +++ b/src/assets/icon/bold.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/bullet.svg b/src/assets/icon/bullet.svg new file mode 100644 index 00000000..8c36eac7 --- /dev/null +++ b/src/assets/icon/bullet.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/color-panel.svg b/src/assets/icon/color-panel.svg new file mode 100644 index 00000000..7b1a2867 --- /dev/null +++ b/src/assets/icon/color-panel.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/assets/icon/compass.svg b/src/assets/icon/compass.svg new file mode 100644 index 00000000..195abe8c --- /dev/null +++ b/src/assets/icon/compass.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/icon/cross.svg b/src/assets/icon/cross.svg new file mode 100644 index 00000000..ca54b3d4 --- /dev/null +++ b/src/assets/icon/cross.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/diamond.svg b/src/assets/icon/diamond.svg new file mode 100644 index 00000000..421dd1cb --- /dev/null +++ b/src/assets/icon/diamond.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/downward-triangle.svg b/src/assets/icon/downward-triangle.svg new file mode 100644 index 00000000..95b06e4e --- /dev/null +++ b/src/assets/icon/downward-triangle.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/edit.svg b/src/assets/icon/edit.svg new file mode 100644 index 00000000..ee95282e --- /dev/null +++ b/src/assets/icon/edit.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/ellipse.svg b/src/assets/icon/ellipse.svg new file mode 100644 index 00000000..437a803b --- /dev/null +++ b/src/assets/icon/ellipse.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/fill.svg b/src/assets/icon/fill.svg new file mode 100644 index 00000000..61cab1ee --- /dev/null +++ b/src/assets/icon/fill.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/highlight.svg b/src/assets/icon/highlight.svg new file mode 100644 index 00000000..5ce89de9 --- /dev/null +++ b/src/assets/icon/highlight.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/link.svg b/src/assets/icon/link.svg new file mode 100644 index 00000000..20e1c25c --- /dev/null +++ b/src/assets/icon/link.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/nofill.svg b/src/assets/icon/nofill.svg new file mode 100644 index 00000000..ed7f1555 --- /dev/null +++ b/src/assets/icon/nofill.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/yattie.png b/src/assets/icon/pinata.png similarity index 100% rename from src/assets/icon/yattie.png rename to src/assets/icon/pinata.png diff --git a/src/assets/icon/yattie.svg b/src/assets/icon/pinata.svg similarity index 100% rename from src/assets/icon/yattie.svg rename to src/assets/icon/pinata.svg diff --git a/src/assets/icon/yattie1.png b/src/assets/icon/pinata1.png similarity index 100% rename from src/assets/icon/yattie1.png rename to src/assets/icon/pinata1.png diff --git a/src/assets/icon/plus-integration.svg b/src/assets/icon/plus-integration.svg new file mode 100644 index 00000000..8fd7feaa --- /dev/null +++ b/src/assets/icon/plus-integration.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icon/plus.png b/src/assets/icon/plus.png new file mode 100644 index 00000000..fd475a50 Binary files /dev/null and b/src/assets/icon/plus.png differ diff --git a/src/assets/icon/rectangle.svg b/src/assets/icon/rectangle.svg new file mode 100644 index 00000000..4c4409c9 --- /dev/null +++ b/src/assets/icon/rectangle.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/setting.svg b/src/assets/icon/setting.svg new file mode 100644 index 00000000..16509bf7 --- /dev/null +++ b/src/assets/icon/setting.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/icon/shape.svg b/src/assets/icon/shape.svg new file mode 100644 index 00000000..9ef3e5d3 --- /dev/null +++ b/src/assets/icon/shape.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/testfiesta.png b/src/assets/icon/testfiesta.png new file mode 100644 index 00000000..d7a2dc43 Binary files /dev/null and b/src/assets/icon/testfiesta.png differ diff --git a/src/assets/icon/text.svg b/src/assets/icon/text.svg new file mode 100644 index 00000000..36a9287b --- /dev/null +++ b/src/assets/icon/text.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/text_link.svg b/src/assets/icon/text_link.svg new file mode 100644 index 00000000..8af07147 --- /dev/null +++ b/src/assets/icon/text_link.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/thick.svg b/src/assets/icon/thick.svg new file mode 100644 index 00000000..f57e696f --- /dev/null +++ b/src/assets/icon/thick.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/thin.svg b/src/assets/icon/thin.svg new file mode 100644 index 00000000..57a82b0f --- /dev/null +++ b/src/assets/icon/thin.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/transparent.svg b/src/assets/icon/transparent.svg new file mode 100644 index 00000000..8eff9808 --- /dev/null +++ b/src/assets/icon/transparent.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/icon/triangle.svg b/src/assets/icon/triangle.svg new file mode 100644 index 00000000..81c4a48f --- /dev/null +++ b/src/assets/icon/triangle.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/underline.svg b/src/assets/icon/underline.svg new file mode 100644 index 00000000..ef8dd901 --- /dev/null +++ b/src/assets/icon/underline.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/upload.svg b/src/assets/icon/upload.svg new file mode 100644 index 00000000..dadc4fbb --- /dev/null +++ b/src/assets/icon/upload.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/xray-logo.png b/src/assets/icon/xray-logo.png new file mode 100644 index 00000000..172959db Binary files /dev/null and b/src/assets/icon/xray-logo.png differ diff --git a/src/assets/icon/yatt.png b/src/assets/icon/yatt.png deleted file mode 100644 index b37c5771..00000000 Binary files a/src/assets/icon/yatt.png and /dev/null differ diff --git a/src/assets/icon/zephyr-scale.png b/src/assets/icon/zephyr-scale.png new file mode 100644 index 00000000..6180d7c3 Binary files /dev/null and b/src/assets/icon/zephyr-scale.png differ diff --git a/src/assets/icon/zephyr-squad.png b/src/assets/icon/zephyr-squad.png new file mode 100644 index 00000000..9efc63ed Binary files /dev/null and b/src/assets/icon/zephyr-squad.png differ diff --git a/src/assets/icon/zoom-in.svg b/src/assets/icon/zoom-in.svg new file mode 100644 index 00000000..a1307563 --- /dev/null +++ b/src/assets/icon/zoom-in.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icon/zoom-out.svg b/src/assets/icon/zoom-out.svg new file mode 100644 index 00000000..bbc2911b --- /dev/null +++ b/src/assets/icon/zoom-out.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/logo.png b/src/assets/logo.png index 42945956..f1c147d5 100644 Binary files a/src/assets/logo.png and b/src/assets/logo.png differ diff --git a/src/assets/logo.svg b/src/assets/logo.svg index 41c13488..dc136423 100644 --- a/src/assets/logo.svg +++ b/src/assets/logo.svg @@ -1,7 +1,11 @@ - - - - - - + + + + + + + + + + diff --git a/src/assets/logo_old.svg b/src/assets/logo_old.svg new file mode 100644 index 00000000..41c13488 --- /dev/null +++ b/src/assets/logo_old.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/mindmap-workspace.png b/src/assets/mindmap-workspace.png new file mode 100644 index 00000000..40cc7a3e Binary files /dev/null and b/src/assets/mindmap-workspace.png differ diff --git a/src/background.js b/src/background.js index 5ae9bf96..3b054fbe 100644 --- a/src/background.js +++ b/src/background.js @@ -10,7 +10,7 @@ import { VIEW_MODE } from "./modules/constants"; let isDevelopment = process.env.NODE_ENV !== "production"; const browserUtility = require("./modules/BrowserWindowUtility"); -const databaseUtility = require("./modules/DatabaseUtility"); +const persistenceUtility = require("./modules/PersistenceUtility"); const windowUtility = require("./modules/WindowUtility"); const serverUtility = require("./modules/ServerUtility"); @@ -19,11 +19,11 @@ import { session } from "electron"; require("./modules/IpcHandlers"); // initialize session -databaseUtility.initializeSession(); +persistenceUtility.initializeSession(); // Check for enabling dev mode -const startupConfig = databaseUtility.getConfig(); -if (startupConfig.devMode) { +const startupConfig = persistenceUtility.getConfig(); +if (startupConfig.debugMode) { isDevelopment = true; windowUtility.setDevMode({ enabled: true }); } @@ -77,7 +77,7 @@ app.on("activate", () => { app.on("ready", async () => { // Changing the User-Agent is required for JIRA token integration to work. session.defaultSession.webRequest.onBeforeSendHeaders((details, callback) => { - details.requestHeaders["User-Agent"] = "YATTIE"; + details.requestHeaders["User-Agent"] = "PINATA"; callback({ cancel: false, requestHeaders: details.requestHeaders }); }); if (isDevelopment && !process.env.IS_TEST) { diff --git a/src/components/AudioWrapper.vue b/src/components/AudioWrapper.vue index 438eae57..130dc460 100644 --- a/src/components/AudioWrapper.vue +++ b/src/components/AudioWrapper.vue @@ -108,6 +108,7 @@
+ + mdi-cog + + + + +
+ + diff --git a/src/components/ControlPanel.vue b/src/components/ControlPanel.vue index f90e51eb..2bcbed57 100644 --- a/src/components/ControlPanel.vue +++ b/src/components/ControlPanel.vue @@ -1,7 +1,7 @@ - + mdi-download @@ -121,6 +89,44 @@ :selected="selected" /> +
+ +
+
+ +
+
+ +
@@ -138,7 +144,7 @@ small color="default" v-on="on" - @click="resume()" + @click="resume" > mdi-play-circle @@ -159,7 +165,7 @@ small color="default" v-on="on" - @click="handleNewSessionDialog()" + @click="handleNewSessionDialog" > mdi-content-save @@ -179,7 +185,7 @@ small color="default" v-on="on" - @click="handleResetConfirmDialog()" + @click="handleResetConfirmDialog" > mdi-restart @@ -287,8 +293,8 @@ color="default" v-on="on" v-shortkey="stopHotkey" - @shortkey="endSession()" - @click="endSession()" + @shortkey="endSession" + @click="endSession" > {{ $tc("caption.mind_map", 1) }} - + @@ -722,7 +756,10 @@ import { VBtn, VCol, VContainer, VIcon, VRow } from "vuetify/lib/components"; import uuidv4 from "uuid"; +import testfiestaIntegrationHelper from "../integrations/TestfiestaIntegrationHelpers"; + import SourcePickerDialog from "./dialogs/SourcePickerDialog.vue"; +import ShareSessionDialog from "./dialogs/ShareSessionDialog.vue"; import NoteDialog from "./dialogs/NoteDialog.vue"; import SummaryDialog from "./dialogs/SummaryDialog.vue"; import DeleteConfirmDialog from "./dialogs/DeleteConfirmDialog.vue"; @@ -732,9 +769,13 @@ import NewSessionDialog from "./dialogs/NewSessionDialog.vue"; import DurationConfirmDialog from "./dialogs/DurationConfirmDialog.vue"; import AudioErrorDialog from "./dialogs/AudioErrorDialog.vue"; import EndSessionDialog from "./dialogs/EndSessionDialog.vue"; -//import MinimizeControlWrapper from "../components/MinimizeControlWrapper.vue"; +import LowProfileControlWrapper from "../components/LowProfileControlWrapper.vue"; import JiraExportSession from "./jira/JiraExportSession"; import TestRailExportSession from "./testrail/TestRailExportSession"; +import XrayExportSession from "./xray/XrayExportSession"; +import ZephyrSquadExportSession from "./zephyr/ZephyrSquadExportSession"; +import ZephyrScaleExportSession from "./zephyr/ZephyrScaleExportSession"; +import AddEvidenceDialog from "@/components/dialogs/AddEvidenceDialog.vue"; import JiraAddIssue from "./jira/JiraAddIssue"; @@ -743,9 +784,15 @@ import { DEFAULT_MAP_NODES, SESSION_STATUSES, STATUSES, + DEFAULT_FILE_TYPES, VIDEO_RESOLUTION, -} from "../modules/constants"; +} from "@/modules/constants"; import { mapGetters } from "vuex"; +import { + createAudioForWeb, + createImageForWeb, + createVideoForWeb, +} from "@/helpers/WebHelpers"; let mediaRecorder; let audioContext; @@ -753,12 +800,14 @@ let dest; export default { name: "ControlPanel", components: { + AddEvidenceDialog, VContainer, VRow, VCol, VBtn, VIcon, SourcePickerDialog, + ShareSessionDialog, NoteDialog, SummaryDialog, DeleteConfirmDialog, @@ -768,16 +817,15 @@ export default { DurationConfirmDialog, AudioErrorDialog, EndSessionDialog, - // MinimizeControlWrapper, + LowProfileControlWrapper, JiraExportSession, TestRailExportSession, + XrayExportSession, + ZephyrSquadExportSession, + ZephyrScaleExportSession, JiraAddIssue, }, props: { - items: { - type: Array, - default: () => [], - }, selectedItems: { type: Array, default: () => [], @@ -804,13 +852,20 @@ export default { } }, watch: { - items: function (newValue) { - this.itemLists = newValue; - }, selectedItems: function (newValue) { this.selected = newValue; }, - "$store.state.status": { + mediaStream: function (newValue) { + if (newValue) { + const videoTrack = this.mediaStream.getVideoTracks()[0]; + + videoTrack.addEventListener("ended", () => { + console.log("The user has stopped sharing their screen."); + this.mediaStream = null; + }); + } + }, + "$store.state.session.status": { deep: true, handler(newValue) { this.status = newValue; @@ -825,13 +880,13 @@ export default { } }, }, - "$store.state.timer": { + "$store.state.session.timer": { deep: true, handler(newValue) { this.timer = newValue; }, }, - "$store.state.duration": { + "$store.state.case.duration": { deep: true, handler(newValue) { this.duration = newValue; @@ -840,11 +895,17 @@ export default { }, computed: { ...mapGetters({ + items: "sessionItems", + nodes: "sessionNodes", + connections: "sessionConnections", hotkeys: "config/hotkeys", postSessionData: "config/postSessionData", config: "config/fullConfig", credentials: "auth/credentials", }), + isShareSessionAllowed() { + return !this.config.localOnly; + }, pauseHotkey() { return this.$hotkeyHelpers.findBinding("workspace.pause", this.hotkeys); }, @@ -918,7 +979,7 @@ export default { summary() { let summary = {}; this.items.map((item) => { - if (item.sessionType === "Summary") { + if (item?.comment?.type === "Summary") { summary = item; } }); @@ -928,6 +989,7 @@ export default { data() { return { sourcePickerDialog: false, + shareSessionDialog: false, noteDialog: false, summaryDialog: false, deleteConfirmDialog: false, @@ -938,23 +1000,27 @@ export default { audioErrorDialog: false, endSessionDialog: false, sources: [], + sessionLink: "", sourceId: this.srcId, - itemLists: this.items, audioDevices: [], loaded: false, - status: this.$store.state.status, + status: this.$store.state.session.status, recordVideoStarted: false, recordAudioStarted: false, interval: null, - timer: this.$store.state.timer, - duration: this.$store.state.duration, + timer: this.$store.state.session.timer, + duration: this.$store.state.case.duration, isDuration: false, started: "", ended: "", selected: [], + selectedNodes: [], callback: null, evidenceExportDestinationMenu: false, issueCreateDestinationMenu: false, + evidenceData: null, + addEvidenceDialog: false, + mediaStream: null, }; }, mounted() { @@ -964,40 +1030,41 @@ export default { this.$electronService.onResetSession(this.showResetConfirmDialog); } + this.$root.$on("update-selected-nodes", this.updateSelectedNodes); this.$root.$on("close-sourcepickerdialog", this.hideSourcePickerDialog); + this.$root.$on("close-sharesessiondialog", this.hideShareSessionDialog); this.$root.$on("close-notedialog", this.hideNoteDialog); + this.$root.$on("start-quick-test", this.showSourcePickerDialog); + this.$root.$on("start-new-exploratory-session", this.startNewSession); this.$root.$on("close-summarydialog", () => { this.summaryDialog = false; }); if ( - this.$store.state.status === SESSION_STATUSES.START || - this.$store.state.status === SESSION_STATUSES.PROCEED || - this.$store.state.status === SESSION_STATUSES.RESUME + this.$store.state.session.status === SESSION_STATUSES.START || + this.$store.state.session.status === SESSION_STATUSES.PROCEED || + this.$store.state.session.status === SESSION_STATUSES.RESUME ) { - this.status = this.$store.state.status; - this.timer = this.$store.state.timer; - this.duration = this.$store.state.duration; - if (this.$store.state.status === SESSION_STATUSES.START) { + this.status = this.$store.state.session.status; + this.timer = this.$store.state.session.timer; + this.duration = this.$store.state.case.duration; + if (this.$store.state.session.status === SESSION_STATUSES.START) { this.startSession(this.sourceId); } this.startInterval(); } - - if ( - this.$store.state.quickTest && - this.$store.state.status === SESSION_STATUSES.PENDING - ) { - this.showSourcePickerDialog(); - } }, beforeDestroy() { + this.updateStoreSession(true); this.$root.$off("close-sourcepickerdialog", this.hideSourcePickerDialog); this.$root.$on("close-notedialog", this.hideNoteDialog); // clear timer clearInterval(this.interval); this.timer = 0; }, + destroyed() { + this.updateStoreSession(true); + }, methods: { showResetConfirmDialog() { this.resetConfirmDialog = true; @@ -1027,7 +1094,7 @@ export default { return; } this.newSessionFromButton(); - this.$store.commit("setQuickTest", false); + this.$store.commit("setSessionQuickTest", false); this.showSourcePickerDialog(); }, handleResetConfirmDialog() { @@ -1049,39 +1116,60 @@ export default { // todo implement web version for this functionality }, async showSourcePickerDialog() { - try { - let data = await this.fetchSources(); - this.loaded = true; - this.sources = data; - if (this.viewMode === "normal") { + if (this.$isElectron) { + try { + let data = await this.fetchSources(); + this.loaded = true; + this.sources = data; + this.sourcePickerDialog = true; - } else { - if (this.$isElectron) { - await this.$electronService.openSourcePickerWindow(this.sources); - } + } catch (err) { + console.log(err); } - } catch (err) { - console.log(err); + } else { + this.mediaStream = await navigator.mediaDevices.getDisplayMedia({ + video: { + displaySurface: "window", + cursor: "always", + }, + audio: true, + }); + + await this.startSession(); + } + }, + async showShareSessionDialog() { + let savedSession = await testfiestaIntegrationHelper.saveSession( + this.credentials + ); + if (savedSession?.error) { + this.$root.$emit( + "set-snackbar", + `Unable to save session: ${savedSession.error}` + ); + } else { + this.sessionLink = savedSession?.link; + this.shareSessionDialog = true; } }, hideSourcePickerDialog() { this.sourcePickerDialog = false; }, - showNoteDialog() { - if (this.viewMode === "normal") { - this.noteDialog = true; - setTimeout(() => { - this.$refs.noteDialog.$refs.comment.editor.commands.focus(); - }); - } else { - if (this.$isElectron) { - this.$electronService.openNoteEditorWindow(this.config); - } - } + hideShareSessionDialog() { + this.shareSessionDialog = false; + }, + async showNoteDialog() { + this.noteDialog = true; + setTimeout(() => { + this.$refs.noteDialog.$refs.comment.editor.commands.focus(); + }); }, hideNoteDialog() { this.noteDialog = false; }, + updateSelectedNodes(value) { + this.selectedNodes = value; + }, handleDeleteConfirmDialog() { this.deleteConfirmDialog = true; setTimeout(() => { @@ -1089,7 +1177,6 @@ export default { }, 100); }, startInterval() { - console.log("start interval"); if (!this.interval) { this.interval = setInterval(() => { this.timer += 1; @@ -1108,53 +1195,62 @@ export default { this.interval = null; this.updateStoreSession(); }, - updateStoreSession() { + updateStoreSession(isForce = false) { this.$store.commit("updateSession", { status: this.status, timer: this.timer, duration: this.duration, + isForce, }); }, - async startSession(id) { - this.sourceId = id; + async startSession(id = null) { + if (this.$isElectron) { + this.sourceId = id; + } this.sourcePickerDialog = false; - this.timer = this.$store.state.timer; - this.duration = this.$store.state.duration; + this.timer = this.$store.state.session.timer; + this.duration = this.$store.state.case.duration; if (this.duration > 0) { this.isDuration = true; } if (this.started === "") { this.started = this.getCurrentDateTime(); - this.$store.commit("setStarted", this.started); + this.$store.commit("setSessionStarted", this.started); } if (this.status !== SESSION_STATUSES.START) { - console.log("start interval-2"); this.status = SESSION_STATUSES.START; this.startInterval(); this.changeSessionStatus(SESSION_STATUSES.START); } - const sessionId = await this.$storageService.getSessionId(); - - if (sessionId === "") { + if (!this.$store.state.session.sessionID) { const data = { - id: uuidv4(), - title: this.$store.state.title, - charter: this.$store.state.charter, - preconditions: this.$store.state.preconditions, - duration: this.$store.state.duration, - status: this.$store.state.status, - timer: this.$store.state.timer, - started: this.$store.state.started, - ended: this.$store.state.ended, - quickTest: this.$store.state.quickTest, - path: this.$route.path, + case: { + title: this.$store.state.case.title, + charter: this.$store.state.case.charter, + preconditions: this.$store.state.case.preconditions, + duration: this.$store.state.case.duration, + }, + session: { + status: this.$store.state.session.status, + timer: this.$store.state.session.timer, + started: this.$store.state.session.started, + ended: this.$store.state.session.ended, + quickTest: this.$store.state.session.quickTest, + path: this.$route.path, + }, }; await this.$storageService.createNewSession(data); + if (this.$isElectron) { + const caseID = await this.$storageService.getCaseId(); + const sessionID = await this.$storageService.getSessionId(); + this.$store.commit("setCaseID", caseID); + this.$store.commit("setSessionID", sessionID); + } } if (this.viewMode === "normal") { @@ -1169,18 +1265,26 @@ export default { this.changeSessionStatus(SESSION_STATUSES.PAUSE); this.stopInterval(); }, - resumeSession() { - this.fetchSources().then((data) => { - const list = data.filter((v) => v.id === this.sourceId); - if (list.length === 0) { - this.showSourcePickerDialog(); - } else { - this.status = SESSION_STATUSES.START; - this.timer = this.$store.state.timer; - console.log("start interval-3"); - this.startInterval(); + async resumeSession() { + if (this.$isElectron) { + this.fetchSources().then((data) => { + const list = data.filter((v) => v.id === this.sourceId); + if (list.length === 0) { + this.showSourcePickerDialog(); + } else { + this.status = SESSION_STATUSES.START; + this.timer = this.$store.state.session.timer; + this.startInterval(); + } + }); + } else { + if (!this.mediaStream) { + await this.setMediaStream(); } - }); + this.status = SESSION_STATUSES.START; + this.timer = this.$store.state.session.timer; + this.startInterval(); + } }, endSession() { if (this.postSessionData.status) { @@ -1192,36 +1296,22 @@ export default { async endSessionProcess() { this.sourceId = ""; this.ended = this.getCurrentDateTime(); - this.$store.commit("setEnded", this.ended); + this.$store.commit("setSessionEnded", this.ended); this.status = SESSION_STATUSES.END; this.changeSessionStatus(SESSION_STATUSES.END); this.stopInterval(); - if (this.$isElectron) { - this.$electronService.setWindowSize({ width: 1440, height: 900 }); - } + this.$root.$emit("handle-mindmap"); await this.$router.push({ path: "/result" }); }, showSummaryDialog() { - if (this.viewMode === "normal") { - this.summaryDialog = true; + this.summaryDialog = true; - setTimeout(() => { - this.$refs.summaryDialog.$refs.comment.editor.commands.focus(); - }, 200); - } else { - if (this.$isElectron) { - this.$electronService.openSummaryWindow(this.config); - } - } + setTimeout(() => { + this.$refs.summaryDialog.$refs.comment.editor.commands.focus(); + }, 200); }, showEndSessionDialog() { - if (this.viewMode === "normal") { - this.endSessionDialog = true; - } else { - if (this.$isElectron) { - this.$electronService.openEndSessionWindow(this.config); - } - } + this.endSessionDialog = true; }, closeEndSessionDialog(status) { this.endSessionDialog = false; @@ -1231,7 +1321,7 @@ export default { }, resume() { this.pauseSession(); - this.timer = this.$store.state.timer; + this.timer = this.$store.state.session.timer; this.updateStoreSession(); const currentPath = this.$router.history.current.path; if (currentPath !== "/main/workspace") { @@ -1256,16 +1346,32 @@ export default { this.changeSessionStatus(this.status); this.$store.commit("setStatus", this.status); }, - handleScreenshot() { - this.fetchSources().then((data) => { - const list = data.filter((v) => v.id === this.sourceId); - if (list.length === 0) { - this.showSourcePickerDialog(); - } else { - this.screenshotProcess(); - } + async setMediaStream() { + this.mediaStream = await navigator.mediaDevices.getDisplayMedia({ + video: { + displaySurface: "window", + cursor: "always", + }, + audio: true, }); }, + async handleScreenshot() { + if (this.$isElectron) { + this.fetchSources().then((data) => { + const list = data.filter((v) => v.id === this.sourceId); + if (list.length === 0) { + this.showSourcePickerDialog(); + } else { + this.screenshotProcess(); + } + }); + } else { + if (!this.mediaStream) { + await this.setMediaStream(); + } + this.screenshotProcess(); + } + }, async screenshotProcess() { this.handleStream = (stream) => { const video = document.createElement("video"); @@ -1280,28 +1386,30 @@ export default { ctx.drawImage(video, 0, 0, canvas.width, canvas.height); video.remove(); const imgURI = canvas.toDataURL("image/png"); - + stream.getTracks().forEach((track) => track.stop()); if (this.$isElectron) { // todo add web implementation const { status, message, item } = await this.$electronService.createImage(imgURI); - - console.log({ item }); - if (status === STATUSES.ERROR) { this.$root.$emit("set-snackbar", message); console.log(message); } else { const data = { - id: item.id, - sessionType: "Screenshot", - fileType: "image", - fileName: item.fileName, - filePath: item.filePath, + ...item, timer_mark: this.timer, }; - await this.openAddWindow(data); + this.evidenceData = data; + this.addEvidenceDialog = true; } + } else { + const { item } = createImageForWeb(imgURI); + const data = { + ...item, + timer_mark: this.timer, + }; + this.evidenceData = data; + this.addEvidenceDialog = true; } }; }; @@ -1309,41 +1417,58 @@ export default { console.log(error); }; try { - const stream = await navigator.mediaDevices.getUserMedia({ - audio: false, - video: { - mandatory: { - chromeMediaSource: "desktop", - chromeMediaSourceId: this.sourceId, - minWidth: 1280, - maxWidth: 10000, - minHeight: 720, - maxHeight: 4000, + let stream; + if (this.$isElectron) { + stream = await navigator.mediaDevices.getUserMedia({ + audio: false, + video: { + mandatory: { + chromeMediaSource: "desktop", + chromeMediaSourceId: this.sourceId, + minWidth: 1280, + maxWidth: 10000, + minHeight: 720, + maxHeight: 4000, + }, }, - }, - }); + }); + } else { + stream = this.mediaStream; + } + this.handleStream(stream); } catch (e) { this.handleError(e); } }, - startRecordVideo() { - this.fetchSources().then((data) => { - const list = data.filter((v) => v.id === this.sourceId); - if (list.length === 0) { - this.showSourcePickerDialog(); - } else { - this.videoRecordProcess(); + async startRecordVideo() { + if (this.$isElectron) { + this.fetchSources().then((data) => { + const list = data.filter((v) => v.id === this.sourceId); + if (list.length === 0) { + this.showSourcePickerDialog(); + } else { + this.videoRecordProcess(); + } + }); + } else { + if (!this.mediaStream) { + await this.setMediaStream(); } - }); + this.videoRecordProcess(); + } }, async videoRecordProcess() { this.handleStream = (stream) => { if (this.config.audioCapture && this.audioDevices.length > 0) { stream.addTrack(dest.stream.getAudioTracks()[0]); } + const mimeType = MediaRecorder.isTypeSupported("video/webm; codecs=vp9") + ? "video/webm; codecs=vp9" + : "video/webm"; + // const mimeType = "video/webm;codecs=h264"; mediaRecorder = new MediaRecorder(stream, { - mimeType: "video/webm;codecs=h264", + mimeType: mimeType, }); let poster; let frames = []; @@ -1370,6 +1495,9 @@ export default { console.log("Unable to generate poster for video: " + message); } poster = item.filePath; + } else { + const { item } = createImageForWeb(imgURI); + poster = item.filePath; } }; }; @@ -1380,7 +1508,7 @@ export default { }; mediaRecorder.onstop = async () => { this.recordVideoStarted = false; - const blob = new Blob(frames, { type: "video/webm;codecs=h264" }); + const blob = new Blob(frames, { type: mimeType }); const buffer = await blob.arrayBuffer(); if (this.$isElectron) { @@ -1390,20 +1518,28 @@ export default { this.$root.$emit("set-snackbar", message); console.log(message); } else { - const { id, fileName, filePath } = item; const data = { - id, - sessionType: "Video", - fileType: "video", - fileName, - filePath, + ...item, poster: poster, timer_mark: this.timer, }; - await this.openAddWindow(data); + this.evidenceData = data; + this.addEvidenceDialog = true; } + } else { + const { item } = createVideoForWeb(blob); + const data = { + ...item, + poster: poster, + timer_mark: this.timer, + }; + this.evidenceData = data; + this.addEvidenceDialog = true; } }; + // mediaRecorder.addEventListener("error", (event) => { + // console.error("MediaRecorder error:", event.error); + // }); frames = []; mediaRecorder.start(1000); }; @@ -1419,27 +1555,34 @@ export default { resolution = temp; } }); - const constraints = { - audio: false, - video: { - mandatory: { - chromeMediaSource: "desktop", - chromeMediaSourceId: this.sourceId, - minWidth: resolution.width, - maxWidth: resolution.width, - minHeight: resolution.height, - maxHeight: resolution.height, + + let stream; + if (this.$isElectron) { + const constraints = { + audio: false, + video: { + mandatory: { + chromeMediaSource: "desktop", + chromeMediaSourceId: this.sourceId, + minWidth: resolution.width, + maxWidth: resolution.width, + minHeight: resolution.height, + maxHeight: resolution.height, + }, }, - }, - }; - if (this.config.audioCapture) { - this.audioDevices = await this.getAudioSources(); - if (this.audioDevices.length > 0) { - await this.setAudio(this.audioDevices); + }; + if (this.config.audioCapture) { + this.audioDevices = await this.getAudioSources(); + if (this.audioDevices.length > 0) { + await this.setAudio(this.audioDevices); + } } + stream = await navigator.mediaDevices.getUserMedia(constraints); + } else { + stream = this.mediaStream; } - const stream = await navigator.mediaDevices.getUserMedia(constraints); - stream.getVideoTracks()[0].applyConstraints({ frameRate: 30 }); + + await stream.getVideoTracks()[0].applyConstraints({ frameRate: 30 }); this.handleStream(stream); } catch (e) { console.log(e); @@ -1519,17 +1662,23 @@ export default { console.log(message); } else { const data = { - id: item.id, - sessionType: "Audio", - fileType: "audio", - fileName: item.fileName, - filePath: item.filePath, + ...item, timer_mark: this.timer, poster: "", }; - await this.openAddWindow(data); + this.evidenceData = data; + this.addEvidenceDialog = true; } recordedChunks = []; + } else { + const { item } = createAudioForWeb(blob); + const data = { + ...item, + timer_mark: this.timer, + poster: "", + }; + this.evidenceData = data; + this.addEvidenceDialog = true; } }; mediaRecorder.start(1000); @@ -1537,17 +1686,6 @@ export default { this.handleError = (error) => { console.log("Error:", error); }; - // try { - // this.audioDevices = await this.getAudioSources(); - // if (!this.audioDevices.length) { - // this.audioErrorDialog = true; - // return; - // } - // const stream = this.setAudio(this.audioDevices); - // this.handleStream(stream); - // } catch (e) { - // console.log(e); - // } await navigator.mediaDevices.enumerateDevices().then((devices) => { this.audioDevices = devices.filter( (d) => @@ -1555,7 +1693,6 @@ export default { d.deviceId != "communications" && d.deviceId != "default" ); - console.log("audio devices:", this.audioDevices); if (!this.audioDevices.length) { this.audioErrorDialog = true; return; @@ -1570,55 +1707,88 @@ export default { console.log(error); } }, - async openAddWindow(data) { - if (this.$isElectron) { - await this.$electronService.openAddWindow(data); - } - }, async addNote(data) { - const { status, message, item } = await this.$storageService.saveNote( - data.comment - ); - if (status === STATUSES.ERROR) { - this.$root.$emit("set-snackbar", message); - console.log(message); + const stepID = uuidv4(); + let newItem = { + stepID: stepID, + fileType: DEFAULT_FILE_TYPES["text"].type, + comment: data.comment, + tags: data.tags, + emoji: data.emoji, + followUp: data.followUp, + timer_mark: this.timer, + color: "#e2e7fe", + createdAt: Date.now(), + }; + const updatedItems = [...this.items]; + let updatedNodes = [...this.nodes]; + let updatedConnections = [...this.connections]; + + if (this.nodes.length == 0) { + newItem.fx = Math.floor(Math.random() * 1001) - 500; + newItem.fy = Math.floor(Math.random() * 1001) - 500; } else { - let newItem = { - id: item.id, - sessionType: "Note", - fileType: "text", - fileName: item.fileName, - filePath: item.filePath, - comment: data.comment, - tags: data.tags, - emoji: data.emoji, - followUp: data.followUp, - timer_mark: this.timer, - createdAt: Date.now(), - }; + let random_offset_x, random_offset_y; + do { + random_offset_x = Math.floor(Math.random() * 800) - 400; + random_offset_y = Math.floor(Math.random() * 800) - 400; + } while ( + (random_offset_x >= -200 && random_offset_x <= -100) || + (random_offset_x >= 100 && random_offset_x <= 200) + ); + newItem.fx = this.nodes[this.nodes.length - 1].fx + random_offset_x; + newItem.fy = this.nodes[this.nodes.length - 1].fy + random_offset_y; + } + updatedItems.push(newItem); + updatedItems.forEach((item) => { + if (item.fileType === "text/plain") { + item.id = item.stepID; + updatedNodes.push({ ...item, content: item.comment.text }); + } + }); - this.$emit("add-item", newItem); - this.noteDialog = false; + if (this.nodes.length > 0) { + if (this.selectedNodes.length) { + this.selectedNodes.forEach((node) => { + updatedConnections.push({ + source: node.stepID, + target: newItem.stepID, + }); + }); + } else { + updatedConnections.push({ + source: this.nodes[this.nodes.length - 1].stepID, + target: newItem.stepID, + }); + } } + await this.$store.commit("setSessionItems", [...updatedItems]); + await this.$store.commit("setSessionNodes", [...updatedNodes]); + await this.$store.commit("setSessionConnections", [ + ...updatedConnections, + ]); + this.noteDialog = false; + this.$root.$emit("render-mindmap"); }, async addSummary(value) { // TODO - handle summary like a regular note and allow additional metadata const data = { - id: uuidv4(), - sessionType: "Summary", + stepID: uuidv4(), + fileType: DEFAULT_FILE_TYPES["text"].type, comment: value, + tags: [], + emoji: [], + followUp: false, timer_mark: this.timer, createdAt: Date.now(), }; if (Object.keys(this.summary).length) { - const items = this.items.map((item) => { - let temp = Object.assign({}, item); - if (temp.sessionType === "Summary") { - temp = data; - } - return temp; - }); - this.$root.$emit("save-session", items); + delete data.stepID; + const newSummary = { + ...this.summary, + ...data, + }; + this.$emit("update-item", newSummary); } else { this.$emit("add-item", data); } @@ -1628,12 +1798,13 @@ export default { addMindmap() { // TODO - With transition to try mindmap format, UUID generation should // move to CaptureUtility - const id = uuidv4(); + const stepID = uuidv4(); + const attachmentID = uuidv4(); const data = { - id, - sessionType: "Mindmap", - fileType: "mindmap", - fileName: `mindmap-${id.substring(0, 5)}.png`, + stepID, + attachmentID, + fileType: DEFAULT_FILE_TYPES["mindmap"].type, + fileName: `mindmap-${attachmentID.substring(0, 5)}.png`, filePath: "", content: { nodes: DEFAULT_MAP_NODES, @@ -1641,10 +1812,11 @@ export default { }, timer_mark: this.timer, }; - this.openAddWindow(data); + this.evidenceData = data; + this.addEvidenceDialog = true; }, async deleteItems() { - await this.$storageService.deleteItems(this.selected); + this.$store.commit("deleteSessionItems", this.selected); this.selected = []; this.$root.$emit("update-selected", this.selected); this.deleteConfirmDialog = false; @@ -1659,20 +1831,24 @@ export default { }, async saveSession(callback = null) { this.newSessionDialog = false; - const sessionId = await this.$storageService.getSessionId(); const data = { - id: sessionId, - title: this.$store.state.title, - charter: this.$store.state.charter, - mindmap: this.$store.state.mindmap, - preconditions: this.$store.state.preconditions, - duration: this.$store.state.duration, - status: this.$store.state.status, - timer: this.$store.state.timer, - started: this.$store.state.started, - ended: this.$store.state.ended, - quickTest: this.$store.state.quickTest, - path: this.$route.path, + case: { + caseID: this.$store.state.case.caseID, + title: this.$store.state.case.title, + charter: this.$store.state.case.charter, + mindmap: this.$store.state.case.mindmap, + preconditions: this.$store.state.case.preconditions, + duration: this.$store.state.case.duration, + }, + session: { + sessionID: this.$store.state.session.sessionID, + status: this.$store.state.session.status, + timer: this.$store.state.session.timer, + started: this.$store.state.session.started, + ended: this.$store.state.session.ended, + quickTest: this.$store.state.session.quickTest, + path: this.$route.path, + }, }; const { status } = await this.$storageService.saveSession(data); if (status === STATUSES.SUCCESS && callback) { @@ -1709,7 +1885,7 @@ export default { this.changeSessionStatus(SESSION_STATUSES.PENDING); this.timer = 0; this.isDuration = false; - this.duration = this.$store.state.duration; + this.duration = this.$store.state.case.duration; // Clear dialogs this.sourcePickerDialog = false; @@ -1723,27 +1899,33 @@ export default { this.audioErrorDialog = false; this.endSessionDialog = false; - // creating new session ID here - let sessionId = uuidv4(); - this.$store.commit("setSessionId", sessionId); - const data = { - id: sessionId, - title: this.$store.state.title, - charter: this.$store.state.charter, - preconditions: this.$store.state.preconditions, - duration: this.$store.state.duration, - status: this.$store.state.status, - timer: this.$store.state.timer, - started: this.$store.state.started, - ended: this.$store.state.ended, - quickTest: this.$store.state.quickTest, - path: this.$route.path, + case: { + title: this.$store.state.case.title, + charter: this.$store.state.case.charter, + preconditions: this.$store.state.case.preconditions, + duration: this.$store.state.case.duration, + }, + session: { + status: this.$store.state.session.status, + timer: this.$store.state.session.timer, + started: this.$store.state.session.started, + ended: this.$store.state.session.ended, + quickTest: this.$store.state.session.quickTest, + path: this.$route.path, + }, }; await this.$storageService.createNewSession(data); await this.$storageService.resetData(); + if (this.$isElectron) { + const caseID = await this.$storageService.getCaseId(); + const sessionID = await this.$storageService.getSessionId(); + this.$store.commit("setCaseID", caseID); + this.$store.commit("setSessionID", sessionID); + } + // Stop any ongoing intervals this.stopInterval(); }, @@ -1778,18 +1960,7 @@ export default { } }, getCurrentDateTime() { - const now = new Date(); - const currentDateTime = - String(now.getHours()).padStart(2, "0") + - ":" + - String(now.getMinutes()).padStart(2, "0") + - " | " + - String(now.getMonth() + 1).padStart(2, "0") + - "-" + - String(now.getDate()).padStart(2, "0") + - "-" + - now.getFullYear(); - return currentDateTime; + return new Date().toISOString(); }, changeSessionStatus(status) { if (this.$isElectron) { @@ -1805,7 +1976,7 @@ export default { }; localStorage.setItem("state-data", JSON.stringify(data)); if (this.$isElectron) { - await this.$electronService.openMinimizeWindow(); + await this.$electronService.openLowProfileWindow(); } }, }, @@ -1813,6 +1984,9 @@ export default { + diff --git a/src/components/ExportPanel.vue b/src/components/ExportPanel.vue index 61c275b6..bc4be47f 100644 --- a/src/components/ExportPanel.vue +++ b/src/components/ExportPanel.vue @@ -27,16 +27,69 @@ - + mdi-download - {{ $tc("caption.save_as", 1) }} + {{ $tc("caption.save_as_zip", 1) }} + + + mdi-download + + + + {{ $tc("caption.save_as_pdf", 1) }} + + + +
+ +
+
+ +
+
+ +
+ + + + + + + +
+
+
+
+
+ +
+
+
+
+
+ + + + + + +
+
+
+ + + + {{ $tc("caption.shapes", 1) }} + + + + + + + {{ $tc("caption.upload_evidence", 1) }} + +
+
+
+
+ +
+ + + {{ $tc("caption.zoom_in_to_flow", 1) }} + + +
+
+ + + {{ $tc("caption.zoom_in", 1) }} + + + + {{ $tc("caption.zoom_out", 1) }} + +
+
+
+ + + + + + + + + diff --git a/src/components/NewMindmapEditor.vue b/src/components/NewMindmapEditor.vue new file mode 100644 index 00000000..b153881d --- /dev/null +++ b/src/components/NewMindmapEditor.vue @@ -0,0 +1,913 @@ + + + + + diff --git a/src/components/NewNode.vue b/src/components/NewNode.vue new file mode 100644 index 00000000..6f2734a6 --- /dev/null +++ b/src/components/NewNode.vue @@ -0,0 +1,356 @@ + + + + + diff --git a/src/components/NewNodeComponent.vue b/src/components/NewNodeComponent.vue new file mode 100644 index 00000000..4ef1d7fd --- /dev/null +++ b/src/components/NewNodeComponent.vue @@ -0,0 +1,295 @@ + + + + + diff --git a/src/components/NodeComponent.vue b/src/components/NodeComponent.vue new file mode 100644 index 00000000..a7f4a575 --- /dev/null +++ b/src/components/NodeComponent.vue @@ -0,0 +1,240 @@ + + + + + diff --git a/src/components/NotesWrapper.vue b/src/components/NotesWrapper.vue index 1f2757ca..100d61b1 100644 --- a/src/components/NotesWrapper.vue +++ b/src/components/NotesWrapper.vue @@ -2,7 +2,7 @@
@@ -29,6 +29,7 @@ v-model="itemLists" draggable=".draggable-item" class="draggable-wrapper" + :animation="200" @change="handleChange" > @@ -37,21 +38,28 @@ :key="i" class="draggable-item notes-evidence" > - - - -