🔖 v1.9.0

This commit is contained in:
Liyas Thomas
2020-02-24 18:36:54 +05:30
26 changed files with 1299 additions and 192 deletions

View File

@@ -9,7 +9,9 @@
- Disable SSL cert for websockets [\#557](https://github.com/liyasthomas/postwoman/issues/557) - Disable SSL cert for websockets [\#557](https://github.com/liyasthomas/postwoman/issues/557)
- Feature request: Keyboard shortcuts for folder creation [\#539](https://github.com/liyasthomas/postwoman/issues/539) - Feature request: Keyboard shortcuts for folder creation [\#539](https://github.com/liyasthomas/postwoman/issues/539)
- Friendly minded GraphQL [\#468](https://github.com/liyasthomas/postwoman/issues/468) - Friendly minded GraphQL [\#468](https://github.com/liyasthomas/postwoman/issues/468)
- multipart/form-data support [\#434](https://github.com/liyasthomas/postwoman/issues/434)
- Implement pre-request and post-request scripts \(and request chaining\) [\#218](https://github.com/liyasthomas/postwoman/issues/218) - Implement pre-request and post-request scripts \(and request chaining\) [\#218](https://github.com/liyasthomas/postwoman/issues/218)
- Environment management and configuration [\#147](https://github.com/liyasthomas/postwoman/issues/147)
- POST request body editor reacts to the content type [\#594](https://github.com/liyasthomas/postwoman/pull/594) ([AndrewBastin](https://github.com/AndrewBastin)) - POST request body editor reacts to the content type [\#594](https://github.com/liyasthomas/postwoman/pull/594) ([AndrewBastin](https://github.com/AndrewBastin))
- Environment Mangement [\#591](https://github.com/liyasthomas/postwoman/pull/591) ([JacobAnavisca](https://github.com/JacobAnavisca)) - Environment Mangement [\#591](https://github.com/liyasthomas/postwoman/pull/591) ([JacobAnavisca](https://github.com/JacobAnavisca))
- GraphQL Query Autocompletion [\#590](https://github.com/liyasthomas/postwoman/pull/590) ([AndrewBastin](https://github.com/AndrewBastin)) - GraphQL Query Autocompletion [\#590](https://github.com/liyasthomas/postwoman/pull/590) ([AndrewBastin](https://github.com/AndrewBastin))
@@ -75,9 +77,8 @@
- i18n [\#538](https://github.com/liyasthomas/postwoman/pull/538) ([liyasthomas](https://github.com/liyasthomas)) - i18n [\#538](https://github.com/liyasthomas/postwoman/pull/538) ([liyasthomas](https://github.com/liyasthomas))
- Modification of French translations [\#537](https://github.com/liyasthomas/postwoman/pull/537) ([thomasbnt](https://github.com/thomasbnt)) - Modification of French translations [\#537](https://github.com/liyasthomas/postwoman/pull/537) ([thomasbnt](https://github.com/thomasbnt))
- Even [\#535](https://github.com/liyasthomas/postwoman/pull/535) ([liyasthomas](https://github.com/liyasthomas)) - Even [\#535](https://github.com/liyasthomas/postwoman/pull/535) ([liyasthomas](https://github.com/liyasthomas))
- Enhancements [\#531](https://github.com/liyasthomas/postwoman/pull/531) ([jamesgeorge007](https://github.com/jamesgeorge007))
- Updating spanish translation [\#529](https://github.com/liyasthomas/postwoman/pull/529) ([liyasthomas](https://github.com/liyasthomas)) - Updating spanish translation [\#529](https://github.com/liyasthomas/postwoman/pull/529) ([liyasthomas](https://github.com/liyasthomas))
- even merge [\#528](https://github.com/liyasthomas/postwoman/pull/528) ([liyasthomas](https://github.com/liyasthomas)) - chore\(deps\): bump nuxt-i18n from 6.4.1 to 6.5.0 [\#522](https://github.com/liyasthomas/postwoman/pull/522) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
## [v1.8.0](https://github.com/liyasthomas/postwoman/tree/v1.8.0) (2020-01-28) ## [v1.8.0](https://github.com/liyasthomas/postwoman/tree/v1.8.0) (2020-01-28)
@@ -94,6 +95,7 @@
- Feature Request: Consumer Driven Contract Testing [\#420](https://github.com/liyasthomas/postwoman/issues/420) - Feature Request: Consumer Driven Contract Testing [\#420](https://github.com/liyasthomas/postwoman/issues/420)
- Feature Request: Support OAuth2/OIDC [\#337](https://github.com/liyasthomas/postwoman/issues/337) - Feature Request: Support OAuth2/OIDC [\#337](https://github.com/liyasthomas/postwoman/issues/337)
- Add DB cache [\#26](https://github.com/liyasthomas/postwoman/issues/26) - Add DB cache [\#26](https://github.com/liyasthomas/postwoman/issues/26)
- Update asset/\*. js to asset/\*. ts. [\#517](https://github.com/liyasthomas/postwoman/pull/517) ([Sn005](https://github.com/Sn005))
- Auth [\#513](https://github.com/liyasthomas/postwoman/pull/513) ([liyasthomas](https://github.com/liyasthomas)) - Auth [\#513](https://github.com/liyasthomas/postwoman/pull/513) ([liyasthomas](https://github.com/liyasthomas))
- Support for Google Chrome Extension [\#512](https://github.com/liyasthomas/postwoman/pull/512) ([AndrewBastin](https://github.com/AndrewBastin)) - Support for Google Chrome Extension [\#512](https://github.com/liyasthomas/postwoman/pull/512) ([AndrewBastin](https://github.com/AndrewBastin))
- GraphQL query validation based on schema [\#508](https://github.com/liyasthomas/postwoman/pull/508) ([AndrewBastin](https://github.com/AndrewBastin)) - GraphQL query validation based on schema [\#508](https://github.com/liyasthomas/postwoman/pull/508) ([AndrewBastin](https://github.com/AndrewBastin))
@@ -110,7 +112,6 @@
- Multiple collections with the same name shouldn't exist [\#509](https://github.com/liyasthomas/postwoman/issues/509) - Multiple collections with the same name shouldn't exist [\#509](https://github.com/liyasthomas/postwoman/issues/509)
- GraphQL String variables are null [\#497](https://github.com/liyasthomas/postwoman/issues/497) - GraphQL String variables are null [\#497](https://github.com/liyasthomas/postwoman/issues/497)
- Post request body is empty [\#473](https://github.com/liyasthomas/postwoman/issues/473) - Post request body is empty [\#473](https://github.com/liyasthomas/postwoman/issues/473)
- API Documentation won't be generated [\#456](https://github.com/liyasthomas/postwoman/issues/456)
**Closed issues:** **Closed issues:**
@@ -121,15 +122,15 @@
- import cURL error [\#477](https://github.com/liyasthomas/postwoman/issues/477) - import cURL error [\#477](https://github.com/liyasthomas/postwoman/issues/477)
- move to postwoman org [\#475](https://github.com/liyasthomas/postwoman/issues/475) - move to postwoman org [\#475](https://github.com/liyasthomas/postwoman/issues/475)
- Create standalone vue components of the request builder. [\#474](https://github.com/liyasthomas/postwoman/issues/474) - Create standalone vue components of the request builder. [\#474](https://github.com/liyasthomas/postwoman/issues/474)
- \* ../.postwoman/version.json in ./node\_modules/babel-loader/lib??ref--2-0!./node\_modules/vue-loader/lib??vue-loader-options!./layouts/default.vue?vue&type=script&lang=js& friendly-errors 11:12:37 [\#448](https://github.com/liyasthomas/postwoman/issues/448)
- Enable running proxy as a backend for Request Capture [\#325](https://github.com/liyasthomas/postwoman/issues/325) - Enable running proxy as a backend for Request Capture [\#325](https://github.com/liyasthomas/postwoman/issues/325)
- Label doesn't change when switching between collection requests [\#291](https://github.com/liyasthomas/postwoman/issues/291) - Label doesn't change when switching between collection requests [\#291](https://github.com/liyasthomas/postwoman/issues/291)
**Merged pull requests:** **Merged pull requests:**
- Enhancements [\#531](https://github.com/liyasthomas/postwoman/pull/531) ([jamesgeorge007](https://github.com/jamesgeorge007))
- Merge pull request \#530 from liyasthomas/feature/post-request-tests [\#530](https://github.com/liyasthomas/postwoman/pull/530) ([liyasthomas](https://github.com/liyasthomas)) - Merge pull request \#530 from liyasthomas/feature/post-request-tests [\#530](https://github.com/liyasthomas/postwoman/pull/530) ([liyasthomas](https://github.com/liyasthomas))
- even merge [\#528](https://github.com/liyasthomas/postwoman/pull/528) ([liyasthomas](https://github.com/liyasthomas))
- Refactor [\#523](https://github.com/liyasthomas/postwoman/pull/523) ([liyasthomas](https://github.com/liyasthomas)) - Refactor [\#523](https://github.com/liyasthomas/postwoman/pull/523) ([liyasthomas](https://github.com/liyasthomas))
- chore\(deps\): bump nuxt-i18n from 6.4.1 to 6.5.0 [\#522](https://github.com/liyasthomas/postwoman/pull/522) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- chore\(deps\): bump v-tooltip from 2.0.2 to 2.0.3 [\#521](https://github.com/liyasthomas/postwoman/pull/521) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview)) - chore\(deps\): bump v-tooltip from 2.0.2 to 2.0.3 [\#521](https://github.com/liyasthomas/postwoman/pull/521) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- chore\(deps-dev\): bump cypress from 3.8.2 to 3.8.3 [\#520](https://github.com/liyasthomas/postwoman/pull/520) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview)) - chore\(deps-dev\): bump cypress from 3.8.2 to 3.8.3 [\#520](https://github.com/liyasthomas/postwoman/pull/520) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- Feature/post request tests [\#518](https://github.com/liyasthomas/postwoman/pull/518) ([nickpalenchar](https://github.com/nickpalenchar)) - Feature/post request tests [\#518](https://github.com/liyasthomas/postwoman/pull/518) ([nickpalenchar](https://github.com/nickpalenchar))
@@ -160,7 +161,6 @@
- Can WSDL be implemented, similar to SoapUI? [\#461](https://github.com/liyasthomas/postwoman/issues/461) - Can WSDL be implemented, similar to SoapUI? [\#461](https://github.com/liyasthomas/postwoman/issues/461)
- Raw Request Body should be supported to format the JSON string [\#446](https://github.com/liyasthomas/postwoman/issues/446) - Raw Request Body should be supported to format the JSON string [\#446](https://github.com/liyasthomas/postwoman/issues/446)
- multipart/form-data support [\#434](https://github.com/liyasthomas/postwoman/issues/434)
- Ability to send Binary data using Postwoman [\#415](https://github.com/liyasthomas/postwoman/issues/415) - Ability to send Binary data using Postwoman [\#415](https://github.com/liyasthomas/postwoman/issues/415)
- Custom request method [\#398](https://github.com/liyasthomas/postwoman/issues/398) - Custom request method [\#398](https://github.com/liyasthomas/postwoman/issues/398)
- \[request\]: CLI possibilities [\#363](https://github.com/liyasthomas/postwoman/issues/363) - \[request\]: CLI possibilities [\#363](https://github.com/liyasthomas/postwoman/issues/363)
@@ -189,15 +189,16 @@
- Cache view [\#188](https://github.com/liyasthomas/postwoman/issues/188) - Cache view [\#188](https://github.com/liyasthomas/postwoman/issues/188)
- chore: stick to Vue.js best practices [\#432](https://github.com/liyasthomas/postwoman/pull/432) ([jamesgeorge007](https://github.com/jamesgeorge007)) - chore: stick to Vue.js best practices [\#432](https://github.com/liyasthomas/postwoman/pull/432) ([jamesgeorge007](https://github.com/jamesgeorge007))
- Header key autocompletion [\#421](https://github.com/liyasthomas/postwoman/pull/421) ([AndrewBastin](https://github.com/AndrewBastin)) - Header key autocompletion [\#421](https://github.com/liyasthomas/postwoman/pull/421) ([AndrewBastin](https://github.com/AndrewBastin))
- Custom methods support [\#400](https://github.com/liyasthomas/postwoman/pull/400) ([liyasthomas](https://github.com/liyasthomas))
- Two Way Data Binding \(v-model\) to Ace Editor component [\#379](https://github.com/liyasthomas/postwoman/pull/379) ([AndrewBastin](https://github.com/AndrewBastin)) - Two Way Data Binding \(v-model\) to Ace Editor component [\#379](https://github.com/liyasthomas/postwoman/pull/379) ([AndrewBastin](https://github.com/AndrewBastin))
- Basic i18n support [\#351](https://github.com/liyasthomas/postwoman/pull/351) ([liyasthomas](https://github.com/liyasthomas)) - Basic i18n support [\#351](https://github.com/liyasthomas/postwoman/pull/351) ([liyasthomas](https://github.com/liyasthomas))
- Undo header/param/body param deletion [\#350](https://github.com/liyasthomas/postwoman/pull/350) ([AndrewBastin](https://github.com/AndrewBastin)) - Undo header/param/body param deletion [\#350](https://github.com/liyasthomas/postwoman/pull/350) ([AndrewBastin](https://github.com/AndrewBastin))
- Added ability to run GraphQL queries [\#346](https://github.com/liyasthomas/postwoman/pull/346) ([AndrewBastin](https://github.com/AndrewBastin))
- refactor: minor improvements [\#343](https://github.com/liyasthomas/postwoman/pull/343) ([jamesgeorge007](https://github.com/jamesgeorge007)) - refactor: minor improvements [\#343](https://github.com/liyasthomas/postwoman/pull/343) ([jamesgeorge007](https://github.com/jamesgeorge007))
**Fixed bugs:** **Fixed bugs:**
- WebSocket page freezes when pasting long URL [\#471](https://github.com/liyasthomas/postwoman/issues/471) - WebSocket page freezes when pasting long URL [\#471](https://github.com/liyasthomas/postwoman/issues/471)
- API Documentation won't be generated [\#456](https://github.com/liyasthomas/postwoman/issues/456)
- Sharing Requests via link is not working [\#435](https://github.com/liyasthomas/postwoman/issues/435) - Sharing Requests via link is not working [\#435](https://github.com/liyasthomas/postwoman/issues/435)
- URL input text is so stutters [\#412](https://github.com/liyasthomas/postwoman/issues/412) - URL input text is so stutters [\#412](https://github.com/liyasthomas/postwoman/issues/412)
- Save to collections after deleting all the collections causes an error page [\#390](https://github.com/liyasthomas/postwoman/issues/390) - Save to collections after deleting all the collections causes an error page [\#390](https://github.com/liyasthomas/postwoman/issues/390)
@@ -214,6 +215,7 @@
**Closed issues:** **Closed issues:**
- Module not found: Error: Can't resolve '../.postwoman/version.json' [\#457](https://github.com/liyasthomas/postwoman/issues/457) - Module not found: Error: Can't resolve '../.postwoman/version.json' [\#457](https://github.com/liyasthomas/postwoman/issues/457)
- \* ../.postwoman/version.json in ./node\_modules/babel-loader/lib??ref--2-0!./node\_modules/vue-loader/lib??vue-loader-options!./layouts/default.vue?vue&type=script&lang=js& friendly-errors 11:12:37 [\#448](https://github.com/liyasthomas/postwoman/issues/448)
- npm run dev module was not found: ../.postwoman/version.json [\#442](https://github.com/liyasthomas/postwoman/issues/442) - npm run dev module was not found: ../.postwoman/version.json [\#442](https://github.com/liyasthomas/postwoman/issues/442)
- graphql and websocket work, but http and https do not [\#441](https://github.com/liyasthomas/postwoman/issues/441) - graphql and websocket work, but http and https do not [\#441](https://github.com/liyasthomas/postwoman/issues/441)
- Can I test localhost? [\#433](https://github.com/liyasthomas/postwoman/issues/433) - Can I test localhost? [\#433](https://github.com/liyasthomas/postwoman/issues/433)
@@ -245,6 +247,7 @@
- Generated code is incorrect [\#269](https://github.com/liyasthomas/postwoman/issues/269) - Generated code is incorrect [\#269](https://github.com/liyasthomas/postwoman/issues/269)
- Lacking documentation and wiki [\#232](https://github.com/liyasthomas/postwoman/issues/232) - Lacking documentation and wiki [\#232](https://github.com/liyasthomas/postwoman/issues/232)
- I can't send POST method [\#210](https://github.com/liyasthomas/postwoman/issues/210) - I can't send POST method [\#210](https://github.com/liyasthomas/postwoman/issues/210)
- Handling request failures when build number is obtained from GitHub [\#122](https://github.com/liyasthomas/postwoman/issues/122)
**Merged pull requests:** **Merged pull requests:**
@@ -275,7 +278,6 @@
- ⬆️ Bump vue-virtual-scroll-list from 1.4.3 to 1.4.4 [\#406](https://github.com/liyasthomas/postwoman/pull/406) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview)) - ⬆️ Bump vue-virtual-scroll-list from 1.4.3 to 1.4.4 [\#406](https://github.com/liyasthomas/postwoman/pull/406) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- ⬆️ Bump nuxt-i18n from 6.4.0 to 6.4.1 [\#405](https://github.com/liyasthomas/postwoman/pull/405) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview)) - ⬆️ Bump nuxt-i18n from 6.4.0 to 6.4.1 [\#405](https://github.com/liyasthomas/postwoman/pull/405) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- I18n [\#404](https://github.com/liyasthomas/postwoman/pull/404) ([yubathom](https://github.com/yubathom)) - I18n [\#404](https://github.com/liyasthomas/postwoman/pull/404) ([yubathom](https://github.com/yubathom))
- Improving translate for pt-BR [\#396](https://github.com/liyasthomas/postwoman/pull/396) ([GustavoBezerra](https://github.com/GustavoBezerra))
- App UI [\#391](https://github.com/liyasthomas/postwoman/pull/391) ([liyasthomas](https://github.com/liyasthomas)) - App UI [\#391](https://github.com/liyasthomas/postwoman/pull/391) ([liyasthomas](https://github.com/liyasthomas))
- i18n [\#383](https://github.com/liyasthomas/postwoman/pull/383) ([liyasthomas](https://github.com/liyasthomas)) - i18n [\#383](https://github.com/liyasthomas/postwoman/pull/383) ([liyasthomas](https://github.com/liyasthomas))
- Added Turkish Language Support [\#382](https://github.com/liyasthomas/postwoman/pull/382) ([AliAnilKocak](https://github.com/AliAnilKocak)) - Added Turkish Language Support [\#382](https://github.com/liyasthomas/postwoman/pull/382) ([AliAnilKocak](https://github.com/AliAnilKocak))
@@ -297,7 +299,6 @@
- Added Farsi language support [\#357](https://github.com/liyasthomas/postwoman/pull/357) ([hosseinnedaee](https://github.com/hosseinnedaee)) - Added Farsi language support [\#357](https://github.com/liyasthomas/postwoman/pull/357) ([hosseinnedaee](https://github.com/hosseinnedaee))
- Adding french language basic [\#355](https://github.com/liyasthomas/postwoman/pull/355) ([thomasbnt](https://github.com/thomasbnt)) - Adding french language basic [\#355](https://github.com/liyasthomas/postwoman/pull/355) ([thomasbnt](https://github.com/thomasbnt))
- Add Proxy URL option [\#345](https://github.com/liyasthomas/postwoman/pull/345) ([NBTX](https://github.com/NBTX)) - Add Proxy URL option [\#345](https://github.com/liyasthomas/postwoman/pull/345) ([NBTX](https://github.com/NBTX))
- ♻️ Refactor Functions [\#344](https://github.com/liyasthomas/postwoman/pull/344) ([athul](https://github.com/athul))
## [v1.0.0](https://github.com/liyasthomas/postwoman/tree/v1.0.0) (2019-11-04) ## [v1.0.0](https://github.com/liyasthomas/postwoman/tree/v1.0.0) (2019-11-04)
@@ -378,7 +379,6 @@
- Response with content-type "application/hal+json" shows as \[Object object\] [\#158](https://github.com/liyasthomas/postwoman/issues/158) - Response with content-type "application/hal+json" shows as \[Object object\] [\#158](https://github.com/liyasthomas/postwoman/issues/158)
- A place to discuss [\#149](https://github.com/liyasthomas/postwoman/issues/149) - A place to discuss [\#149](https://github.com/liyasthomas/postwoman/issues/149)
- Inconsistent version name [\#141](https://github.com/liyasthomas/postwoman/issues/141) - Inconsistent version name [\#141](https://github.com/liyasthomas/postwoman/issues/141)
- Handling request failures when build number is obtained from GitHub [\#122](https://github.com/liyasthomas/postwoman/issues/122)
- Autoresize the textarea [\#102](https://github.com/liyasthomas/postwoman/issues/102) - Autoresize the textarea [\#102](https://github.com/liyasthomas/postwoman/issues/102)
- Content-Type revamping [\#99](https://github.com/liyasthomas/postwoman/issues/99) - Content-Type revamping [\#99](https://github.com/liyasthomas/postwoman/issues/99)
- Add version number in footer [\#97](https://github.com/liyasthomas/postwoman/issues/97) - Add version number in footer [\#97](https://github.com/liyasthomas/postwoman/issues/97)

View File

@@ -204,7 +204,7 @@ _**All `i18n` contributions are welcome to `i18n` [branch](https://github.com/li
- **[CLI β](https://github.com/postwoman-io/postwoman-cli)** - A CLI solution for Postwoman - **[CLI β](https://github.com/postwoman-io/postwoman-cli)** - A CLI solution for Postwoman
- **Browser Extensions** - Browser extensions that simplifies access to Postwoman - **Browser Extensions** - Browser extensions that simplifies access to Postwoman
[![Firefox](https://raw.github.com/alrra/browser-logos/master/src/firefox/firefox_16x16.png) **Firefox**](https://addons.mozilla.org/en-US/firefox/addon/postwoman) ([GitHub](https://github.com/AndrewBastin/postwoman-firefox))  |  [![Chrome](https://raw.github.com/alrra/browser-logos/master/src/chrome/chrome_16x16.png) **Chrome**](https://chrome.google.com/webstore/detail/postwoman-extension-for-c/amknoiejhlmhancpahfcfcfhllgkpbld) ([GitHub](https://github.com/AndrewBastin/postwoman-chrome)) [![Firefox](https://raw.github.com/alrra/browser-logos/master/src/firefox/firefox_16x16.png) **Firefox**](https://addons.mozilla.org/en-US/firefox/addon/postwoman)  |  [![Chrome](https://raw.github.com/alrra/browser-logos/master/src/chrome/chrome_16x16.png) **Chrome**](https://chrome.google.com/webstore/detail/postwoman-extension-for-c/amknoiejhlmhancpahfcfcfhllgkpbld) ([GitHub](https://github.com/AndrewBastin/postwoman-extension))
>**Extensions fixes `CORS` issues.** >**Extensions fixes `CORS` issues.**
@@ -315,7 +315,10 @@ See the [CHANGELOG](CHANGELOG.md) file for details.
### Lead Developers ### Lead Developers
* **[Liyas Thomas](https://github.com/liyasthomas)** - *Author* * **[Liyas Thomas](https://github.com/liyasthomas)** - *Author*
* **[Caneco](https://twitter.com/caneco)** - *Designer* * **[John Harker](https://github.com/NBTX)** - *Lead developer*
* **[Andrew Bastin](https://github.com/andrewbastin)** - *Lead developer*
* **[James George](https://github.com/jamesgeorge007)** - *Lead maintainer*
* **[Caneco](https://twitter.com/caneco)** - *Logo and banner designer*
### Testing and Debugging ### Testing and Debugging

View File

@@ -22,13 +22,11 @@ $responsiveWidth: 768px;
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 4px; width: 4px;
height: 4px; height: 4px;
border-radius: 4px; background-color: var(--bg-dark-color);
background-color: var(--bg-light-color);
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
background-color: var(--fg-light-color); background-color: var(--fg-light-color);
border-radius: 8px;
&:hover { &:hover {
background-color: var(--fg-color); background-color: var(--fg-color);
@@ -60,9 +58,9 @@ body {
padding: 0; padding: 0;
margin: 0; margin: 0;
scroll-behavior: smooth; scroll-behavior: smooth;
transition: all 0.2s ease-in-out;
} }
// Make theme transition smoother.
body.afterLoad { body.afterLoad {
transition: background-color 0.2s ease-in-out; transition: background-color 0.2s ease-in-out;
} }
@@ -76,6 +74,10 @@ a {
color: inherit; color: inherit;
text-decoration: none; text-decoration: none;
transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out;
&.link {
color: var(--ac-color);
}
} }
header, header,
@@ -146,7 +148,8 @@ footer {
z-index: 1; z-index: 1;
height: 100vh; height: 100vh;
padding: 0 8px; padding: 0 8px;
background-color: var(--bg-light-color); background-color: var(--bg-dark-color);
transition: all 0.2s ease-in-out;
} }
.main { .main {
@@ -173,6 +176,7 @@ nav.primary-nav {
svg { svg {
fill: var(--fg-light-color); fill: var(--fg-light-color);
transition: all 0.2s ease-in-out;
} }
a { a {
@@ -186,7 +190,6 @@ nav.primary-nav {
color: var(--fg-light-color); color: var(--fg-light-color);
fill: var(--fg-light-color); fill: var(--fg-light-color);
margin: 8px 0; margin: 8px 0;
transition: all 0.2s ease-in-out;
&:hover { &:hover {
color: var(--fg-color); color: var(--fg-color);
@@ -263,11 +266,16 @@ hr {
border-bottom: 1px dashed var(--brd-color); border-bottom: 1px dashed var(--brd-color);
} }
p {
transition: all 0.2s ease-in-out;
}
.tooltip { .tooltip {
$bgcolor: var(--tt-color); $bgcolor: var(--tt-color);
$fgcolor: var(--fg-color); $fgcolor: var(--fg-color);
display: block !important; display: block !important;
z-index: 10000; z-index: 10000;
transition: all 0.2s ease-in-out;
.tooltip-inner { .tooltip-inner {
background: $bgcolor; background: $bgcolor;
@@ -422,7 +430,6 @@ button {
color: var(--act-color); color: var(--act-color);
fill: var(--act-color); fill: var(--act-color);
box-shadow: inset 0 0 0 2px var(--fg-color); box-shadow: inset 0 0 0 2px var(--fg-color);
transition: all 0.2s ease-in-out;
} }
&.icon { &.icon {
@@ -437,7 +444,6 @@ button {
color: var(--fg-color); color: var(--fg-color);
fill: var(--fg-color); fill: var(--fg-color);
box-shadow: none; box-shadow: none;
transition: all 0.2s ease-in-out;
} }
} }
@@ -472,8 +478,19 @@ button {
fieldset { fieldset {
margin: 16px 0; margin: 16px 0;
border-radius: 16px; border-radius: 16px;
transition: all 0.2s ease-in-out;
background-color: var(--bg-dark-color); background-color: var(--bg-dark-color);
transition: all 0.2s ease-in-out;
}
fieldset:target,
section:target {
animation: highlight 2s ease;
}
@keyframes highlight {
50% {
box-shadow: 0 0 0 2px var(--ac-color);
}
} }
legend { legend {
@@ -483,6 +500,7 @@ legend {
color: var(--fg-color); color: var(--fg-color);
font-weight: 700; font-weight: 700;
cursor: pointer; cursor: pointer;
transition: all 0.2s ease-in-out;
* { * {
vertical-align: middle; vertical-align: middle;
@@ -565,7 +583,6 @@ code {
&:not([readonly]):not(.ace_editor):active, &:not([readonly]):not(.ace_editor):active,
&:not([readonly]):not(.ace_editor):focus { &:not([readonly]):not(.ace_editor):focus {
box-shadow: inset 0 0 0 2px var(--fg-light-color); box-shadow: inset 0 0 0 2px var(--fg-light-color);
transition: all 0.2s ease-in-out;
} }
} }
@@ -576,7 +593,6 @@ code {
&:active, &:active,
&:focus { &:focus {
box-shadow: inset 0 0 0 2px var(--fg-light-color); box-shadow: inset 0 0 0 2px var(--fg-light-color);
transition: all 0.2s ease-in-out;
} }
} }
@@ -681,6 +697,7 @@ input[type="checkbox"] {
label { label {
padding: 4px; padding: 4px;
color: var(--fg-light-color); color: var(--fg-light-color);
transition: all 0.2s ease-in-out;
} }
ul, ul,
@@ -805,6 +822,7 @@ ol li {
section { section {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
border-radius: 16px;
} }
.tab { .tab {
@@ -884,18 +902,19 @@ input[type="radio"]:checked + label + .tab {
padding: 0; padding: 0;
width: 100%; width: 100%;
background-color: var(--bg-color); background-color: var(--bg-color);
transition: all 0.2s ease-in-out;
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.45); box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.45);
} }
nav.primary-nav { nav.primary-nav {
flex-flow: row nowrap; flex-flow: row nowrap;
overflow: auto; overflow: auto;
justify-content: space-around; justify-content: space-between;
background-color: var(--bg-dark-color);
a { a {
background-color: transparent; background-color: transparent;
margin: 8px; margin: 8px;
flex: 1;
&.nuxt-link-exact-active { &.nuxt-link-exact-active {
background-color: transparent; background-color: transparent;

View File

@@ -121,12 +121,19 @@ export default {
let content = event.target.result; let content = event.target.result;
let collections = JSON.parse(content); let collections = JSON.parse(content);
if (collections[0]) { if (collections[0]) {
let [ name, folders, requests ] = Object.keys(collections[0]) let [name, folders, requests] = Object.keys(collections[0]);
if (name === 'name' && folders === 'folders' && requests === 'requests') { if (
name === "name" &&
folders === "folders" &&
requests === "requests"
) {
// Do nothing // Do nothing
} }
} else if (collections.info && collections.info.schema.includes('v2.1.0')) { } else if (
collections = this.parsePostmanCollection(collections) collections.info &&
collections.info.schema.includes("v2.1.0")
) {
collections = this.parsePostmanCollection(collections);
} else { } else {
return this.failedImport(); return this.failedImport();
} }
@@ -141,11 +148,18 @@ export default {
let content = event.target.result; let content = event.target.result;
let collections = JSON.parse(content); let collections = JSON.parse(content);
if (collections[0]) { if (collections[0]) {
let [ name, folders, requests ] = Object.keys(collections[0]) let [name, folders, requests] = Object.keys(collections[0]);
if (name === 'name' && folders === 'folders' && requests === 'requests') { if (
name === "name" &&
folders === "folders" &&
requests === "requests"
) {
// Do nothing // Do nothing
} }
} else if (collections.info && collections.info.schema.includes('v2.1.0')) { } else if (
collections.info &&
collections.info.schema.includes("v2.1.0")
) {
collections = this.parsePostmanCollection(collections); collections = this.parsePostmanCollection(collections);
} else { } else {
return this.failedImport(); return this.failedImport();
@@ -188,28 +202,38 @@ export default {
}); });
}, },
parsePostmanCollection(collection, folders = true) { parsePostmanCollection(collection, folders = true) {
let postwomanCollection = folders ? [{ let postwomanCollection = folders
"name": "", ? [
"folders": [], {
"requests": [] name: "",
}] folders: [],
requests: []
}
]
: { : {
"name": "", name: "",
"requests": [] requests: []
}; };
for(let collectionItem of collection.item) { for (let collectionItem of collection.item) {
if (collectionItem.request) { if (collectionItem.request) {
if (postwomanCollection[0]) { if (postwomanCollection[0]) {
postwomanCollection[0].name = collection.info ? collection.info.name : ""; postwomanCollection[0].name = collection.info
postwomanCollection[0].requests.push(this.parsePostmanRequest(collectionItem)); ? collection.info.name
: "";
postwomanCollection[0].requests.push(
this.parsePostmanRequest(collectionItem)
);
} else { } else {
postwomanCollection.name = collection.name ? collection.name postwomanCollection.name = collection.name ? collection.name : "";
: ""; postwomanCollection.requests.push(
postwomanCollection.requests.push(this.parsePostmanRequest(collectionItem)); this.parsePostmanRequest(collectionItem)
);
} }
} else if (collectionItem.item) { } else if (collectionItem.item) {
if (collectionItem.item[0]) { if (collectionItem.item[0]) {
postwomanCollection[0].folders.push(this.parsePostmanCollection(collectionItem, false)); postwomanCollection[0].folders.push(
this.parsePostmanCollection(collectionItem, false)
);
} }
} }
} }
@@ -217,46 +241,51 @@ export default {
}, },
parsePostmanRequest(requestObject) { parsePostmanRequest(requestObject) {
let pwRequest = { let pwRequest = {
"url": "", url: "",
"path": "", path: "",
"method": "", method: "",
"auth": "", auth: "",
"httpUser": "", httpUser: "",
"httpPassword": "", httpPassword: "",
"passwordFieldType": "password", passwordFieldType: "password",
"bearerToken": "", bearerToken: "",
"headers": [], headers: [],
"params": [], params: [],
"bodyParams": [], bodyParams: [],
"rawParams": "", rawParams: "",
"rawInput": false, rawInput: false,
"contentType": "", contentType: "",
"requestType": "", requestType: "",
"name": "", name: ""
}; };
pwRequest.name = requestObject.name; pwRequest.name = requestObject.name;
let requestObjectUrl = requestObject.request.url.raw.match(/^(.+:\/\/[^\/]+|{[^\/]+})(\/[^\?]+|).*$/); let requestObjectUrl = requestObject.request.url.raw.match(
/^(.+:\/\/[^\/]+|{[^\/]+})(\/[^\?]+|).*$/
);
pwRequest.url = requestObjectUrl[1]; pwRequest.url = requestObjectUrl[1];
pwRequest.path = requestObjectUrl[2] ? requestObjectUrl[2] : ""; pwRequest.path = requestObjectUrl[2] ? requestObjectUrl[2] : "";
pwRequest.method = requestObject.request.method; pwRequest.method = requestObject.request.method;
let itemAuth = requestObject.request.auth ? requestObject.request.auth let itemAuth = requestObject.request.auth
: ""; ? requestObject.request.auth
let authType = itemAuth ? itemAuth.type
: ""; : "";
let authType = itemAuth ? itemAuth.type : "";
if (authType === "basic") { if (authType === "basic") {
pwRequest.auth = "Basic Auth"; pwRequest.auth = "Basic Auth";
pwRequest.httpUser = itemAuth.basic[0].key === "username" pwRequest.httpUser =
? itemAuth.basic[0].value itemAuth.basic[0].key === "username"
: itemAuth.basic[1].value; ? itemAuth.basic[0].value
pwRequest.httpPassword = itemAuth.basic[0].key === "password" : itemAuth.basic[1].value;
? itemAuth.basic[0].value pwRequest.httpPassword =
: itemAuth.basic[1].value; itemAuth.basic[0].key === "password"
? itemAuth.basic[0].value
: itemAuth.basic[1].value;
} else if (authType === "oauth2") { } else if (authType === "oauth2") {
pwRequest.auth = "OAuth 2.0"; pwRequest.auth = "OAuth 2.0";
pwRequest.bearerToken = itemAuth.oauth2[0].key === "accessToken" pwRequest.bearerToken =
? itemAuth.oauth2[0].value itemAuth.oauth2[0].key === "accessToken"
: itemAuth.oauth2[1].value; ? itemAuth.oauth2[0].value
: itemAuth.oauth2[1].value;
} else if (authType === "bearer") { } else if (authType === "bearer") {
pwRequest.auth = "Bearer Token"; pwRequest.auth = "Bearer Token";
pwRequest.bearerToken = itemAuth.bearer[0].value; pwRequest.bearerToken = itemAuth.bearer[0].value;
@@ -280,7 +309,7 @@ export default {
if (requestObject.request.body.mode === "urlencoded") { if (requestObject.request.body.mode === "urlencoded") {
let params = requestObject.request.body.urlencoded; let params = requestObject.request.body.urlencoded;
pwRequest.bodyParams = params ? params : []; pwRequest.bodyParams = params ? params : [];
for(let param of pwRequest.bodyParams) { for (let param of pwRequest.bodyParams) {
delete param.type; delete param.type;
} }
} else if (requestObject.request.body.mode === "raw") { } else if (requestObject.request.body.mode === "raw") {

View File

@@ -0,0 +1,94 @@
<template>
<modal v-if="show" @close="hideModal">
<div slot="header">
<ul>
<li>
<div class="flex-wrap">
<h3 class="title">{{ $t("new_environment") }}</h3>
<div>
<button class="icon" @click="hideModal">
<i class="material-icons">close</i>
</button>
</div>
</div>
</li>
</ul>
</div>
<div slot="body">
<ul>
<li>
<input
type="text"
v-model="name"
:placeholder="$t('my_new_environment')"
@keyup.enter="addNewEnvironment"
/>
</li>
</ul>
</div>
<div slot="footer">
<div class="flex-wrap">
<span></span>
<span>
<button class="icon" @click="hideModal">
{{ $t("cancel") }}
</button>
<button class="icon primary" @click="addNewEnvironment">
{{ $t("save") }}
</button>
</span>
</div>
</div>
</modal>
</template>
<script>
import { fb } from "../../functions/fb";
export default {
props: {
show: Boolean
},
components: {
modal: () => import("../../components/modal")
},
data() {
return {
name: undefined
};
},
methods: {
syncEnvironments() {
if (fb.currentUser !== null) {
if (fb.currentSettings[1].value) {
fb.writeEnvironments(
JSON.parse(JSON.stringify(this.$store.state.postwoman.environments))
);
}
}
},
addNewEnvironment() {
if (!this.$data.name) {
this.$toast.info(this.$t("invalid_environment_name"));
return;
}
let newEnvironment = [
{
name: this.$data.name,
variables: []
}
];
this.$store.commit("postwoman/importAddEnvironments", {
environments: newEnvironment,
confirmation: "Environment added"
});
this.$emit("hide-modal");
this.syncEnvironments();
},
hideModal() {
this.$data.name = undefined;
this.$emit("hide-modal");
}
}
};
</script>

View File

@@ -0,0 +1,221 @@
<template>
<modal v-if="show" @close="hideModal">
<div slot="header">
<ul>
<li>
<div class="flex-wrap">
<h3 class="title">{{ $t("edit_environment") }}</h3>
<div>
<button class="icon" @click="hideModal">
<i class="material-icons">close</i>
</button>
</div>
</div>
</li>
</ul>
</div>
<div slot="body">
<ul>
<li>
<input
type="text"
v-model="name"
:placeholder="editingEnvironment.name"
@keyup.enter="saveEnvironment"
/>
</li>
</ul>
<ul>
<li>
<div class="flex-wrap">
<label for="variableList">{{ $t("env_variable_list") }}</label>
<div>
<button
class="icon"
@click="clearContent($event)"
v-tooltip.bottom="$t('clear')"
>
<i class="material-icons">clear_all</i>
</button>
</div>
</div>
<textarea
id="variableList"
readonly
v-textarea-auto-height="variableString"
v-model="variableString"
:placeholder="$t('add_one_variable')"
rows="1"
></textarea>
</li>
</ul>
<ul
v-for="(variable, index) in this.editingEnvCopy.variables"
:key="index"
>
<li>
<input
:placeholder="$t('parameter_count', { count: index + 1 })"
:name="'param' + index"
:value="variable.key"
@change="
$store.commit('postwoman/setVariableKey', {
index,
value: $event.target.value
})
"
autofocus
/>
</li>
<li>
<input
:placeholder="$t('value_count', { count: index + 1 })"
:name="'value' + index"
:value="
typeof variable.value === 'string'
? variable.value
: JSON.stringify(variable.value)
"
@change="
$store.commit('postwoman/setVariableValue', {
index,
value: $event.target.value
})
"
/>
</li>
<div>
<li>
<button
class="icon"
@click="removeEnvironmentVariable(index)"
v-tooltip.bottom="$t('delete')"
id="variable"
>
<i class="material-icons">delete</i>
</button>
</li>
</div>
</ul>
<ul>
<li>
<button class="icon" @click="addEnvironmentVariable">
<i class="material-icons">add</i>
<span>{{ $t("add_new") }}</span>
</button>
</li>
</ul>
</div>
<div slot="footer">
<div class="flex-wrap">
<span></span>
<span>
<button class="icon" @click="hideModal">
{{ $t("cancel") }}
</button>
<button class="icon primary" @click="saveEnvironment">
{{ $t("save") }}
</button>
</span>
</div>
</div>
</modal>
</template>
<script>
import textareaAutoHeight from "../../directives/textareaAutoHeight";
export default {
directives: {
textareaAutoHeight
},
props: {
show: Boolean,
editingEnvironment: Object,
editingEnvironmentIndex: Number
},
components: {
modal: () => import("../../components/modal")
},
data() {
return {
name: undefined
};
},
watch: {
editingEnvironment: function(update) {
this.name = this.$props.editingEnvironment && this.$props.editingEnvironment.name
? this.$props.editingEnvironment.name
: undefined
this.$store.commit(
"postwoman/setEditingEnvironment",
this.$props.editingEnvironment
);
}
},
computed: {
editingEnvCopy() {
return this.$store.state.postwoman.editingEnvironment;
},
variableString() {
const result = this.editingEnvCopy.variables;
return result === "" ? "" : JSON.stringify(result);
}
},
methods: {
clearContent(e) {
this.$store.commit("postwoman/removeVariables", []);
e.target.innerHTML = this.doneButton;
this.$toast.info(this.$t("cleared"), {
icon: "clear_all"
});
setTimeout(
() => (e.target.innerHTML = '<i class="material-icons">clear_all</i>'),
1000
);
},
addEnvironmentVariable() {
let value = { key: "", value: "" };
this.$store.commit("postwoman/addVariable", value);
},
removeEnvironmentVariable(index) {
let variableIndex = index;
const oldVariables = this.editingEnvCopy.variables.slice();
const newVariables = this.editingEnvCopy.variables.filter(
(variable, index) => variableIndex !== index
);
this.$store.commit("postwoman/removeVariable", newVariables);
this.$toast.error(this.$t("deleted"), {
icon: "delete",
action: {
text: this.$t("undo"),
onClick: (e, toastObject) => {
this.$store.commit("postwoman/removeVariable", oldVariables);
toastObject.remove();
}
}
});
},
saveEnvironment() {
if (!this.$data.name) {
this.$toast.info(this.$t("invalid_environment_name"));
return;
}
const environmentUpdated = {
...this.editingEnvCopy,
name: this.$data.name
};
this.$store.commit("postwoman/saveEnvironment", {
environment: environmentUpdated,
environmentIndex: this.$props.editingEnvironmentIndex
});
this.$emit("hide-modal");
},
hideModal() {
this.$data.name = undefined;
this.$emit("hide-modal");
}
}
};
</script>

View File

@@ -0,0 +1,65 @@
<template>
<div class="flex-wrap">
<div>
<button
class="icon"
@click="$emit('select-environment')"
v-tooltip="$t('use_environment')"
>
<i class="material-icons">insert_drive_file</i>
<span>{{ environment.name }}</span>
</button>
</div>
<v-popover>
<button class="tooltip-target icon" v-tooltip="$t('more')">
<i class="material-icons">more_vert</i>
</button>
<template slot="popover">
<div>
<button
class="icon"
@click="$emit('edit-environment')"
v-close-popover
>
<i class="material-icons">create</i>
<span>{{ $t("edit") }}</span>
</button>
</div>
<div>
<button class="icon" @click="removeEnvironment" v-close-popover>
<i class="material-icons">delete</i>
<span>{{ $t("delete") }}</span>
</button>
</div>
</template>
</v-popover>
</div>
</template>
<style scoped lang="scss">
ul {
display: flex;
flex-direction: column;
}
ul li {
display: flex;
padding-left: 16px;
border-left: 1px solid var(--brd-color);
}
</style>
<script>
export default {
props: {
environment: Object,
environmentIndex: Number
},
methods: {
removeEnvironment() {
if (!confirm("Are you sure you want to remove this environment?")) return;
this.$store.commit("postwoman/removeEnvironment", this.environmentIndex);
}
}
};
</script>

View File

@@ -0,0 +1,173 @@
<template>
<modal v-if="show" @close="hideModal">
<div slot="header">
<ul>
<li>
<div class="flex-wrap">
<h3 class="title">Import / Export Environment</h3>
<div>
<button class="icon" @click="hideModal">
<i class="material-icons">close</i>
</button>
</div>
</div>
<div class="flex-wrap">
<span
v-tooltip="{
content: !fb.currentUser
? $t('login_first')
: $t('replace_current')
}"
>
<button
:disabled="!fb.currentUser"
class="icon"
@click="syncEnvironments"
>
<i class="material-icons">folder_shared</i>
<span>{{ $t("import_from_sync") }}</span>
</button>
</span>
<button
class="icon"
@click="openDialogChooseFileToReplaceWith"
v-tooltip="$t('replace_current')"
>
<i class="material-icons">create_new_folder</i>
<span>{{ $t("replace_json") }}</span>
<input
type="file"
@change="replaceWithJSON"
style="display: none;"
ref="inputChooseFileToReplaceWith"
accept="application/json"
/>
</button>
<button
class="icon"
@click="openDialogChooseFileToImportFrom"
v-tooltip="$t('preserve_current')"
>
<i class="material-icons">folder_special</i>
<span>{{ $t("import_json") }}</span>
<input
type="file"
@change="importFromJSON"
style="display: none;"
ref="inputChooseFileToImportFrom"
accept="application/json"
/>
</button>
</div>
</li>
</ul>
</div>
<div slot="body">
<textarea v-model="environmentJson" rows="8"></textarea>
</div>
<div slot="footer">
<div class="flex-wrap">
<span></span>
<span>
<button class="icon" @click="hideModal">
{{ $t("cancel") }}
</button>
<button
class="icon primary"
@click="exportJSON"
v-tooltip="$t('download_file')"
>
{{ $t("export") }}
</button>
</span>
</div>
</div>
</modal>
</template>
<script>
import { fb } from "../../functions/fb";
export default {
data() {
return {
fb
};
},
props: {
show: Boolean
},
components: {
modal: () => import("../../components/modal")
},
computed: {
environmentJson() {
return JSON.stringify(this.$store.state.postwoman.environments, null, 2);
}
},
methods: {
hideModal() {
this.$emit("hide-modal");
},
openDialogChooseFileToReplaceWith() {
this.$refs.inputChooseFileToReplaceWith.click();
},
openDialogChooseFileToImportFrom() {
this.$refs.inputChooseFileToImportFrom.click();
},
replaceWithJSON() {
let reader = new FileReader();
reader.onload = event => {
let content = event.target.result;
let environments = JSON.parse(content);
this.$store.commit("postwoman/replaceEnvironments", environments);
};
reader.readAsText(this.$refs.inputChooseFileToReplaceWith.files[0]);
this.fileImported();
},
importFromJSON() {
let reader = new FileReader();
reader.onload = event => {
let content = event.target.result;
let environments = JSON.parse(content);
let confirmation = this.$t("file_imported")
this.$store.commit("postwoman/importAddEnvironments", {
environments,
confirmation
});
};
reader.readAsText(this.$refs.inputChooseFileToImportFrom.files[0]);
},
exportJSON() {
let text = this.environmentJson;
text = text.replace(/\n/g, "\r\n");
let blob = new Blob([text], {
type: "text/json"
});
let anchor = document.createElement("a");
anchor.download = "postwoman-environment.json";
anchor.href = window.URL.createObjectURL(blob);
anchor.target = "_blank";
anchor.style.display = "none";
document.body.appendChild(anchor);
anchor.click();
document.body.removeChild(anchor);
this.$toast.success(this.$t("download_started"), {
icon: "done"
});
},
syncEnvironments() {
this.$store.commit(
"postwoman/replaceEnvironments",
fb.currentEnvironments
);
this.fileImported();
},
fileImported() {
this.$toast.info(this.$t("file_imported"), {
icon: "folder_shared"
});
}
}
};
</script>

View File

@@ -0,0 +1,147 @@
<template>
<pw-section
class="green"
icon="history"
:label="$t('environment')"
ref="environment"
>
<addEnvironment :show="showModalAdd" @hide-modal="displayModalAdd(false)" />
<editEnvironment
:show="showModalEdit"
:editingEnvironment="editingEnvironment"
:editingEnvironmentIndex="editingEnvironmentIndex"
@hide-modal="displayModalEdit(false)"
/>
<importExportEnvironment
:show="showModalImportExport"
@hide-modal="displayModalImportExport(false)"
/>
<div class="flex-wrap">
<div>
<button class="icon" @click="displayModalAdd(true)">
<i class="material-icons">add</i>
<span>{{ $t("new") }}</span>
</button>
</div>
<div>
<button class="icon" @click="displayModalImportExport(true)">
{{ $t("import_export") }}
</button>
</div>
</div>
<p v-if="environments.length === 0" class="info">
Create new environment
</p>
<virtual-list
class="virtual-list"
:class="{ filled: environments.length }"
:size="152"
:remain="Math.min(5, environments.length)"
>
<ul>
<li
v-for="(environment, index) in environments"
:key="environment.name"
>
<environment
:environmentIndex="index"
:environment="environment"
@edit-environment="editEnvironment(environment, index)"
@select-environment="$emit('use-environment', environment)"
/>
</li>
<li v-if="environments.length === 0">
<label>Environments are empty</label>
</li>
</ul>
</virtual-list>
</pw-section>
</template>
<style scoped lang="scss">
.virtual-list {
max-height: calc(100vh - 276px);
}
ul {
display: flex;
flex-direction: column;
}
</style>
<script>
import environment from "./environment";
import { fb } from "../../functions/fb";
const updateOnLocalStorage = (propertyName, property) =>
window.localStorage.setItem(propertyName, JSON.stringify(property));
export default {
components: {
environment,
"pw-section": () => import("../section"),
addEnvironment: () => import("./addEnvironment"),
editEnvironment: () => import("./editEnvironment"),
importExportEnvironment: () => import("./importExportEnvironment"),
VirtualList: () => import("vue-virtual-scroll-list")
},
data() {
return {
showModalImportExport: false,
showModalAdd: false,
showModalEdit: false,
editingEnvironment: undefined,
editingEnvironmentIndex: undefined
};
},
computed: {
environments() {
return this.$store.state.postwoman.environments;
}
},
async mounted() {
this._keyListener = function(e) {
if (e.key === "Escape") {
e.preventDefault();
this.showModalImportExport = false;
}
};
document.addEventListener("keydown", this._keyListener.bind(this));
},
methods: {
displayModalAdd(shouldDisplay) {
this.showModalAdd = shouldDisplay;
},
displayModalEdit(shouldDisplay) {
this.showModalEdit = shouldDisplay;
if (!shouldDisplay) this.resetSelectedData();
},
displayModalImportExport(shouldDisplay) {
this.showModalImportExport = shouldDisplay;
},
editEnvironment(environment, environmentIndex) {
this.$data.editingEnvironment = environment;
this.$data.editingEnvironmentIndex = environmentIndex;
this.displayModalEdit(true);
this.syncEnvironments;
},
resetSelectedData() {
this.$data.editingEnvironment = undefined;
this.$data.editingEnvironmentIndex = undefined;
},
syncEnvironments() {
if (fb.currentUser !== null) {
if (fb.currentSettings[1].value) {
fb.writeEnvironments(
JSON.parse(JSON.stringify(this.$store.state.postwoman.environments))
);
}
}
}
},
beforeDestroy() {
document.removeEventListener("keydown", this._keyListener);
}
};
</script>

View File

@@ -57,9 +57,9 @@ export default {
firebase firebase
.auth() .auth()
.signInWithPopup(provider) .signInWithPopup(provider)
.then(res => { .then(({ additionalUserInfo }) => {
if (res.additionalUserInfo.isNewUser) { if (additionalUserInfo.isNewUser) {
this.$toast.info(this.$t("turn_on") + " " + this.$t("sync"), { this.$toast.info(`${this.$t("turn_on")} ${this.$t("sync")}`, {
icon: "sync", icon: "sync",
duration: null, duration: null,
closeOnSwipe: false, closeOnSwipe: false,
@@ -86,9 +86,9 @@ export default {
firebase firebase
.auth() .auth()
.signInWithPopup(provider) .signInWithPopup(provider)
.then(res => { .then(({ additionalUserInfo }) => {
if (res.additionalUserInfo.isNewUser) { if (additionalUserInfo.isNewUser) {
this.$toast.info(this.$t("turn_on") + " " + this.$t("sync"), { this.$toast.info(`${this.$t("turn_on")} ${this.$t("sync")}`, {
icon: "sync", icon: "sync",
duration: null, duration: null,
closeOnSwipe: false, closeOnSwipe: false,

View File

@@ -7,7 +7,9 @@ const DEFAULT_THEME = "twilight";
import ace from "ace-builds"; import ace from "ace-builds";
import * as gql from "graphql"; import * as gql from "graphql";
import { getAutocompleteSuggestions } from "graphql-language-service-interface";
import "ace-builds/webpack-resolver"; import "ace-builds/webpack-resolver";
import "ace-builds/src-noconflict/ext-language_tools";
import debounce from "../../functions/utils/debounce"; import debounce from "../../functions/utils/debounce";
export default { export default {
@@ -46,10 +48,10 @@ export default {
} }
}, },
theme() { theme() {
this.editor.setTheme("ace/theme/" + this.defineTheme()); this.editor.setTheme(`ace/theme/${this.defineTheme()}`);
}, },
lang(value) { lang(value) {
this.editor.getSession().setMode("ace/mode/" + value); this.editor.getSession().setMode(`ace/mode/${value}`);
}, },
options(value) { options(value) {
this.editor.setOptions(value); this.editor.setOptions(value);
@@ -57,12 +59,48 @@ export default {
}, },
mounted() { mounted() {
let langTools = ace.require("ace/ext/language_tools");
const editor = ace.edit(this.$refs.editor, { const editor = ace.edit(this.$refs.editor, {
theme: "ace/theme/" + this.defineTheme(), theme: `ace/theme/${this.defineTheme()}`,
mode: "ace/mode/" + this.lang, mode: `ace/mode/${this.lang}`,
enableBasicAutocompletion: true,
enableLiveAutocompletion: true,
...this.options ...this.options
}); });
const completer = {
getCompletions: (
editor,
_session,
{ row, column },
_prefix,
callback
) => {
if (this.validationSchema) {
const completions = getAutocompleteSuggestions(
this.validationSchema,
editor.getValue(),
{ line: row, character: column }
);
callback(
null,
completions.map(({ label, detail }) => ({
name: label,
value: label,
score: 1.0,
meta: detail
}))
);
} else {
callback(null, []);
}
}
};
langTools.setCompleters([completer]);
if (this.value) editor.setValue(this.value, 1); if (this.value) editor.setValue(this.value, 1);
this.editor = editor; this.editor = editor;
@@ -101,14 +139,14 @@ export default {
if (this.validationSchema) { if (this.validationSchema) {
this.editor.session.setAnnotations( this.editor.session.setAnnotations(
gql.validate(this.validationSchema, doc).map(err => { gql
return { .validate(this.validationSchema, doc)
row: err.locations[0].line - 1, .map(({ locations, message }) => ({
column: err.locations[0].column - 1, row: locations[0].line - 1,
text: err.message, column: locations[0].column - 1,
text: message,
type: "error" type: "error"
}; }))
})
); );
} }
} catch (e) { } catch (e) {

View File

@@ -20,6 +20,7 @@
border-radius: 100%; border-radius: 100%;
border: 3px solid var(--bg-dark-color); border: 3px solid var(--bg-dark-color);
cursor: pointer; cursor: pointer;
transition: all 0.2s ease-in-out;
&.fg { &.fg {
color: var(--act-color); color: var(--act-color);

11
functions/editorutils.js Normal file
View File

@@ -0,0 +1,11 @@
const mimeToMode = {
"text/plain": "plain_text",
"text/html": "html",
"application/xml": "xml",
"application/hal+json": "json",
"application/json": "json"
}
export function getEditorLangForMimeType(mimeType) {
return mimeToMode[mimeType] || "plain_text";
}

View File

@@ -26,6 +26,7 @@ export const fb = {
currentSettings: [], currentSettings: [],
currentHistory: [], currentHistory: [],
currentCollections: [], currentCollections: [],
currentEnvironments: [],
writeFeeds: async (message, label) => { writeFeeds: async (message, label) => {
const dt = { const dt = {
createdOn: new Date(), createdOn: new Date(),
@@ -112,6 +113,21 @@ export const fb = {
.doc("sync") .doc("sync")
.set(cl) .set(cl)
.catch(e => console.error("error updating", cl, e)); .catch(e => console.error("error updating", cl, e));
},
writeEnvironments: async environment => {
const ev = {
updatedOn: new Date(),
author: fb.currentUser.uid,
author_name: fb.currentUser.displayName,
author_image: fb.currentUser.photoURL,
environment: environment
};
usersCollection
.doc(fb.currentUser.uid)
.collection("environments")
.doc("sync")
.set(ev)
.catch(e => console.error("error updating", ev, e));
} }
}; };
@@ -186,6 +202,19 @@ firebase.auth().onAuthStateChanged(user => {
}); });
fb.currentCollections = collections[0].collection; fb.currentCollections = collections[0].collection;
}); });
usersCollection
.doc(fb.currentUser.uid)
.collection("environments")
.onSnapshot(environmentsRef => {
const environments = [];
environmentsRef.forEach(doc => {
const environment = doc.data();
environment.id = doc.id;
environments.push(environment);
});
fb.currentEnvironments = environments[0].environment;
});
} else { } else {
fb.currentUser = null; fb.currentUser = null;
} }

View File

@@ -121,4 +121,4 @@ export const commonHeaders = [
"X-Requested-With", "X-Requested-With",
"X-Robots-Tag", "X-Robots-Tag",
"X-UA-Compatible" "X-UA-Compatible"
] ];

View File

@@ -1,18 +1,28 @@
import AxiosStrategy from "./strategies/AxiosStrategy"; import AxiosStrategy from "./strategies/AxiosStrategy";
import ExtensionStrategy, {
hasExtensionInstalled
} from "./strategies/ExtensionStrategy";
import FirefoxStrategy from "./strategies/FirefoxStrategy"; import FirefoxStrategy from "./strategies/FirefoxStrategy";
import ChromeStrategy, { hasChromeExtensionInstalled } from "./strategies/ChromeStrategy"; import ChromeStrategy, {
hasChromeExtensionInstalled
} from "./strategies/ChromeStrategy";
const isExtensionsAllowed = ({ state }) => { const isExtensionsAllowed = ({ state }) =>
return typeof state.postwoman.settings.EXTENSIONS_ENABLED === 'undefined' typeof state.postwoman.settings.EXTENSIONS_ENABLED === "undefined" ||
|| state.postwoman.settings.EXTENSIONS_ENABLED; state.postwoman.settings.EXTENSIONS_ENABLED;
}
const runAppropriateStrategy = (req, store) => { const runAppropriateStrategy = (req, store) => {
if (isExtensionsAllowed(store)) { if (isExtensionsAllowed(store)) {
if (hasExtensionInstalled()) {
return ExtensionStrategy(req, store);
}
// The following strategies are deprecated and kept to support older version of the extensions
// Chrome Provides a chrome object for scripts to access // Chrome Provides a chrome object for scripts to access
// Check its availability to say whether you are in Google Chrome // Check its availability to say whether you are in Google Chrome
if (window.chrome && hasChromeExtensionInstalled()) { if (window.chrome && hasChromeExtensionInstalled()) {
return ChromeStrategy(req, store); return ChromeStrategy(req, store);
} }
// The firefox plugin injects a function to send requests through it // The firefox plugin injects a function to send requests through it
// If that is available, then we can use the FirefoxStrategy // If that is available, then we can use the FirefoxStrategy
@@ -22,10 +32,11 @@ const runAppropriateStrategy = (req, store) => {
} }
return AxiosStrategy(req, store); return AxiosStrategy(req, store);
} };
const sendNetworkRequest = (req, store) => const sendNetworkRequest = (req, store) =>
runAppropriateStrategy(req, store) runAppropriateStrategy(req, store).finally(() =>
.finally(() => window.$nuxt.$loading.finish()); window.$nuxt.$loading.finish()
);
export { sendNetworkRequest }; export { sendNetworkRequest };

View File

@@ -3,47 +3,54 @@ const EXTENSION_ID = "amknoiejhlmhancpahfcfcfhllgkpbld";
// Check if the Chrome Extension is present // Check if the Chrome Extension is present
// The Chrome extension injects an empty span to help detection. // The Chrome extension injects an empty span to help detection.
// Also check for the presence of window.chrome object to confirm smooth operations // Also check for the presence of window.chrome object to confirm smooth operations
export const hasChromeExtensionInstalled = () => { export const hasChromeExtensionInstalled = () =>
return document.getElementById("chromePWExtensionDetect") !== null; document.getElementById("chromePWExtensionDetect") !== null;
}
const chromeWithoutProxy = (req, _store) => new Promise((resolve, reject) => { const chromeWithoutProxy = (req, _store) =>
chrome.runtime.sendMessage( new Promise((resolve, reject) => {
EXTENSION_ID, { chrome.runtime.sendMessage(
messageType: "send-req", EXTENSION_ID,
data: { {
config: req messageType: "send-req",
} data: {
}, (message) => { config: req
if (message.data.error) { }
reject(message.data.error); },
} else { ({ data }) => {
resolve(message.data.response); if (data.error) {
} reject(data.error);
} } else {
); resolve(data.response);
});
const chromeWithProxy = (req, { state }) => new Promise((resolve, reject) => {
chrome.runtime.sendMessage(
EXTENSION_ID, {
messageType: "send-req",
data: {
config: {
method: "post",
url: state.postwoman.settings.PROXY_URL || "https://postwoman.apollotv.xyz/",
data: req
} }
} }
}, (message) => { );
if (message.data.error) { });
reject(error);
} else { const chromeWithProxy = (req, { state }) =>
resolve(message.data.response.data); new Promise((resolve, reject) => {
chrome.runtime.sendMessage(
EXTENSION_ID,
{
messageType: "send-req",
data: {
config: {
method: "post",
url:
state.postwoman.settings.PROXY_URL ||
"https://postwoman.apollotv.xyz/",
data: req
}
}
},
({ data }) => {
if (data.error) {
reject(error);
} else {
resolve(data.response.data);
}
} }
} );
) });
});
const chromeStrategy = (req, store) => { const chromeStrategy = (req, store) => {
if (store.state.postwoman.settings.PROXY_ENABLED) { if (store.state.postwoman.settings.PROXY_ENABLED) {
@@ -51,6 +58,6 @@ const chromeStrategy = (req, store) => {
} else { } else {
return chromeWithoutProxy(req, store); return chromeWithoutProxy(req, store);
} }
} };
export default chromeStrategy; export default chromeStrategy;

View File

@@ -0,0 +1,26 @@
export const hasExtensionInstalled = () =>
typeof window.__POSTWOMAN_EXTENSION_HOOK__ !== "undefined";
const extensionWithProxy = async (req, { state }) => {
const { data } = await window.__POSTWOMAN_EXTENSION_HOOK__.sendRequest({
method: "post",
url:
state.postwoman.settings.PROXY_URL || "https://postwoman.apollotv.xyz/",
data: req
});
return data;
};
const extensionWithoutProxy = async (req, _store) => {
const res = await window.__POSTWOMAN_EXTENSION_HOOK__.sendRequest(req);
return res;
};
const extensionStrategy = (req, store) => {
if (store.state.postwoman.settings.PROXY_ENABLED) {
return extensionWithProxy(req, store);
}
return extensionWithoutProxy(req, store);
};
export default extensionStrategy;

View File

@@ -45,6 +45,14 @@ export default {
preview_html: "Preview HTML", preview_html: "Preview HTML",
history: "History", history: "History",
collections: "Collections", collections: "Collections",
environment: "Environment",
new_environment: "New Environment",
my_new_environment: "My New Environment",
edit_environment: "Edit Environment",
env_variable_list: "Variable List",
invalid_environment_name: "Please provide a valid name for the environment",
use_environment: "Use Environment",
add_one_variable: "(add at least one variable)",
import_curl: "Import cURL", import_curl: "Import cURL",
import: "Import", import: "Import",
generate_code: "Generate code", generate_code: "Generate code",
@@ -248,7 +256,8 @@ export default {
enter_curl: "Enter cURL", enter_curl: "Enter cURL",
empty: "Empty", empty: "Empty",
extensions: "Extensions", extensions: "Extensions",
extensions_use_toggle: "Use the browser extension to send requests (if present)", extensions_use_toggle:
"Use the browser extension to send requests (if present)",
extensions_info1: "Browser extension that simplifies access to Postwoman", extensions_info1: "Browser extension that simplifies access to Postwoman",
extensions_info2: "Get Postwoman browser extension!", extensions_info2: "Get Postwoman browser extension!",
installed: "Installed", installed: "Installed",
@@ -259,6 +268,7 @@ export default {
sync: "Sync", sync: "Sync",
syncHistory: "History", syncHistory: "History",
syncCollections: "Collections", syncCollections: "Collections",
syncEnvironments: "Environments",
turn_on: "Turn on", turn_on: "Turn on",
login_first: "Login first", login_first: "Login first",
paste_a_note: "Paste a note", paste_a_note: "Paste a note",

View File

@@ -247,6 +247,11 @@
<i class="material-icons">brush</i> <i class="material-icons">brush</i>
</a> </a>
</li> </li>
<li>
<a href="#extensions" v-tooltip.right="$t('extensions')">
<i class="material-icons">extensions</i>
</a>
</li>
<li> <li>
<a href="#proxy" v-tooltip.right="$t('proxy')"> <a href="#proxy" v-tooltip.right="$t('proxy')">
<i class="material-icons">public</i> <i class="material-icons">public</i>
@@ -408,7 +413,7 @@
<div class="flex-wrap"> <div class="flex-wrap">
<span v-if="version.name" class="mono"> <span v-if="version.name" class="mono">
<a <a
class="link" class="footer-link"
:href=" :href="
'https://github.com/liyasthomas/postwoman/releases/tag/' + 'https://github.com/liyasthomas/postwoman/releases/tag/' +
version.name version.name
@@ -420,7 +425,7 @@
{{ version.name }} {{ version.name }}
</a> </a>
<a <a
class="link hide-on-small-screen" class="footer-link hide-on-small-screen"
href="https://www.netlify.com" href="https://www.netlify.com"
target="_blank" target="_blank"
rel="noopener" rel="noopener"
@@ -660,7 +665,7 @@
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
.link { .footer-link {
margin: 8px 16px; margin: 8px 16px;
} }
</style> </style>
@@ -668,7 +673,7 @@
<script> <script>
import intializePwa from "../assets/js/pwa"; import intializePwa from "../assets/js/pwa";
import * as version from "../.postwoman/version.json"; import * as version from "../.postwoman/version.json";
import { hasChromeExtensionInstalled } from "../functions/strategies/ChromeStrategy"; import { hasExtensionInstalled } from "../functions/strategies/ExtensionStrategy";
import firebase from "firebase/app"; import firebase from "firebase/app";
import { fb } from "../functions/fb"; import { fb } from "../functions/fb";
@@ -715,7 +720,7 @@ export default {
.then(() => {}) .then(() => {})
.catch(console.error); .catch(console.error);
} else { } else {
// fallback // fallback
} }
} }
}, },
@@ -730,8 +735,7 @@ export default {
showExtensions: false, showExtensions: false,
showShortcuts: false, showShortcuts: false,
showSupport: false, showSupport: false,
firefoxExtInstalled: window.firefoxExtSendRequest, extensionInstalled: hasExtensionInstalled(),
chromeExtInstalled: window.chrome && hasChromeExtensionInstalled(),
fb, fb,
navigatorShare: navigator.share navigatorShare: navigator.share
}; };
@@ -794,8 +798,7 @@ export default {
let showExtensionsToast = let showExtensionsToast =
localStorage.getItem("showExtensionsToast") === "yes"; localStorage.getItem("showExtensionsToast") === "yes";
if ( if (
!this.firefoxExtInstalled && !this.extensionInstalled &&
!this.chromeExtInstalled &&
!showExtensionsToast !showExtensionsToast
) { ) {
setTimeout(() => { setTimeout(() => {

136
package-lock.json generated
View File

@@ -991,9 +991,9 @@
} }
}, },
"@firebase/firestore": { "@firebase/firestore": {
"version": "1.10.2", "version": "1.11.1",
"resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-1.10.2.tgz", "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-1.11.1.tgz",
"integrity": "sha512-Ay9V7eLYNEt12STCfmUxtyu4IBWIgOONzxoRUnkK1nmNbvket7XhSCfij4P4pi3qx4kdpp+hzjUl6ndVbh7y5Q==", "integrity": "sha512-bzGBY1JgzVJs9rdjWNl9ZnJxkqt2ty8oBIplHYCkpa+lp5RNpyvwmuZ6D6vFW67f/2+kEN8Wci82KMIvnoBVtg==",
"requires": { "requires": {
"@firebase/component": "0.1.5", "@firebase/component": "0.1.5",
"@firebase/firestore-types": "1.9.1", "@firebase/firestore-types": "1.9.1",
@@ -1011,9 +1011,9 @@
"integrity": "sha512-w3pT+RMQOORS8Tvf6wCaW8sq8hklPS4FkWSGCyo/gIbATP7pG8rvQDihN1x6D3if1jILWiZ/uPyl0eazm+MGzw==" "integrity": "sha512-w3pT+RMQOORS8Tvf6wCaW8sq8hklPS4FkWSGCyo/gIbATP7pG8rvQDihN1x6D3if1jILWiZ/uPyl0eazm+MGzw=="
}, },
"@firebase/functions": { "@firebase/functions": {
"version": "0.4.32", "version": "0.4.34",
"resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.4.32.tgz", "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.4.34.tgz",
"integrity": "sha512-0v8YkEElryo7Apx1S+eTUBR/yz/Gatj064hy37AWNN9n5oUjRyrkwl40/YywFPw15AZPB8ItoEx+wJBnyFjgUw==", "integrity": "sha512-TbgNlYLJudpugjEPz6JNcYWOBPXuq8DSBvztxGnP/bxEE4wqR9MAjADwJ0QfJYM8llbi/G9Vp9XbVKj+Jdszpg==",
"requires": { "requires": {
"@firebase/component": "0.1.5", "@firebase/component": "0.1.5",
"@firebase/functions-types": "0.3.14", "@firebase/functions-types": "0.3.14",
@@ -1050,9 +1050,9 @@
"integrity": "sha512-T7I/0+IQrlPAm/uUw6xeyJH5Msi8P6in/0LUtz2XQn2+LVBqyatlr+Nod9AldDCZehwLySEAFhXlqhb3BrI5GA==" "integrity": "sha512-T7I/0+IQrlPAm/uUw6xeyJH5Msi8P6in/0LUtz2XQn2+LVBqyatlr+Nod9AldDCZehwLySEAFhXlqhb3BrI5GA=="
}, },
"@firebase/messaging": { "@firebase/messaging": {
"version": "0.6.4", "version": "0.6.6",
"resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.6.4.tgz", "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.6.6.tgz",
"integrity": "sha512-QKoK5gskZ9cECOa5nnp2oXoP3vmVOyzrEj3x0vHu1HsZhCg6EgRiJ9yO4LeTwoVcwFKDMkuNNPJZ8USOy2fdtw==", "integrity": "sha512-acCZ9gXKYecLdPAoQv9MvaMKO0a7C636AxRHW+vHkJ+rId5AgoZqIqn99y3tHv5LAkm+BrGqOva7SOQBhEWkiA==",
"requires": { "requires": {
"@firebase/component": "0.1.5", "@firebase/component": "0.1.5",
"@firebase/installations": "0.4.2", "@firebase/installations": "0.4.2",
@@ -3822,6 +3822,27 @@
"sha.js": "^2.4.8" "sha.js": "^2.4.8"
} }
}, },
"cross-fetch": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-2.2.2.tgz",
"integrity": "sha1-pH/09/xxLauo9qaVoRyUhEDUVyM=",
"requires": {
"node-fetch": "2.1.2",
"whatwg-fetch": "2.0.4"
},
"dependencies": {
"node-fetch": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz",
"integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U="
},
"whatwg-fetch": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz",
"integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng=="
}
}
},
"cross-spawn": { "cross-spawn": {
"version": "6.0.5", "version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
@@ -5194,19 +5215,19 @@
} }
}, },
"firebase": { "firebase": {
"version": "7.8.2", "version": "7.9.1",
"resolved": "https://registry.npmjs.org/firebase/-/firebase-7.8.2.tgz", "resolved": "https://registry.npmjs.org/firebase/-/firebase-7.9.1.tgz",
"integrity": "sha512-qB/YopC6PVYTe2Q8hSwDD9CLdQHiMN1HUj/rxFxoICJR1VGkHP2KUvx2gv990V7CwzXIruLWoz9MwCOHFj9D0w==", "integrity": "sha512-yF80JPxLDXypBxhOeJDKULeP1MwZ/+Clovx3JZOvzH9yoRhIZZBx17/vkQFb7d0b+ICqwrKIofgpPzPef+CMpw==",
"requires": { "requires": {
"@firebase/analytics": "0.2.13", "@firebase/analytics": "0.2.13",
"@firebase/app": "0.5.4", "@firebase/app": "0.5.4",
"@firebase/app-types": "0.5.1", "@firebase/app-types": "0.5.1",
"@firebase/auth": "0.13.5", "@firebase/auth": "0.13.5",
"@firebase/database": "0.5.21", "@firebase/database": "0.5.21",
"@firebase/firestore": "1.10.2", "@firebase/firestore": "1.11.1",
"@firebase/functions": "0.4.32", "@firebase/functions": "0.4.34",
"@firebase/installations": "0.4.2", "@firebase/installations": "0.4.2",
"@firebase/messaging": "0.6.4", "@firebase/messaging": "0.6.6",
"@firebase/performance": "0.2.32", "@firebase/performance": "0.2.32",
"@firebase/polyfill": "0.3.31", "@firebase/polyfill": "0.3.31",
"@firebase/remote-config": "0.1.13", "@firebase/remote-config": "0.1.13",
@@ -5589,6 +5610,79 @@
"iterall": "^1.2.2" "iterall": "^1.2.2"
} }
}, },
"graphql-config": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/graphql-config/-/graphql-config-2.2.1.tgz",
"integrity": "sha512-U8+1IAhw9m6WkZRRcyj8ZarK96R6lQBQ0an4lp76Ps9FyhOXENC5YQOxOFGm5CxPrX2rD0g3Je4zG5xdNJjwzQ==",
"requires": {
"graphql-import": "^0.7.1",
"graphql-request": "^1.5.0",
"js-yaml": "^3.10.0",
"lodash": "^4.17.4",
"minimatch": "^3.0.4"
}
},
"graphql-import": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/graphql-import/-/graphql-import-0.7.1.tgz",
"integrity": "sha512-YpwpaPjRUVlw2SN3OPljpWbVRWAhMAyfSba5U47qGMOSsPLi2gYeJtngGpymjm9nk57RFWEpjqwh4+dpYuFAPw==",
"requires": {
"lodash": "^4.17.4",
"resolve-from": "^4.0.0"
},
"dependencies": {
"resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="
}
}
},
"graphql-language-service-interface": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/graphql-language-service-interface/-/graphql-language-service-interface-2.3.3.tgz",
"integrity": "sha512-SMUbbiHbD19ffyDrucR+vwyaKYhDcTgbBFDJu9Z4TBa5XaksmyiurB3f+pWlIkuFvogBvW3JDiiJJlUW7awivg==",
"requires": {
"graphql-config": "2.2.1",
"graphql-language-service-parser": "^1.5.2",
"graphql-language-service-types": "^1.5.2",
"graphql-language-service-utils": "^2.3.3"
}
},
"graphql-language-service-parser": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/graphql-language-service-parser/-/graphql-language-service-parser-1.5.2.tgz",
"integrity": "sha512-kModfvwX5XiT+tYRhh8d6X+rb5Zq9zFQVdcoVlQJvoIW7U6SkxUAeO5Ei9OI3KOMH5r8wyfmXflBZ+xUbJySJw==",
"requires": {
"graphql-config": "2.2.1",
"graphql-language-service-types": "^1.5.2"
}
},
"graphql-language-service-types": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/graphql-language-service-types/-/graphql-language-service-types-1.5.2.tgz",
"integrity": "sha512-WOFHBZX1K41svohPTmhOcKg+zz27d6ULFuZ8mzkiJ9nIpGKueAPyh7/xR0VZNBUAfDzTCbE6wQZxsPl5Kvd7IA==",
"requires": {
"graphql-config": "2.2.1"
}
},
"graphql-language-service-utils": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/graphql-language-service-utils/-/graphql-language-service-utils-2.3.3.tgz",
"integrity": "sha512-uHLdIbQpKkE1V2WA12DRMXrUZpPD3ZKPOuH3MHlNg+j9AEe1y83chA4yP5DQqR+ARdMpefz4FJHvEjQr9alXYw==",
"requires": {
"graphql-config": "2.2.1",
"graphql-language-service-types": "^1.5.2"
}
},
"graphql-request": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-1.8.2.tgz",
"integrity": "sha512-dDX2M+VMsxXFCmUX0Vo0TopIZIX4ggzOtiCsThgtrKR4niiaagsGTDIHj3fsOMFETpa064vzovI+4YV4QnMbcg==",
"requires": {
"cross-fetch": "2.2.2"
}
},
"grpc": { "grpc": {
"version": "1.24.2", "version": "1.24.2",
"resolved": "https://registry.npmjs.org/grpc/-/grpc-1.24.2.tgz", "resolved": "https://registry.npmjs.org/grpc/-/grpc-1.24.2.tgz",
@@ -9676,9 +9770,9 @@
}, },
"dependencies": { "dependencies": {
"@types/node": { "@types/node": {
"version": "10.17.15", "version": "10.17.16",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.15.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.16.tgz",
"integrity": "sha512-daFGV9GSs6USfPgxceDA8nlSe48XrVCJfDeYm7eokxq/ye7iuOH87hKXgMtEAVLFapkczbZsx868PMDT1Y0a6A==" "integrity": "sha512-A4283YSA1OmnIivcpy/4nN86YlnKRiQp8PYwI2KdPCONEBN093QTb0gCtERtkLyVNGKKIGazTZ2nAmVzQU51zA=="
} }
} }
}, },
@@ -12087,9 +12181,9 @@
"integrity": "sha512-GVbwInwnqkVxQ4GU/XYeQt1e0dAXL8sF5Hr1H/coCBbYUan5xP0G2mEz/HRDf1lt73rFQAN/bJcLTOKkqiM6tg==" "integrity": "sha512-GVbwInwnqkVxQ4GU/XYeQt1e0dAXL8sF5Hr1H/coCBbYUan5xP0G2mEz/HRDf1lt73rFQAN/bJcLTOKkqiM6tg=="
}, },
"vue-virtual-scroll-list": { "vue-virtual-scroll-list": {
"version": "1.4.5", "version": "1.4.6",
"resolved": "https://registry.npmjs.org/vue-virtual-scroll-list/-/vue-virtual-scroll-list-1.4.5.tgz", "resolved": "https://registry.npmjs.org/vue-virtual-scroll-list/-/vue-virtual-scroll-list-1.4.6.tgz",
"integrity": "sha512-9Rdq5acfwHcOmtIJC9LeLdfaXnXuJW6DwyGxXEgIT3aMyXbluP4eEMnKC3uNQ/kiZ0Eno7G95xYfWvopEMQpmA==" "integrity": "sha512-YVPVy+aNDgTq151ONOR9jA/X0BGqcXXyX3E8eyAUvEWDNy2cRScqHA9tUqS+FPszSYEY+Bgxto9Rkd99AN5xsQ=="
}, },
"vuefire": { "vuefire": {
"version": "2.2.1", "version": "2.2.1",

View File

@@ -26,12 +26,13 @@
"@nuxtjs/sitemap": "^2.0.1", "@nuxtjs/sitemap": "^2.0.1",
"@nuxtjs/toast": "^3.3.0", "@nuxtjs/toast": "^3.3.0",
"ace-builds": "^1.4.8", "ace-builds": "^1.4.8",
"firebase": "^7.8.2", "firebase": "^7.9.1",
"graphql": "^14.6.0", "graphql": "^14.6.0",
"graphql-language-service-interface": "^2.3.3",
"nuxt": "^2.11.0", "nuxt": "^2.11.0",
"nuxt-i18n": "^6.5.0", "nuxt-i18n": "^6.5.0",
"v-tooltip": "^2.0.3", "v-tooltip": "^2.0.3",
"vue-virtual-scroll-list": "^1.4.5", "vue-virtual-scroll-list": "^1.4.6",
"vuefire": "^2.2.1", "vuefire": "^2.2.1",
"vuejs-auto-complete": "^0.9.0", "vuejs-auto-complete": "^0.9.0",
"vuex-persist": "^2.2.0", "vuex-persist": "^2.2.0",

View File

@@ -375,7 +375,7 @@
<label for="rawBody">{{ $t("raw_request_body") }}</label> <label for="rawBody">{{ $t("raw_request_body") }}</label>
<Editor <Editor
v-model="rawParams" v-model="rawParams"
:lang="'json'" :lang="rawInputEditorLang"
:options="{ :options="{
maxLines: '16', maxLines: '16',
minLines: '8', minLines: '8',
@@ -1075,13 +1075,18 @@
<div class="tab"> <div class="tab">
<collections /> <collections />
</div> </div>
<input id="environment-tab" type="radio" name="side" />
<label for="environment-tab">{{ $t("environment") }}</label>
<div class="tab">
<environments @use-environment="useSelectedEnvironment($event)" />
</div>
<input id="sync-tab" type="radio" name="side" /> <input id="sync-tab" type="radio" name="side" />
<label for="sync-tab">{{ $t("notes") }}</label> <label for="sync-tab">{{ $t("notes") }}</label>
<div class="tab"> <div class="tab">
<pw-section class="pink" :label="$t('notes')" ref="sync"> <pw-section class="pink" :label="$t('notes')" ref="sync">
<div v-if="fb.currentUser"> <div v-if="fb.currentUser">
<inputform /> <inputform />
<ballsfeed /> <notes />
</div> </div>
<div v-else> <div v-else>
<ul> <ul>
@@ -1385,6 +1390,7 @@ import AceEditor from "../components/ace-editor";
import { tokenRequest, oauthRedirect } from "../assets/js/oauth"; import { tokenRequest, oauthRedirect } from "../assets/js/oauth";
import { sendNetworkRequest } from "../functions/network"; import { sendNetworkRequest } from "../functions/network";
import { fb } from "../functions/fb"; import { fb } from "../functions/fb";
import { getEditorLangForMimeType } from "~/functions/editorutils";
const statusCategories = [ const statusCategories = [
{ {
@@ -1451,7 +1457,8 @@ export default {
saveRequestAs: () => import("../components/collections/saveRequestAs"), saveRequestAs: () => import("../components/collections/saveRequestAs"),
Editor: AceEditor, Editor: AceEditor,
inputform: () => import("../components/firebase/inputform"), inputform: () => import("../components/firebase/inputform"),
ballsfeed: () => import("../components/firebase/feeds") notes: () => import("../components/firebase/feeds"),
environments: () => import("../components/environments")
}, },
data() { data() {
return { return {
@@ -1808,6 +1815,9 @@ export default {
this.$store.commit("setState", { value, attribute: "rawInput" }); this.$store.commit("setState", { value, attribute: "rawInput" });
} }
}, },
rawInputEditorLang() {
return getEditorLangForMimeType(this.contentType);
},
requestType: { requestType: {
get() { get() {
return this.$store.state.request.requestType; return this.$store.state.request.requestType;
@@ -2040,6 +2050,16 @@ export default {
} }
}, },
methods: { methods: {
useSelectedEnvironment(environment) {
let preRequestScriptString = "";
for (let variable of environment.variables) {
preRequestScriptString =
preRequestScriptString +
`pw.env.set('${variable.key}', '${variable.value}');\n`;
}
this.preRequestScript = preRequestScriptString;
this.showPreRequestScript = true;
},
checkCollections() { checkCollections() {
const checkCollectionAvailability = const checkCollectionAvailability =
this.$store.state.postwoman.collections && this.$store.state.postwoman.collections &&
@@ -2233,7 +2253,7 @@ export default {
}; };
this.$refs.historyComponent.addEntry(entry); this.$refs.historyComponent.addEntry(entry);
if (fb.currentUser !== null) { if (fb.currentUser !== null) {
if (fb.currentSettings[1].value) { if (fb.currentSettings[2].value) {
fb.writeHistory(entry); fb.writeHistory(entry);
} }
} }
@@ -2270,7 +2290,7 @@ export default {
}; };
this.$refs.historyComponent.addEntry(entry); this.$refs.historyComponent.addEntry(entry);
if (fb.currentUser !== null) { if (fb.currentUser !== null) {
if (fb.currentSettings[1].value) { if (fb.currentSettings[2].value) {
fb.writeHistory(entry); fb.writeHistory(entry);
} }
} }

View File

@@ -38,7 +38,7 @@
{{ setting.value ? $t("enabled") : $t("disabled") }} {{ setting.value ? $t("enabled") : $t("disabled") }}
</pw-toggle> </pw-toggle>
</p> </p>
<p v-if="fb.currentSettings.length == 0"> <p v-if="fb.currentSettings.length !== 3">
<button class="" @click="initSettings"> <button class="" @click="initSettings">
<i class="material-icons">sync</i> <i class="material-icons">sync</i>
<span>{{ $t("turn_on") + " " + $t("sync") }}</span> <span>{{ $t("turn_on") + " " + $t("sync") }}</span>
@@ -155,6 +155,7 @@
</li> </li>
</ul> </ul>
</pw-section> </pw-section>
<pw-section class="blue" :label="$t('proxy')" ref="proxy"> <pw-section class="blue" :label="$t('proxy')" ref="proxy">
<ul> <ul>
<li> <li>
@@ -206,7 +207,12 @@
{{ $t("postwoman_official_proxy_hosting") }} {{ $t("postwoman_official_proxy_hosting") }}
<br /> <br />
{{ $t("read_the") }} {{ $t("read_the") }}
<a href="https://apollotv.xyz/legal" target="_blank" rel="noopener"> <a
class="link"
href="https://apollotv.xyz/legal"
target="_blank"
rel="noopener"
>
{{ $t("apollotv_privacy_policy") }} </a {{ $t("apollotv_privacy_policy") }} </a
>. >.
</p> </p>
@@ -427,7 +433,8 @@ export default {
text: this.$t("yes"), text: this.$t("yes"),
onClick: (e, toastObject) => { onClick: (e, toastObject) => {
fb.writeSettings("syncHistory", true); fb.writeSettings("syncHistory", true);
fb.writeSettings("syncCollections", false); fb.writeSettings("syncCollections", true);
fb.writeSettings("syncEnvironments", true);
this.$router.push({ path: "/settings" }); this.$router.push({ path: "/settings" });
toastObject.remove(); toastObject.remove();
} }
@@ -456,7 +463,8 @@ export default {
text: this.$t("yes"), text: this.$t("yes"),
onClick: (e, toastObject) => { onClick: (e, toastObject) => {
fb.writeSettings("syncHistory", true); fb.writeSettings("syncHistory", true);
fb.writeSettings("syncCollections", false); fb.writeSettings("syncCollections", true);
fb.writeSettings("syncEnvironments", true);
this.$router.push({ path: "/settings" }); this.$router.push({ path: "/settings" });
toastObject.remove(); toastObject.remove();
} }
@@ -475,7 +483,8 @@ export default {
}, },
initSettings() { initSettings() {
fb.writeSettings("syncHistory", true); fb.writeSettings("syncHistory", true);
fb.writeSettings("syncCollections", false); fb.writeSettings("syncCollections", true);
fb.writeSettings("syncEnvironments", true);
}, },
resetProxy({ target }) { resetProxy({ target }) {
this.settings.PROXY_URL = `https://postwoman.apollotv.xyz/`; this.settings.PROXY_URL = `https://postwoman.apollotv.xyz/`;

View File

@@ -57,11 +57,11 @@ export const SETTINGS_KEYS = [
* e.g. 'auth' * e.g. 'auth'
*/ */
"URL_EXCLUDES", "URL_EXCLUDES",
/** /**
* A boolean value indicating whether to use the browser extensions * A boolean value indicating whether to use the browser extensions
* to run the requests * to run the requests
*/ */
"EXTENSIONS_ENABLED" "EXTENSIONS_ENABLED"
]; ];
@@ -74,6 +74,13 @@ export const state = () => ({
requests: [] requests: []
} }
], ],
environments: [
{
name: "My Environment Variables",
variables: []
}
],
editingEnvironment: {},
selectedRequest: {}, selectedRequest: {},
editingRequest: {} editingRequest: {}
}); });
@@ -102,6 +109,80 @@ export const mutations = {
settings[key] = value; settings[key] = value;
}, },
removeVariables({ editingEnvironment }, value) {
editingEnvironment.variables = value;
},
setEditingEnvironment(state, value) {
state.editingEnvironment = { ...value };
},
setVariableKey({ editingEnvironment }, { index, value }) {
editingEnvironment.variables[index].key = value;
},
setVariableValue({ editingEnvironment }, { index, value }) {
editingEnvironment.variables[index].value = testValue(value);
},
removeVariable({ editingEnvironment }, variables) {
editingEnvironment.variables = variables;
},
addVariable({ editingEnvironment }, value) {
editingEnvironment.variables.push(value);
},
replaceEnvironments(state, environments) {
state.environments = environments;
},
importAddEnvironments(state, { environments, confirmation }) {
const duplicateEnvironment = environments.some(
item => {
return state.environments.some(
item2 => {
return item.name.toLowerCase() === item2.name.toLowerCase();
});
}
);
if (duplicateEnvironment) {
this.$toast.info("Duplicate environment");
return;
};
state.environments = [...state.environments, ...environments];
let index = 0;
for (let environment of state.environments) {
environment.environmentIndex = index;
index += 1;
}
this.$toast.info(confirmation, {
icon: "folder_shared"
});
},
removeEnvironment({ environments }, environmentIndex) {
environments.splice(environmentIndex, 1);
},
saveEnvironment({ environments }, payload) {
const { environment, environmentIndex } = payload;
const { name } = environment;
const duplicateEnvironment = environments.length === 1
? false
: environments.some(
item =>
item.environmentIndex !== environmentIndex &&
item.name.toLowerCase() === name.toLowerCase()
);
if (duplicateEnvironment) {
this.$toast.info("Duplicate environment");
return;
}
environments[environmentIndex] = environment;
},
replaceCollections(state, collections) { replaceCollections(state, collections) {
state.collections = collections; state.collections = collections;
}, },
@@ -118,7 +199,9 @@ export const mutations = {
addNewCollection({ collections }, collection) { addNewCollection({ collections }, collection) {
const { name } = collection; const { name } = collection;
const duplicateCollection = collections.some(item => item.name.toLowerCase() === name.toLowerCase()); const duplicateCollection = collections.some(
item => item.name.toLowerCase() === name.toLowerCase()
);
if (duplicateCollection) { if (duplicateCollection) {
this.$toast.info("Duplicate collection"); this.$toast.info("Duplicate collection");
return; return;
@@ -137,9 +220,13 @@ export const mutations = {
}, },
editCollection({ collections }, payload) { editCollection({ collections }, payload) {
const { collection, collectionIndex } = payload; const {
const { name } = collection; collection: { name },
const duplicateCollection = collections.some(item => item.name.toLowerCase() === name.toLowerCase()); collectionIndex
} = payload;
const duplicateCollection = collections.some(
item => item.name.toLowerCase() === name.toLowerCase()
);
if (duplicateCollection) { if (duplicateCollection) {
this.$toast.info("Duplicate collection"); this.$toast.info("Duplicate collection");
return; return;
@@ -323,3 +410,12 @@ export const mutations = {
state.selectedRequest = Object.assign({}, request); state.selectedRequest = Object.assign({}, request);
} }
}; };
function testValue(myValue) {
try {
return JSON.parse(myValue);
} catch(ex) {
// Now we know it's a string just leave it as a string value.
return myValue;
}
}

View File

@@ -20,7 +20,7 @@ export default () => ({
gql: { gql: {
url: "https://rickandmortyapi.com/graphql", url: "https://rickandmortyapi.com/graphql",
headers: [], headers: [],
variablesJSONString: "", variablesJSONString: "{}",
query: "" query: ""
}, },
oauth2: { oauth2: {