Merge branch 'master' into feat/gql-variable-update

This commit is contained in:
Andrew Bastin
2020-01-29 20:49:05 -05:00
committed by GitHub
31 changed files with 2707 additions and 195 deletions

View File

@@ -13,38 +13,40 @@
language: node_js
node_js:
- "12"
- "12"
os: linux
addons:
apt:
packages:
- libgconf-2-4 # cypress binary dependency
apt:
packages:
- libgconf-2-4 # cypress binary dependency
env:
- DEPLOY_ENV=POSTWOMAN_IO
- DEPLOY_ENV=POSTWOMAN_IO
cache:
npm: true
directories:
- "node_modules"
- ~/.cache
npm: true
directories:
- "node_modules"
- ~/.cache
branches:
only:
- "master"
only:
- "master"
install:
- "npm install firebase-tools"
- "npm install"
- "npm install firebase-tools"
- "npm install"
before_script:
- "npm run test"
- "npm run test"
script:
- "cd functions"
- "npm install"
- "cd .."
- "npm run generate"
- "cd functions"
- "npm install"
- "cd .."
- "npm run generate"
notifications:
webhooks: https://www.travisbuddy.com

View File

@@ -1,5 +1,76 @@
# Changelog
## [v1.8.0](https://github.com/liyasthomas/postwoman/tree/v1.8.0) (2020-01-28)
[Full Changelog](https://github.com/liyasthomas/postwoman/compare/v1.5.0...v1.8.0)
**Implemented enhancements:**
- Sync collection with a cloud storage \(e.g: Google drive\) [\#507](https://github.com/liyasthomas/postwoman/issues/507)
- Application contains many hard-coded strings that aren't translatable [\#488](https://github.com/liyasthomas/postwoman/issues/488)
- ULR parsing and var auto creation [\#469](https://github.com/liyasthomas/postwoman/issues/469)
- What about additional loaders: + Pug, TypeScript, SASS, material-vue ? [\#467](https://github.com/liyasthomas/postwoman/issues/467)
- \[suggestion\] - Tests tab [\#465](https://github.com/liyasthomas/postwoman/issues/465)
- 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)
- Add DB cache [\#26](https://github.com/liyasthomas/postwoman/issues/26)
- 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))
- Syntax Error marking in GraphQL query editor [\#505](https://github.com/liyasthomas/postwoman/pull/505) ([AndrewBastin](https://github.com/AndrewBastin))
- Refactoring proxy handling to be done in strategies [\#500](https://github.com/liyasthomas/postwoman/pull/500) ([AndrewBastin](https://github.com/AndrewBastin))
- Firefox Extension compatibility [\#494](https://github.com/liyasthomas/postwoman/pull/494) ([AndrewBastin](https://github.com/AndrewBastin))
- Network Strategies [\#487](https://github.com/liyasthomas/postwoman/pull/487) ([AndrewBastin](https://github.com/AndrewBastin))
- chore\(oauth\): Added method signatures as per JSDoc conventions [\#486](https://github.com/liyasthomas/postwoman/pull/486) ([jamesgeorge007](https://github.com/jamesgeorge007))
- GraphQL Type Highlight and Links [\#479](https://github.com/liyasthomas/postwoman/pull/479) ([AndrewBastin](https://github.com/AndrewBastin))
**Fixed bugs:**
- Warn the user if name field was left blank while creating a new collection [\#515](https://github.com/liyasthomas/postwoman/issues/515)
- 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)
- Post request body is empty [\#473](https://github.com/liyasthomas/postwoman/issues/473)
**Closed issues:**
- Allow importing Postman collections [\#524](https://github.com/liyasthomas/postwoman/issues/524)
- Request descriptions [\#511](https://github.com/liyasthomas/postwoman/issues/511)
- Ability to run all requests of a folder/collection [\#498](https://github.com/liyasthomas/postwoman/issues/498)
- Change import/export collection on requests page icon [\#495](https://github.com/liyasthomas/postwoman/issues/495)
- import cURL error [\#477](https://github.com/liyasthomas/postwoman/issues/477)
- 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)
- 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)
**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))
- 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-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))
- Validations for edit and create collections activity [\#516](https://github.com/liyasthomas/postwoman/pull/516) ([jamesgeorge007](https://github.com/jamesgeorge007))
- Validate duplicate collections [\#510](https://github.com/liyasthomas/postwoman/pull/510) ([jamesgeorge007](https://github.com/jamesgeorge007))
- Lint and refactor [\#506](https://github.com/liyasthomas/postwoman/pull/506) ([liyasthomas](https://github.com/liyasthomas))
- Merge pull request \#504 from liyasthomas/dependabot/npm\_and\_yarn/node-sass-4.13.1 [\#504](https://github.com/liyasthomas/postwoman/pull/504) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- chore\(deps\): bump @nuxtjs/axios from 5.9.2 to 5.9.3 [\#503](https://github.com/liyasthomas/postwoman/pull/503) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- chore\(deps-dev\): bump sass-loader from 8.0.1 to 8.0.2 [\#502](https://github.com/liyasthomas/postwoman/pull/502) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- chore\(deps\): bump ace-builds from 1.4.7 to 1.4.8 [\#501](https://github.com/liyasthomas/postwoman/pull/501) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- 💚 Fixed \#497 [\#499](https://github.com/liyasthomas/postwoman/pull/499) ([pushrbx](https://github.com/pushrbx))
- Feat/firefox strategy [\#496](https://github.com/liyasthomas/postwoman/pull/496) ([liyasthomas](https://github.com/liyasthomas))
- i18n Japanese: Added new translations [\#492](https://github.com/liyasthomas/postwoman/pull/492) ([reefqi037](https://github.com/reefqi037))
- Merge pull request \#491 from liyasthomas/i18n [\#491](https://github.com/liyasthomas/postwoman/pull/491) ([liyasthomas](https://github.com/liyasthomas))
- Replaced hard-coded strings with localizable strings [\#490](https://github.com/liyasthomas/postwoman/pull/490) ([liyasthomas](https://github.com/liyasthomas))
- chore: Minor tweaks [\#485](https://github.com/liyasthomas/postwoman/pull/485) ([jamesgeorge007](https://github.com/jamesgeorge007))
- Porting \(most of\) code to typescript [\#484](https://github.com/liyasthomas/postwoman/pull/484) ([AndrewBastin](https://github.com/AndrewBastin))
- ⬆️ Bump cypress from 3.8.1 to 3.8.2 [\#483](https://github.com/liyasthomas/postwoman/pull/483) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- ⬆️ Bump sass-loader from 8.0.0 to 8.0.1 [\#482](https://github.com/liyasthomas/postwoman/pull/482) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- ⬆️ Bump @nuxtjs/google-analytics from 2.2.2 to 2.2.3 [\#481](https://github.com/liyasthomas/postwoman/pull/481) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- OAuth 2.0/OIDC Access Token Retrieval Support [\#476](https://github.com/liyasthomas/postwoman/pull/476) ([reefqi037](https://github.com/reefqi037))
- ⬆️ Bump cypress from 3.8.0 to 3.8.1 [\#460](https://github.com/liyasthomas/postwoman/pull/460) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
## [v1.5.0](https://github.com/liyasthomas/postwoman/tree/v1.5.0) (2020-01-04)
[Full Changelog](https://github.com/liyasthomas/postwoman/compare/v1.0.0...v1.5.0)
@@ -8,6 +79,7 @@
- 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)
- cookie not found support [\#443](https://github.com/liyasthomas/postwoman/issues/443)
- 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)
- \[request\]: CLI possibilities [\#363](https://github.com/liyasthomas/postwoman/issues/363)
@@ -29,6 +101,7 @@
- Missing Focus on Inputs [\#279](https://github.com/liyasthomas/postwoman/issues/279)
- Download the request result into a file. [\#278](https://github.com/liyasthomas/postwoman/issues/278)
- Improve UI Contrast [\#277](https://github.com/liyasthomas/postwoman/issues/277)
- \[UI\] \[UX\] Allow app to take width of browser [\#236](https://github.com/liyasthomas/postwoman/issues/236)
- Extend syntax highlighting with ACE for pre-request script textarea [\#235](https://github.com/liyasthomas/postwoman/issues/235)
- Store pre-request scripts in history [\#233](https://github.com/liyasthomas/postwoman/issues/233)
- Store the time spent on fetching a response [\#225](https://github.com/liyasthomas/postwoman/issues/225)
@@ -86,7 +159,6 @@
- Intent to translate [\#367](https://github.com/liyasthomas/postwoman/issues/367)
- Static builds on releases [\#352](https://github.com/liyasthomas/postwoman/issues/352)
- fix:SSE onclose handle [\#349](https://github.com/liyasthomas/postwoman/issues/349)
- ⏬ Import a Postman's Collection [\#333](https://github.com/liyasthomas/postwoman/issues/333)
- \[Request\] Use responses for next request? [\#324](https://github.com/liyasthomas/postwoman/issues/324)
- Make response body area expandable [\#294](https://github.com/liyasthomas/postwoman/issues/294)
- Mobile can't see console for request errors [\#283](https://github.com/liyasthomas/postwoman/issues/283)
@@ -102,7 +174,6 @@
- ⬆️ Bump @nuxtjs/axios from 5.9.0 to 5.9.2 [\#472](https://github.com/liyasthomas/postwoman/pull/472) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- Added variables to graphql page. [\#464](https://github.com/liyasthomas/postwoman/pull/464) ([pushrbx](https://github.com/pushrbx))
- i18n [\#463](https://github.com/liyasthomas/postwoman/pull/463) ([liyasthomas](https://github.com/liyasthomas))
- ⬆️ Bump cypress from 3.8.0 to 3.8.1 [\#460](https://github.com/liyasthomas/postwoman/pull/460) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- i18n\(de-DE\): improve some translations [\#459](https://github.com/liyasthomas/postwoman/pull/459) ([gabschne](https://github.com/gabschne))
- bn-BD i18n [\#455](https://github.com/liyasthomas/postwoman/pull/455) ([hmtanbir](https://github.com/hmtanbir))
- API documentation page [\#451](https://github.com/liyasthomas/postwoman/pull/451) ([liyasthomas](https://github.com/liyasthomas))
@@ -148,6 +219,157 @@
- 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))
## [v1.0.0](https://github.com/liyasthomas/postwoman/tree/v1.0.0) (2019-11-04)
[Full Changelog](https://github.com/liyasthomas/postwoman/compare/v0.1.0...v1.0.0)
**Implemented enhancements:**
- Chain requests. Execute a bunch of requests one by one and produce results [\#196](https://github.com/liyasthomas/postwoman/issues/196)
- Allow User to Choose Whether to Include Authentication in Permalink [\#178](https://github.com/liyasthomas/postwoman/issues/178)
- Allow HTTP \(not HTTPS\) on postwoman.io [\#175](https://github.com/liyasthomas/postwoman/issues/175)
- Docker-compose in development [\#168](https://github.com/liyasthomas/postwoman/issues/168)
- Add Docker [\#164](https://github.com/liyasthomas/postwoman/issues/164)
- Clear Input [\#155](https://github.com/liyasthomas/postwoman/issues/155)
- introduce some script language to parse the response and pass environment variable as request parameter [\#139](https://github.com/liyasthomas/postwoman/issues/139)
- Add links to the footer version and commit sha [\#134](https://github.com/liyasthomas/postwoman/issues/134)
- Please add a label for each request. It will be helpful. [\#133](https://github.com/liyasthomas/postwoman/issues/133)
- Use 'icon buttons' instead of 'text buttons' [\#130](https://github.com/liyasthomas/postwoman/issues/130)
- Change .editorconfig [\#115](https://github.com/liyasthomas/postwoman/issues/115)
- \[UX\] Provide Focus State for Buttons, etc. [\#112](https://github.com/liyasthomas/postwoman/issues/112)
- Add linter semistandard [\#98](https://github.com/liyasthomas/postwoman/issues/98)
- Show "Send" button all over the page or enable hotkeys [\#94](https://github.com/liyasthomas/postwoman/issues/94)
- Import request from cURL [\#93](https://github.com/liyasthomas/postwoman/issues/93)
- Search on History [\#92](https://github.com/liyasthomas/postwoman/issues/92)
- Add support for "application/hal+json" Content-Type [\#88](https://github.com/liyasthomas/postwoman/issues/88)
- The query string is built incorrectly when the path contains a parameter [\#87](https://github.com/liyasthomas/postwoman/issues/87)
- Option to Copy request as Fetch or XHR Or CURL [\#76](https://github.com/liyasthomas/postwoman/issues/76)
- Add Tests [\#65](https://github.com/liyasthomas/postwoman/issues/65)
- Request Headers [\#57](https://github.com/liyasthomas/postwoman/issues/57)
- Colored response codes based on status code [\#46](https://github.com/liyasthomas/postwoman/issues/46)
- Improve SEO [\#45](https://github.com/liyasthomas/postwoman/issues/45)
- Add html preview to response section [\#41](https://github.com/liyasthomas/postwoman/issues/41)
- websocket support [\#40](https://github.com/liyasthomas/postwoman/issues/40)
- Raw request body for POST requests and Authorization key/value in Header [\#36](https://github.com/liyasthomas/postwoman/issues/36)
- Code highlight on response body [\#33](https://github.com/liyasthomas/postwoman/issues/33)
- Template selector [\#32](https://github.com/liyasthomas/postwoman/issues/32)
- Vue template [\#31](https://github.com/liyasthomas/postwoman/issues/31)
- Add copy response to clipboard button [\#30](https://github.com/liyasthomas/postwoman/issues/30)
- Ability to store/share/create collections [\#29](https://github.com/liyasthomas/postwoman/issues/29)
- Send request on Enter Key press [\#17](https://github.com/liyasthomas/postwoman/issues/17)
- Readable [\#5](https://github.com/liyasthomas/postwoman/issues/5)
- Serialize a request into JSON? [\#4](https://github.com/liyasthomas/postwoman/issues/4)
- Add brand new logo to the project [\#244](https://github.com/liyasthomas/postwoman/pull/244) ([caneco](https://github.com/caneco))
- Feature/pre request script [\#231](https://github.com/liyasthomas/postwoman/pull/231) ([nickpalenchar](https://github.com/nickpalenchar))
- Add the ApolloTV proxy server [\#217](https://github.com/liyasthomas/postwoman/pull/217) ([NBTX](https://github.com/NBTX))
- bug: keeping information on page change [\#211](https://github.com/liyasthomas/postwoman/pull/211) ([breno-pereira](https://github.com/breno-pereira))
- Work in Progress: feature/allow-collections-importing [\#209](https://github.com/liyasthomas/postwoman/pull/209) ([vlad0337187](https://github.com/vlad0337187))
- Feature/log errors [\#207](https://github.com/liyasthomas/postwoman/pull/207) ([nickpalenchar](https://github.com/nickpalenchar))
- Use returned value from toggle component on change event [\#205](https://github.com/liyasthomas/postwoman/pull/205) ([hosseinnedaee](https://github.com/hosseinnedaee))
- Fix CORS and mixed content issue [\#199](https://github.com/liyasthomas/postwoman/pull/199) ([hosseinnedaee](https://github.com/hosseinnedaee))
- Added Tooltips [\#197](https://github.com/liyasthomas/postwoman/pull/197) ([AndrewBastin](https://github.com/AndrewBastin))
- Added auto theme [\#185](https://github.com/liyasthomas/postwoman/pull/185) ([AndrewBastin](https://github.com/AndrewBastin))
- Add Request name label for every requests [\#184](https://github.com/liyasthomas/postwoman/pull/184) ([sharath2106](https://github.com/sharath2106))
- Collections [\#176](https://github.com/liyasthomas/postwoman/pull/176) ([TheHollidayInn](https://github.com/TheHollidayInn))
**Fixed bugs:**
- Bearer Token value still left even after being cleared [\#212](https://github.com/liyasthomas/postwoman/issues/212)
- All changes in input fields lost when you switch to another page [\#203](https://github.com/liyasthomas/postwoman/issues/203)
- POST request json bodies aren't sent [\#180](https://github.com/liyasthomas/postwoman/issues/180)
- Headers turn into 0 : \[Object object\] [\#166](https://github.com/liyasthomas/postwoman/issues/166)
- Send Again Button Constantly Flickering [\#157](https://github.com/liyasthomas/postwoman/issues/157)
- There are cross-domain problems [\#128](https://github.com/liyasthomas/postwoman/issues/128)
- Raw requests are not being sent [\#124](https://github.com/liyasthomas/postwoman/issues/124)
- Request Body Is Not Sent [\#113](https://github.com/liyasthomas/postwoman/issues/113)
- default menu option - 'Http' is not highlighted when launched from installed pwa app \(UI bug\) [\#100](https://github.com/liyasthomas/postwoman/issues/100)
- App is broken with old history in localStorage [\#74](https://github.com/liyasthomas/postwoman/issues/74)
- Last added history entry is removed automatically after refresh [\#66](https://github.com/liyasthomas/postwoman/issues/66)
- Cannot use localhost as base url [\#56](https://github.com/liyasthomas/postwoman/issues/56)
- \[CORS\] No 'Access-Control-Allow-Origin' header is present on the requested resource [\#2](https://github.com/liyasthomas/postwoman/issues/2)
**Closed issues:**
- Section labels don't display properly in Firefox [\#237](https://github.com/liyasthomas/postwoman/issues/237)
- Unsupported URLs \[BUG\]? [\#229](https://github.com/liyasthomas/postwoman/issues/229)
- Credentials are still being included in Permalink even when "Include in URL" is turned off [\#227](https://github.com/liyasthomas/postwoman/issues/227)
- Display sendRequest runtime errors in the console [\#206](https://github.com/liyasthomas/postwoman/issues/206)
- Missing "Landing/start page" [\#162](https://github.com/liyasthomas/postwoman/issues/162)
- 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)
- Inconsistent version name [\#141](https://github.com/liyasthomas/postwoman/issues/141)
- Autoresize the textarea [\#102](https://github.com/liyasthomas/postwoman/issues/102)
- Content-Type revamping [\#99](https://github.com/liyasthomas/postwoman/issues/99)
- Add version number in footer [\#97](https://github.com/liyasthomas/postwoman/issues/97)
- The history doesn't show a date with the timestamp. [\#81](https://github.com/liyasthomas/postwoman/issues/81)
- Not working on Brave Browser anymore [\#71](https://github.com/liyasthomas/postwoman/issues/71)
- Why da fuq is your name plastered all over the README? [\#70](https://github.com/liyasthomas/postwoman/issues/70)
- Comparison with Postman is missing [\#69](https://github.com/liyasthomas/postwoman/issues/69)
- HTTP request with different library [\#61](https://github.com/liyasthomas/postwoman/issues/61)
- Editorconfig file [\#60](https://github.com/liyasthomas/postwoman/issues/60)
- 500 this.isValidURL is not a function [\#58](https://github.com/liyasthomas/postwoman/issues/58)
- Styling with Tailwindcss [\#38](https://github.com/liyasthomas/postwoman/issues/38)
- Not Working in IE 11 [\#37](https://github.com/liyasthomas/postwoman/issues/37)
- PWA not installable [\#19](https://github.com/liyasthomas/postwoman/issues/19)
- Simple Misspelling [\#8](https://github.com/liyasthomas/postwoman/issues/8)
**Merged pull requests:**
- docs: add liyasthomas as a contributor [\#264](https://github.com/liyasthomas/postwoman/pull/264) ([allcontributors[bot]](https://github.com/apps/allcontributors))
- docs: add jamesgeorge007 as a contributor [\#263](https://github.com/liyasthomas/postwoman/pull/263) ([allcontributors[bot]](https://github.com/apps/allcontributors))
- docs: add NBTX as a contributor [\#262](https://github.com/liyasthomas/postwoman/pull/262) ([allcontributors[bot]](https://github.com/apps/allcontributors))
- Fix .all-contributorsrc badge template. [\#260](https://github.com/liyasthomas/postwoman/pull/260) ([NBTX](https://github.com/NBTX))
- docs: add hosseinnedaee as a contributor [\#259](https://github.com/liyasthomas/postwoman/pull/259) ([allcontributors[bot]](https://github.com/apps/allcontributors))
- docs: add nityanandagohain as a contributor [\#257](https://github.com/liyasthomas/postwoman/pull/257) ([allcontributors[bot]](https://github.com/apps/allcontributors))
- docs: add JacobAnavisca as a contributor [\#256](https://github.com/liyasthomas/postwoman/pull/256) ([allcontributors[bot]](https://github.com/apps/allcontributors))
- docs: add izerozlu as a contributor [\#255](https://github.com/liyasthomas/postwoman/pull/255) ([allcontributors[bot]](https://github.com/apps/allcontributors))
- docs: add vlad0337187 as a contributor [\#254](https://github.com/liyasthomas/postwoman/pull/254) ([allcontributors[bot]](https://github.com/apps/allcontributors))
- docs: add AndrewBastin as a contributor [\#253](https://github.com/liyasthomas/postwoman/pull/253) ([allcontributors[bot]](https://github.com/apps/allcontributors))
- docs: add terranblake as a contributor [\#252](https://github.com/liyasthomas/postwoman/pull/252) ([allcontributors[bot]](https://github.com/apps/allcontributors))
- docs: add nickpalenchar as a contributor [\#251](https://github.com/liyasthomas/postwoman/pull/251) ([allcontributors[bot]](https://github.com/apps/allcontributors))
- docs: add yubathom as a contributor [\#250](https://github.com/liyasthomas/postwoman/pull/250) ([allcontributors[bot]](https://github.com/apps/allcontributors))
- docs: add larouxn as a contributor [\#249](https://github.com/liyasthomas/postwoman/pull/249) ([allcontributors[bot]](https://github.com/apps/allcontributors))
- docs: add NBTX as a contributor [\#248](https://github.com/liyasthomas/postwoman/pull/248) ([allcontributors[bot]](https://github.com/apps/allcontributors))
- docs: add liyasthomas as a contributor [\#247](https://github.com/liyasthomas/postwoman/pull/247) ([allcontributors[bot]](https://github.com/apps/allcontributors))
- Make page changes more fluid [\#246](https://github.com/liyasthomas/postwoman/pull/246) ([NBTX](https://github.com/NBTX))
- Minor tweaks [\#245](https://github.com/liyasthomas/postwoman/pull/245) ([liyasthomas](https://github.com/liyasthomas))
- ⬆️ Bump @nuxtjs/google-tag-manager from 2.3.0 to 2.3.1 [\#243](https://github.com/liyasthomas/postwoman/pull/243) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- ⬆️ Bump yargs-parser from 15.0.0 to 16.1.0 [\#242](https://github.com/liyasthomas/postwoman/pull/242) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- ⬆️ Bump @nuxtjs/toast from 3.2.1 to 3.3.0 [\#241](https://github.com/liyasthomas/postwoman/pull/241) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- ⬆️ Bump highlight.js from 9.15.10 to 9.16.2 [\#240](https://github.com/liyasthomas/postwoman/pull/240) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- ⬆️ Bump cypress from 3.5.0 to 3.6.0 [\#239](https://github.com/liyasthomas/postwoman/pull/239) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- Fix legend labels in Firefox, fix colored labels slider [\#238](https://github.com/liyasthomas/postwoman/pull/238) ([NBTX](https://github.com/NBTX))
- Documentation Cleanup [\#230](https://github.com/liyasthomas/postwoman/pull/230) ([amitdash291](https://github.com/amitdash291))
- Fix \#227 Exclude credentials from permalink [\#228](https://github.com/liyasthomas/postwoman/pull/228) ([reefqi037](https://github.com/reefqi037))
- ⬆️ Bump cypress from 3.4.1 to 3.5.0 [\#224](https://github.com/liyasthomas/postwoman/pull/224) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- ⬆️ Bump @nuxtjs/axios from 5.6.0 to 5.8.0 [\#223](https://github.com/liyasthomas/postwoman/pull/223) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- ⬆️ Bump node-sass from 4.12.0 to 4.13.0 [\#222](https://github.com/liyasthomas/postwoman/pull/222) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- ⬆️ Bump nuxt from 2.10.1 to 2.10.2 [\#221](https://github.com/liyasthomas/postwoman/pull/221) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- ⬆️ Bump @nuxtjs/google-analytics from 2.2.0 to 2.2.1 [\#220](https://github.com/liyasthomas/postwoman/pull/220) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- ⬆️ Bump vuex-persist from 2.1.0 to 2.1.1 [\#219](https://github.com/liyasthomas/postwoman/pull/219) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- Fixed frame colors toggle [\#216](https://github.com/liyasthomas/postwoman/pull/216) ([mateusppereira](https://github.com/mateusppereira))
- Re-order sections and add toggle for including authentication in URL [\#215](https://github.com/liyasthomas/postwoman/pull/215) ([NBTX](https://github.com/NBTX))
- chore: minor code refactor [\#214](https://github.com/liyasthomas/postwoman/pull/214) ([jamesgeorge007](https://github.com/jamesgeorge007))
- Fix \#212 Clear bearer token value [\#213](https://github.com/liyasthomas/postwoman/pull/213) ([reefqi037](https://github.com/reefqi037))
- fix: don't display 'Collection is empty' label if collection has any … [\#208](https://github.com/liyasthomas/postwoman/pull/208) ([vlad0337187](https://github.com/vlad0337187))
- Fix proxy URL [\#201](https://github.com/liyasthomas/postwoman/pull/201) ([NBTX](https://github.com/NBTX))
- Fix CORS and Mixed-Content issue & Bug Fixes [\#200](https://github.com/liyasthomas/postwoman/pull/200) ([NBTX](https://github.com/NBTX))
- ⬆️ Bump start-server-and-test from 1.10.5 to 1.10.6 [\#198](https://github.com/liyasthomas/postwoman/pull/198) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- ⬆️ Bump start-server-and-test from 1.10.3 to 1.10.5 [\#194](https://github.com/liyasthomas/postwoman/pull/194) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- ⬆️ Bump @nuxtjs/google-tag-manager from 2.2.1 to 2.3.0 [\#193](https://github.com/liyasthomas/postwoman/pull/193) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- ⬆️ Bump nuxt from 2.10.0 to 2.10.1 [\#192](https://github.com/liyasthomas/postwoman/pull/192) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- ⬆️ Bump yargs-parser from 14.0.0 to 15.0.0 [\#191](https://github.com/liyasthomas/postwoman/pull/191) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- Add quotation marks for generated code [\#187](https://github.com/liyasthomas/postwoman/pull/187) ([johnhenry](https://github.com/johnhenry))
- Add basic e2e tests [\#181](https://github.com/liyasthomas/postwoman/pull/181) ([yubathom](https://github.com/yubathom))
- ⬆️ Bump nuxt from 2.9.2 to 2.10.0 [\#179](https://github.com/liyasthomas/postwoman/pull/179) ([dependabot-preview[bot]](https://github.com/apps/dependabot-preview))
- 🐛 Fixed sitemap configuration [\#177](https://github.com/liyasthomas/postwoman/pull/177) ([NicoPennec](https://github.com/NicoPennec))
- Code Refactoring [\#173](https://github.com/liyasthomas/postwoman/pull/173) ([edisonaugusthy](https://github.com/edisonaugusthy))
- Added Black Theme [\#172](https://github.com/liyasthomas/postwoman/pull/172) ([AndrewBastin](https://github.com/AndrewBastin))
## [v0.1.0](https://github.com/liyasthomas/postwoman/tree/v0.1.0) (2019-08-22)
[Full Changelog](https://github.com/liyasthomas/postwoman/compare/91c08a5e6305cc95a0df46a33fdd0013bf7339b4...v0.1.0)
\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*

View File

@@ -3,10 +3,10 @@
<br>
<br>
<p>
API request builder - A free, fast, and beautiful alternative to Postman
<b>A free, fast & beautiful API request builder</b>
</p>
<p>
Helps you create your requests faster, saving you precious time on your development - <a href="https://postwoman.launchaco.com">Subscribe</a>
<i>Web alternative to Postman - Helps you create requests faster, saving precious time on development - <a href="https://postwoman.launchaco.com">Subscribe</a></i>
</p>
<p>
@@ -32,7 +32,6 @@
<div align="center">
<br>
<img src="static/images/screenshot1.png" alt="Screenshot1" width="100%">
<img src="static/images/screenshot2.png" alt="Screenshot2" width="100%">
<br>
</div>
@@ -190,41 +189,43 @@ _Requests with Pre-Request Scripts are indicated in History entries_
🌎 **i18n β**: Experience the app in your own language.
1. Scroll down to the footer
2. Click "Choose Language" button
2. Click "Choose Language" icon button
3. Select your language from the menu
_Keep in mind translations aren't available for all source and target language combinations_
_Keep in mind: Translations aren't available for all source and target language combinations_
**To provide a localized experience for users around the world, you can add you own translations.**
- Add a new locale in `lang/`
Example: `lang/es-ES.js`
- Mention `code`, `name`, `iso` and `file` in `nuxt.config.js`
Example:
```
i18n: {
locales: [{
code: 'es',
name: 'Español',
iso: 'es-ES',
file: 'es-ES.js'
}]
}
```
_**All `i18n` contributions are welcome to `i18n` [branch](https://github.com/liyasthomas/postwoman/tree/i18n) only!**_
📦 **Add-ons**: Official add-ons for Postwoman.
- **[Proxy β](https://github.com/postwoman-io/postwoman-proxy)** - A simple proxy server created for Postwoman
- **[CLI β](https://github.com/postwoman-io/postwoman-cli)** - A CLI solution for Postwoman
- **[Browser Extensions](https://github.com/AndrewBastin/postwoman-firefox)** - 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) &nbsp;|&nbsp; ![Chrome](https://raw.github.com/alrra/browser-logos/master/src/chrome/chrome_16x16.png) **Chrome (coming soon)**
[![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)) &nbsp;|&nbsp; [![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))
_Add-ons are developed and maintained under **[Official Postwoman Organization](https://github.com/postwoman-io)**_
>**Extensions fixes `CORS` issues.**
_Add-ons are developed and maintained under **[Official Postwoman Organization](https://github.com/postwoman-io)**._
☁️ **Auth + Sync**: Sign in and sync in real-time.
**Sign in with:**
- Google
- GitHub
**Sync:**
- History
- Collections
**Post-Request Tests β**: Write tests associated with a request that are executed after the request response.
**Use-cases:**
- Check the status code as an integer
- Filter response headers
- Parse the response data
**To find out more, please check out [Postwoman Wiki](https://github.com/liyasthomas/postwoman/wiki).**

View File

@@ -27,6 +27,7 @@
-webkit-font-feature-settings: "liga";
-webkit-font-smoothing: antialiased;
font-feature-settings: "liga";
border-radius: 50%;
}
/* poppins-500 - latin */

View File

@@ -259,6 +259,10 @@ h4 {
font-weight: 700;
}
hr {
border-bottom: 1px dashed var(--brd-color);
}
.tooltip {
$bgcolor: var(--tt-color);
$fgcolor: var(--fg-color);
@@ -387,6 +391,10 @@ h3.title {
color: var(--fg-light-color);
}
.bg-color {
background-color: transparent;
}
button {
display: inline-flex;
align-items: center;
@@ -592,7 +600,6 @@ pre {
select {
height: 37px;
background-color: var(--bg-dark-color);
cursor: pointer;
-webkit-appearance: none;
-moz-appearance: none;
@@ -698,6 +705,7 @@ ol li {
.show-on-large-screen {
display: inline-flex;
flex: 1;
}
.info-response {

View File

@@ -53,7 +53,7 @@ try {
// Write version data into a file
fs.writeFileSync(
PW_BUILD_DATA_DIR + "/version.json",
`${PW_BUILD_DATA_DIR}/version.json`,
JSON.stringify(version)
);
})();

View File

@@ -56,6 +56,10 @@ export default {
},
methods: {
addNewCollection() {
if (!this.$data.name) {
this.$toast.info("Please provide a valid name for the collection");
return;
}
this.$store.commit("postwoman/addNewCollection", {
name: this.$data.name
});

View File

@@ -59,6 +59,10 @@ export default {
},
methods: {
saveCollection() {
if (!this.$data.name) {
this.$toast.info("Please provide a valid name for the collection");
return;
}
const collectionUpdated = {
...this.$props.editingCollection,
name: this.$data.name

View File

@@ -11,6 +11,54 @@
</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="syncCollections"
>
<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>
@@ -18,39 +66,6 @@
<textarea v-model="collectionJson" rows="8"></textarea>
</div>
<div slot="footer">
<div class="flex-wrap">
<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"
/>
</button>
<button
class="icon"
@click="openDialogChooseFileToImportFrom"
v-tooltip="$t('preserve_current')"
>
<i class="material-icons">folder_shared</i>
<span>{{ $t("import_json") }}</span>
<input
type="file"
@change="importFromJSON"
style="display: none;"
ref="inputChooseFileToImportFrom"
/>
</button>
</span>
<span></span>
</div>
<div class="flex-wrap">
<span></span>
<span>
@@ -71,7 +86,14 @@
</template>
<script>
import { fb } from "../../functions/fb";
export default {
data() {
return {
fb
};
},
props: {
show: Boolean
},
@@ -101,6 +123,7 @@ export default {
this.$store.commit("postwoman/replaceCollections", collections);
};
reader.readAsText(this.$refs.inputChooseFileToReplaceWith.files[0]);
this.fileImported();
},
importFromJSON() {
let reader = new FileReader();
@@ -110,6 +133,7 @@ export default {
this.$store.commit("postwoman/importCollections", collections);
};
reader.readAsText(this.$refs.inputChooseFileToImportFrom.files[0]);
this.fileImported();
},
exportJSON() {
let text = this.collectionJson;
@@ -125,6 +149,18 @@ export default {
document.body.appendChild(anchor);
anchor.click();
document.body.removeChild(anchor);
this.$toast.success(this.$t("download_started"), {
icon: "done"
});
},
syncCollections() {
this.$store.commit("postwoman/replaceCollections", fb.currentCollections);
this.fileImported();
},
fileImported() {
this.$toast.info(this.$t("file_imported"), {
icon: "folder_shared"
});
}
}
};

View File

@@ -108,6 +108,7 @@ ul {
<script>
import collection from "./collection";
import { fb } from "../../functions/fb";
export default {
components: {
@@ -172,11 +173,13 @@ export default {
this.$data.editingCollection = collection;
this.$data.editingCollectionIndex = collectionIndex;
this.displayModalEdit(true);
this.syncCollections();
},
addFolder(collection, collectionIndex) {
this.$data.editingCollection = collection;
this.$data.editingCollectionIndex = collectionIndex;
this.displayModalAddFolder(true);
this.syncCollections();
},
editFolder(payload) {
const { collectionIndex, folder, folderIndex } = payload;
@@ -185,6 +188,7 @@ export default {
this.$data.editingFolder = folder;
this.$data.editingFolderIndex = folderIndex;
this.displayModalEditFolder(true);
this.syncCollections();
},
editRequest(payload) {
const { request, collectionIndex, folderIndex, requestIndex } = payload;
@@ -193,6 +197,7 @@ export default {
this.$data.editingRequest = request;
this.$data.editingRequestIndex = requestIndex;
this.displayModalEditRequest(true);
this.syncCollections();
},
resetSelectedData() {
this.$data.editingCollection = undefined;
@@ -201,6 +206,15 @@ export default {
this.$data.editingFolderIndex = undefined;
this.$data.editingRequest = undefined;
this.$data.editingRequestIndex = undefined;
},
syncCollections() {
if (fb.currentUser !== null) {
if (fb.currentSettings[0].value) {
fb.writeCollections(
JSON.parse(JSON.stringify(this.$store.state.postwoman.collections))
);
}
}
}
}
};

View File

@@ -0,0 +1,81 @@
<template>
<virtual-list
v-if="fb.currentFeeds.length !== 0"
class="virtual-list"
:class="{ filled: fb.currentFeeds.length }"
:size="56"
:remain="Math.min(8, fb.currentFeeds.length)"
>
<ul v-for="feed in fb.currentFeeds" :key="feed.id">
<div class="show-on-large-screen">
<li>
<input
:aria-label="$t('label')"
type="text"
readonly
:value="feed.label"
:placeholder="$t('no_label')"
class="bg-color"
/>
</li>
<button class="icon" @click="saveFeed(feed)">
<i class="material-icons">get_app</i>
</button>
<button class="icon" @click="deleteFeed(feed)">
<i class="material-icons">delete</i>
</button>
</div>
</ul>
</virtual-list>
<ul v-else>
<li>
<label class="info">{{ $t("empty") }}</label>
</li>
</ul>
</template>
<style scoped lang="scss">
.virtual-list {
max-height: calc(100vh - 288px);
}
</style>
<script>
import { fb } from "../../functions/fb";
export default {
components: {
VirtualList: () => import("vue-virtual-scroll-list")
},
data() {
return {
fb
};
},
methods: {
deleteFeed(feed) {
fb.deleteFeed(feed.id);
this.$toast.error(this.$t("deleted"), {
icon: "delete"
});
},
saveFeed(feed) {
const dataToWrite = JSON.stringify(feed.message, null, 2);
const file = new Blob([dataToWrite], { type: "application/json" });
const a = document.createElement("a"),
url = URL.createObjectURL(file);
a.href = url;
a.download = (feed.label + " on " + Date()).replace(/\./g, "[dot]");
document.body.appendChild(a);
a.click();
this.$toast.success(this.$t("download_started"), {
icon: "done"
});
setTimeout(() => {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 1000);
}
}
};
</script>

View File

@@ -0,0 +1,55 @@
<template>
<div>
<ul>
<li>
<input
:aria-label="$t('label')"
type="text"
autofocus
v-model="message"
:placeholder="$t('paste_a_collection')"
/>
</li>
</ul>
<ul>
<li>
<input
:aria-label="$t('label')"
type="text"
autofocus
v-model="label"
:placeholder="$t('label')"
/>
</li>
<button
class="icon"
:disabled="!(this.message && this.label)"
value="Save"
@click="formPost"
>
<i class="material-icons">add</i>
<span>Add</span>
</button>
</ul>
</div>
</template>
<script>
import { fb } from "../../functions/fb";
export default {
data() {
return {
message: null,
label: null
};
},
methods: {
formPost() {
fb.writeFeeds(this.message, this.label);
this.message = null;
this.label = null;
}
}
};
</script>

View File

@@ -0,0 +1,115 @@
<template>
<v-popover>
<button class="icon" v-tooltip="$t('login_with')">
<i class="material-icons">vpn_key</i>
</button>
<template slot="popover">
<div>
<button class="icon" @click="signInWithGoogle" v-close-popover>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
class="material-icons"
>
<path
d="M12.24 10.285V14.4h6.806c-.275 1.765-2.056 5.174-6.806 5.174-4.095 0-7.439-3.389-7.439-7.574s3.345-7.574 7.439-7.574c2.33 0 3.891.989 4.785 1.849l3.254-3.138C18.189 1.186 15.479 0 12.24 0c-6.635 0-12 5.365-12 12s5.365 12 12 12c6.926 0 11.52-4.869 11.52-11.726 0-.788-.085-1.39-.189-1.989H12.24z"
/>
</svg>
<span>Google</span>
</button>
</div>
<div>
<button class="icon" @click="signInWithGithub" v-close-popover>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
class="material-icons"
>
<path
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"
/>
</svg>
<span>GitHub</span>
</button>
</div>
</template>
</v-popover>
</template>
<script>
import firebase from "firebase/app";
import { fb } from "../../functions/fb";
export default {
data() {
return {
fb
};
},
methods: {
signInWithGoogle() {
const provider = new firebase.auth.GoogleAuthProvider();
firebase
.auth()
.signInWithPopup(provider)
.then(res => {
if (res.additionalUserInfo.isNewUser) {
this.$toast.info(this.$t("turn_on") + " " + this.$t("sync"), {
icon: "sync",
duration: null,
closeOnSwipe: false,
action: {
text: this.$t("yes"),
onClick: (e, toastObject) => {
fb.writeSettings("syncHistory", false);
fb.writeSettings("syncCollections", true);
this.$router.push({ path: "/settings" });
toastObject.remove();
}
}
});
}
})
.catch(err => {
this.$toast.show(err.message || err, {
icon: "error"
});
});
},
signInWithGithub() {
const provider = new firebase.auth.GithubAuthProvider();
firebase
.auth()
.signInWithPopup(provider)
.then(res => {
if (res.additionalUserInfo.isNewUser) {
this.$toast.info(this.$t("turn_on") + " " + this.$t("sync"), {
icon: "sync",
duration: null,
closeOnSwipe: false,
action: {
text: this.$t("yes"),
onClick: (e, toastObject) => {
fb.writeSettings("syncHistory", false);
fb.writeSettings("syncCollections", true);
this.$router.push({ path: "/settings" });
toastObject.remove();
}
}
});
}
})
.catch(err => {
this.$toast.show(err.message || err, {
icon: "error"
});
});
}
}
};
</script>

View File

@@ -34,7 +34,7 @@ export default {
return {
editor: null,
cacheValue: "",
validationSchema: null
validationSchema: null
};
},
@@ -88,7 +88,7 @@ export default {
);
}
},
setValidationSchema(schema) {
this.validationSchema = schema;
this.parseContents(this.cacheValue);
@@ -101,16 +101,15 @@ export default {
if (this.validationSchema) {
this.editor.session.setAnnotations(
gql.validate(this.validationSchema, doc)
.map((err) => {
return {
row: err.locations[0].line - 1,
column: err.locations[0].column - 1,
text: err.message,
type: "error"
}
})
)
gql.validate(this.validationSchema, doc).map(err => {
return {
row: err.locations[0].line - 1,
column: err.locations[0].column - 1,
text: err.message,
type: "error"
};
})
);
}
} catch (e) {
this.editor.session.setAnnotations([

View File

@@ -21,7 +21,7 @@
<button
class="icon"
:class="{ stared: entry.star }"
@click="toggleStar(index)"
@click="toggleStar(entry)"
v-tooltip="{
content: !entry.star ? $t('add_star') : $t('remove_star')
}"
@@ -314,10 +314,6 @@ ol li {
padding: 0 0 8px;
}
.bg-color {
background-color: transparent;
}
@media (max-width: 720px) {
.virtual-list.filled {
min-height: 320px;
@@ -331,6 +327,7 @@ ol li {
<script>
import { findStatusGroup } from "../pages/index";
import { fb } from "../functions/fb";
const updateOnLocalStorage = (propertyName, property) =>
window.localStorage.setItem(propertyName, JSON.stringify(property));
@@ -341,11 +338,11 @@ export default {
VirtualList: () => import("vue-virtual-scroll-list")
},
data() {
const localStorageHistory = JSON.parse(
window.localStorage.getItem("history")
);
return {
history: localStorageHistory || [],
history:
fb.currentUser !== null
? fb.currentHistory
: JSON.parse(window.localStorage.getItem("history")) || [],
filterText: "",
showFilter: false,
isClearingHistory: false,
@@ -359,6 +356,10 @@ export default {
},
computed: {
filteredHistory() {
this.history =
fb.currentUser !== null
? fb.currentHistory
: JSON.parse(window.localStorage.getItem("history")) || [];
return this.history.filter(entry => {
const filterText = this.filterText.toLowerCase();
return Object.keys(entry).some(key => {
@@ -371,6 +372,9 @@ export default {
},
methods: {
clearHistory() {
if (fb.currentUser !== null) {
fb.clearHistory();
}
this.history = [];
this.filterText = "";
this.disableHistoryClearing();
@@ -391,6 +395,9 @@ export default {
);
},
deleteHistory(entry) {
if (fb.currentUser !== null) {
fb.deleteHistory(entry);
}
this.history.splice(this.history.indexOf(entry), 1);
if (this.history.length === 0) {
this.filterText = "";
@@ -497,8 +504,11 @@ export default {
toggleCollapse() {
this.showMore = !this.showMore;
},
toggleStar(index) {
this.history[index]["star"] = !this.history[index]["star"];
toggleStar(entry) {
if (fb.currentUser !== null) {
fb.toggleStar(entry, !entry.star);
}
entry.star = !entry.star;
updateOnLocalStorage("history", this.history);
}
}

View File

@@ -1,7 +1,14 @@
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write;
allow read, write: if request.auth.uid != null;
}
// Make sure the uid of the requesting user matches name of the user
// document. The wildcard expression {userId} makes the userId variable
// available in rules.
match /users/{userId} {
allow read, update, delete: if request.auth.uid == userId;
allow create: if request.auth.uid != null;
}
}
}

192
functions/fb.js Normal file
View File

@@ -0,0 +1,192 @@
import firebase from "firebase/app";
import "firebase/firestore";
import "firebase/auth";
// Initialize Firebase, copied from cloud console
const firebaseConfig = {
apiKey: "AIzaSyCMsFreESs58-hRxTtiqQrIcimh4i1wbsM",
authDomain: "postwoman-api.firebaseapp.com",
databaseURL: "https://postwoman-api.firebaseio.com",
projectId: "postwoman-api",
storageBucket: "postwoman-api.appspot.com",
messagingSenderId: "421993993223",
appId: "1:421993993223:web:ec0baa8ee8c02ffa1fc6a2",
measurementId: "G-ERJ6025CEB"
};
firebase.initializeApp(firebaseConfig);
// a reference to the users collection
const usersCollection = firebase.firestore().collection("users");
// the shared state object that any vue component
// can get access to
export const fb = {
currentUser: {},
currentFeeds: [],
currentSettings: [],
currentHistory: [],
currentCollections: [],
writeFeeds: async (message, label) => {
const dt = {
createdOn: new Date(),
author: fb.currentUser.uid,
author_name: fb.currentUser.displayName,
author_image: fb.currentUser.photoURL,
message,
label
};
usersCollection
.doc(fb.currentUser.uid)
.collection("feeds")
.add(dt)
.catch(e => console.error("error inserting", dt, e));
},
deleteFeed: id => {
usersCollection
.doc(fb.currentUser.uid)
.collection("feeds")
.doc(id)
.delete()
.catch(e => console.error("error deleting", id, e));
},
writeSettings: async (setting, value) => {
const st = {
updatedOn: new Date(),
author: fb.currentUser.uid,
author_name: fb.currentUser.displayName,
author_image: fb.currentUser.photoURL,
name: setting,
value
};
usersCollection
.doc(fb.currentUser.uid)
.collection("settings")
.doc(setting)
.set(st)
.catch(e => console.error("error updating", st, e));
},
writeHistory: async entry => {
const hs = entry;
usersCollection
.doc(fb.currentUser.uid)
.collection("history")
.add(hs)
.catch(e => console.error("error inserting", hs, e));
},
deleteHistory: entry => {
usersCollection
.doc(fb.currentUser.uid)
.collection("history")
.doc(entry.id)
.delete()
.catch(e => console.error("error deleting", entry, e));
},
clearHistory: () => {
usersCollection
.doc(fb.currentUser.uid)
.collection("history")
.get()
.then(({ docs }) => {
docs.forEach(e => fb.deleteHistory(e));
});
},
toggleStar: (entry, value) => {
usersCollection
.doc(fb.currentUser.uid)
.collection("history")
.doc(entry.id)
.update({ star: value })
.catch(e => console.error("error deleting", entry, e));
},
writeCollections: async collection => {
const cl = {
updatedOn: new Date(),
author: fb.currentUser.uid,
author_name: fb.currentUser.displayName,
author_image: fb.currentUser.photoURL,
collection: collection
};
usersCollection
.doc(fb.currentUser.uid)
.collection("collections")
.doc("sync")
.set(cl)
.catch(e => console.error("error updating", cl, e));
}
};
// When a user logs in or out, save that in the store
firebase.auth().onAuthStateChanged(user => {
if (user) {
fb.currentUser = user;
fb.currentUser.providerData.forEach(profile => {
let us = {
updatedOn: new Date(),
provider: profile.providerId,
name: profile.displayName,
email: profile.email,
photoUrl: profile.photoURL,
uid: profile.uid
};
usersCollection
.doc(fb.currentUser.uid)
.set(us)
.catch(e => console.error("error updating", us, e));
});
usersCollection
.doc(fb.currentUser.uid)
.collection("feeds")
.orderBy("createdOn", "desc")
.onSnapshot(feedsRef => {
const feeds = [];
feedsRef.forEach(doc => {
const feed = doc.data();
feed.id = doc.id;
feeds.push(feed);
});
fb.currentFeeds = feeds;
});
usersCollection
.doc(fb.currentUser.uid)
.collection("settings")
.onSnapshot(settingsRef => {
const settings = [];
settingsRef.forEach(doc => {
const setting = doc.data();
setting.id = doc.id;
settings.push(setting);
});
fb.currentSettings = settings;
});
usersCollection
.doc(fb.currentUser.uid)
.collection("history")
.onSnapshot(historyRef => {
const history = [];
historyRef.forEach(doc => {
const entry = doc.data();
entry.id = doc.id;
history.push(entry);
});
fb.currentHistory = history;
});
usersCollection
.doc(fb.currentUser.uid)
.collection("collections")
.onSnapshot(collectionsRef => {
const collections = [];
collectionsRef.forEach(doc => {
const collection = doc.data();
collection.id = doc.id;
collections.push(collection);
});
fb.currentCollections = collections[0].collection;
});
} else {
fb.currentUser = null;
}
});

View File

@@ -1,8 +1,13 @@
import AxiosStrategy from "./strategies/AxiosStrategy";
import FirefoxStrategy from "./strategies/FirefoxStrategy";
import ChromeStrategy, { hasChromeExtensionInstalled } from "./strategies/ChromeStrategy";
const runAppropriateStrategy = (req, store) => {
// Chrome Provides a chrome object for scripts to access
// Check its availability to say whether you are in Google Chrome
if (window.chrome && hasChromeExtensionInstalled()) {
return ChromeStrategy(req, store);
}
// The firefox plugin injects a function to send requests through it
// If that is available, then we can use the FirefoxStrategy
if (window.firefoxExtSendRequest) {

View File

@@ -0,0 +1,175 @@
const PASS = "PASS";
const FAIL = "FAIL";
const ERROR = "ERROR";
const styles = {
[PASS]: { icon: "check", class: "success-response" },
[FAIL]: { icon: "close", class: "cl-error-response" },
[ERROR]: { icon: "close", class: "cl-error-response" },
none: { icon: "", class: "" }
};
// TODO: probably have to use a more global state for `test`
export default function runTestScriptWithVariables(script, variables) {
let pw = {
_errors: [],
_testReports: [],
_report: "",
expect(value) {
try {
return expect(value, this._testReports);
} catch (e) {
pw._testReports.push({ result: ERROR, message: e });
}
},
test: (descriptor, func) => test(descriptor, func, pw._testReports)
// globals that the script is allowed to have access to.
};
Object.assign(pw, variables);
// run pre-request script within this function so that it has access to the pw object.
new Function("pw", script)(pw);
//
const testReports = pw._testReports.map(item => {
if (item.result) {
item.styles = styles[item.result];
} else {
item.styles = styles.none;
}
return item;
});
return { report: pw._report, errors: pw._errors, testResults: testReports };
}
function test(descriptor, func, _testReports) {
_testReports.push({ startBlock: descriptor });
try {
func();
} catch (e) {
_testReports.push({ result: ERROR, message: e });
}
_testReports.push({ endBlock: true });
// TODO: Organize and generate text report of each {descriptor: true} section in testReports.
// add checkmark or x depending on if each testReport is pass=true or pass=false
}
function expect(expectValue, _testReports) {
return new Expectation(expectValue, null, _testReports);
}
class Expectation {
constructor(expectValue, _not, _testReports) {
this.expectValue = expectValue;
this.not = _not || new Expectation(this.expectValue, true, _testReports);
this._testReports = _testReports; // this values is used within Test.it, which wraps Expectation and passes _testReports value.
this._satisfies = function(expectValue, targetValue) {
// Used for testing if two values match the expectation, which could be === OR !==, depending on if not
// was used. Expectation#_satisfies prevents the need to have an if(this.not) branch in every test method.
// Signature is _satisfies([expectValue,] targetValue): if only one argument is given, it is assumed the targetValue, and expectValue is set to this.expectValue
if (!targetValue) {
targetValue = expectValue;
expectValue = this.expectValue;
}
if (this.not === true) {
// test the inverse. this.not is always truthly, but an Expectation that is inverted will always be strictly `true`
return expectValue !== targetValue;
} else {
return expectValue === targetValue;
}
};
}
_fmtNot(message) {
// given a string with "(not)" in it, replaces with "not" or "", depending if the expectation is expecting the positive or inverse (this._not)
if (this.not === true) {
return message.replace("(not)", "not ");
} else {
return message.replace("(not)", "");
}
}
_fail(message) {
this._testReports.push({ result: FAIL, message });
}
_pass(message) {
this._testReports.push({ result: PASS });
}
// TEST METHODS DEFINED BELOW
// these are the usual methods that would follow expect(...)
toBe(value) {
return this._satisfies(value)
? this._pass()
: this._fail(
this._fmtNot(`Expected ${this.expectValue} (not)to be ${value}`)
);
}
toHaveProperty(value) {
return this._satisfies(this.expectValue.hasOwnProperty(value), true)
? this._pass()
: this._fail(
this._fmtNot(
`Expected object ${this.expectValue} to (not)have property ${value}`
)
);
}
toBeLevel2xx() {
const code = parseInt(this.expectValue);
if (Number.isNaN(code)) {
return this._fail(
`Expected 200-level status but could not parse value ${this.expectValue}`
);
}
return this._satisfies(code >= 200 && code < 300)
? this._pass()
: this._fail(
this._fmtNot(
`Expected ${this.expectValue} to (not)be 200-level status`
)
);
}
toBeLevel3xx() {
const code = parseInt(this.expectValue);
if (Number.isNaN(code)) {
return this._fail(
`Expected 300-level status but could not parse value ${this.expectValue}`
);
}
return this._satisfies(code >= 300 && code < 400)
? this._pass()
: this._fail(
this._fmtNot(
`Expected ${this.expectValue} to (not)be 300-level status`
)
);
}
toBeLevel4xx() {
const code = parseInt(this.expectValue);
if (Number.isNaN(code)) {
return this._fail(
`Expected 400-level status but could not parse value ${this.expectValue}`
);
}
return this._satisfies(code >= 400 && code < 500)
? this._pass()
: this._fail(
this._fmtNot(
`Expected ${this.expectValue} to (not)be 400-level status`
)
);
}
toBeLevel5xx() {
const code = parseInt(this.expectValue);
if (Number.isNaN(code)) {
return this._fail(
`Expected 500-level status but could not parse value ${this.expectValue}`
);
}
return this._satisfies(code >= 500 && code < 600)
? this._pass()
: this._fail(
this._fmtNot(
`Expected ${this.expectValue} to (not)be 500-level status`
)
);
}
}

View File

@@ -0,0 +1,56 @@
const EXTENSION_ID = "amknoiejhlmhancpahfcfcfhllgkpbld";
// Check if the Chrome Extension is present
// The Chrome extension injects an empty span to help detection.
// Also check for the presence of window.chrome object to confirm smooth operations
export const hasChromeExtensionInstalled = () => {
return document.getElementById("chromePWExtensionDetect") !== null;
}
const chromeWithoutProxy = (req, _store) => new Promise((resolve, reject) => {
chrome.runtime.sendMessage(
EXTENSION_ID, {
messageType: "send-req",
data: {
config: req
}
}, (message) => {
if (message.data.error) {
reject(message.data.error);
} else {
resolve(message.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 {
resolve(message.data.response.data);
}
}
)
});
const chromeStrategy = (req, store) => {
if (store.state.postwoman.settings.PROXY_ENABLED) {
return chromeWithProxy(req, store);
} else {
return chromeWithoutProxy(req, store);
}
}
export default chromeStrategy;

View File

@@ -6,7 +6,7 @@ const firefoxWithProxy = (req, { state }) =>
if (event.detail.error) {
reject(JSON.parse(event.detail.error));
} else {
resolve(JSON.parse(event.detail.response));
resolve(JSON.parse(event.detail.response).data);
}
};

View File

@@ -3,13 +3,13 @@
// functions which might be called frequently
// NOTE : Don't use lambda functions as this doesn't get bound properly in them, use the 'function (args) {}' format
const debounce = (func, delay) => {
let inDebounce
let inDebounce;
return function() {
const context = this
const args = arguments
clearTimeout(inDebounce)
inDebounce = setTimeout(() => func.apply(context, args), delay)
}
}
const context = this;
const args = arguments;
clearTimeout(inDebounce);
inDebounce = setTimeout(() => func.apply(context, args), delay);
};
};
export default debounce;

View File

@@ -249,5 +249,16 @@ export default {
extensions: "Extensions",
extensions_info1: "Browser extension that simplifies access to Postwoman",
extensions_info2: "Get Postwoman browser extension!",
installed: "Installed"
installed: "Installed",
login_with: "Login with",
logged_out: "Logged out",
logout: "Logout",
account: "Account",
sync: "Sync",
syncHistory: "History",
syncCollections: "Collections",
turn_on: "Turn on",
login_first: "Login first",
paste_a_collection: "Paste a Collection",
import_from_sync: "Import from Sync"
};

View File

@@ -66,7 +66,7 @@ export default {
response: "レスポンス",
query: "クエリ",
queries: "クエリ",
query_variables: "変数 (へんすう)",
query_variables: "変数",
mutations: "ミューテーション",
subscriptions: "サブスクリプション",
types: "タイプ",
@@ -83,8 +83,163 @@ export default {
read_the: "プライバシーポリシー",
apollotv_privacy_policy: "を読む",
contact_us: "お問い合わせ",
connect: "つなぐ",
disconnect: "切断する",
connect: "接続",
disconnect: "切断",
start: "開始",
stop: "やめる"
stop: "停止",
access_token: "アクセストークン",
token_list: "トークンリスト",
get_token: "新しいトークンを取得",
manage_token: "アクセストークンを管理",
save_token: "アクセストークンを保存",
use_token: "アクセストークンを使用",
request_token: "トークンをリクエスト",
save_token_req: "トークンリクエストを保存",
manage_token_req: "トークンリクエストを管理",
use_token_req: "トークンリクエストを使用",
token_req_name: "リクエスト名",
token_req_details: "リクエスト詳細",
token_name: "トークン名",
oidc_discovery_url: "OIDC Discovery URL",
auth_url: "認証URL",
access_token_url: "アクセストークンURL",
client_id: "クライアントID",
scope: "スコープ",
state: "ステート",
token_req_list: "トークンリクエストリスト",
no_path: "パス無し",
no_label: "ラベル無し",
prerequest_script: "プレリクエストスクリプト",
no_prerequest_script: "プレリクエストスクリプト無し",
search_history: "検索履歴",
history_empty: "履歴が空です",
history_deleted: "履歴が削除された",
clear: "クリア",
clear_all: "全てクリア",
cleared: "クリアされた",
close: "閉じる",
sort: "ソート",
time: "時間",
duration: "期間",
no_duration: "期間なし",
show_more: "もっと表示する",
hide_more: "隠す",
collection: "コレクション",
current_collection: "現在のコレクション",
select_collection: "コレクションを選択",
create_collection: "コレクションを作成",
new: "新規",
import_export: "インポート・エクスポート",
more: "More",
folder: "フォルダ",
new_folder: "新しいフォルダー",
my_new_folder: "私の新しいフォルダー",
folder_empty: "フォルダーが空です",
edit_folder: "フォルダーを編集",
edit: "編集",
delete: "削除",
deleted: "削除された",
undo: "元に戻す",
collection_empty: "コレクションが空です",
new_collection: "新しいコレクション",
my_new_collection: "私の新しいコレクション",
edit_collection: "コレクションを編集",
edit_request: "リクエストを編集",
save_request_as: "名前を付けてリクエストを保存",
export: "エクスポート",
connecting_to: "{name}に接続中...",
connected: "接続した",
connected_to: "{name}に接続した",
disconnected: "切断された",
disconnected_from: "{name}から切断された",
something_went_wrong: "何かの問題が起きた",
error_occurred: "エラーが発生した",
browser_support_sse: "このブラウザはサーバー送信イベントのサポートがないようです。",
log: "ログ",
no_url: "URL無し",
run_query: "クエリを実行",
copy_query: "クエリをコピー",
kinda_dark: "ちょっと暗い",
clearly_white: "明らかに白",
just_black: "ただの黒",
auto_system: "オート(システム)",
green: "緑",
yellow: "黄",
pink: "ピンク",
red: "赤",
purple: "紫",
orange: "オレンジ",
cyan: "シヤン",
blue: "青",
loading: "ロード中...",
fetching: "フェッチ中...",
waiting_send_req: "(リクエスト送信待ち)",
cancel: "キャンセル",
save: "保存",
dismiss: "Dismiss",
are_you_sure: "よろしいですか?",
yes: "はい",
no: "いいえ",
restore: "リストア",
add_star: "星を付ける",
remove_star: "星を外す",
nothing_found: "何も見つからない",
replace_current: "置換",
replace_json: "JSONに置換",
preserve_current: "保持",
import_json: "JSONをインポート",
download_file: "ファイルをダウンロード",
upload_file: "ファイルをアップロード",
copy_response: "レスポンスをコピー",
copy_code: "コードをコピー",
copy_schema: "スキーマをコピー",
use_request: "リクエストを使用",
documentation: "ドキュメンテーション",
docs: "ドキュメント",
reset_default: "デフォルトにリセット",
fields: "FIELDS",
deprecated: "DEPRECATED",
add_one_header: "ヘッダーを少なくとも1つ追加してください",
add_one_parameter: "パラメータを少なくとも1つ追加してください",
header_count: "ヘッダー {count}",
parameter_count: "パラメータ {count}",
variable_count: "変数 {count}",
value_count: "値 {count}",
send_request_first: "リクエストを先に送信してください",
generate_docs: "ドキュメンテーションを生成",
generate_docs_message: "Postwomanのコレクションをインポートし、直ちにドキュメンテーションを生成",
generate_docs_first: "ドキュメントを先に生成してください",
docs_generated: "ドキュメンテーションを生成した",
import_collections: "コレクションをインポート",
optional: "(オプション)",
json: "JSON",
none: "なし",
username: "ユーザー名",
password: "パスワード",
token: "トークン",
payload: "ペイロード",
choose_file: "ファイルを選択",
file_imported: "ファイルをインポートした",
f12_details: "F12を押して詳細を確認してください",
we_use_cookies: "クッキーを使用します。",
copied_to_clipboard: "クリップボードにコピーした",
finished_in: "{duration}msで終了した",
check_console_details: "コンソールより詳細を確認してください",
download_started: "ダウンロードを開始した",
url_invalid_format: "URLが正しくフォーマットされていない",
curl_invalid_format: "cURLが正しくフォーマットされていない",
enable_proxy: "プロキシを有効にしてみてください",
complete_config_urls: "設定URLsを入力してください",
token_request_saved: "トークンリクエストを保存した",
donate_info1: "Postwomanを非常に役に立つと思われる場合、感謝の印として寄付のご検討をお願いします。",
donate_info2: "以下の方法でPostwomanの開発をサポートできます",
one_time_recurring: "一度又は定期的",
one_time: "一度",
recurring: "定期的",
wiki: "Wiki",
error: "エラー",
go_home: "ホームに戻る",
reload: "リロード",
enter_curl: "cURLを入力",
empty: "空"
};

View File

@@ -237,6 +237,11 @@
<div v-else-if="$route.path === '/settings'">
<nav class="secondary-nav">
<ul>
<li>
<a href="#account" v-tooltip.right="$t('account')">
<i class="material-icons">person</i>
</a>
</li>
<li>
<a href="#theme" v-tooltip.right="$t('theme')">
<i class="material-icons">brush</i>
@@ -288,6 +293,48 @@
>
<i class="material-icons">offline_bolt</i>
</button>
<login v-if="!fb.currentUser" />
<span v-if="fb.currentUser">
<v-popover>
<button
class="icon"
v-tooltip="
(fb.currentUser.displayName ||
'<label><i>Name not found</i></label>') +
'<br>' +
(fb.currentUser.email ||
'<label><i>Email not found</i></label>')
"
aria-label="Account"
>
<img
v-if="fb.currentUser.photoURL"
:src="fb.currentUser.photoURL"
class="material-icons"
alt="Profile image"
/>
<i v-else class="material-icons">account_circle</i>
</button>
<template slot="popover">
<div>
<nuxt-link :to="localePath('settings')" v-close-popover>
<button class="icon">
<i class="material-icons">settings</i>
<span>
{{ $t("settings") }}
</span>
</button>
</nuxt-link>
</div>
<div>
<button class="icon" @click="logout" v-close-popover>
<i class="material-icons">exit_to_app</i>
<span>{{ $t("logout") }}</span>
</button>
</div>
</template>
</v-popover>
</span>
<v-popover>
<button class="icon" v-tooltip="$t('more')">
<i class="material-icons">more_vert</i>
@@ -470,27 +517,33 @@
</a>
</div>
<div>
<button class="icon" disabled>
<svg
class="material-icons"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
>
<path
d="M2.897 4.181c2.43-2.828 5.763-4.181 9.072-4.181 4.288 0 8.535 2.273 10.717 6.554-2.722.001-6.984 0-9.293 0-1.674.001-2.755-.037-3.926.579-1.376.724-2.415 2.067-2.777 3.644l-3.793-6.596zm5.11 7.819c0 2.2 1.789 3.99 3.988 3.99s3.988-1.79 3.988-3.99-1.789-3.991-3.988-3.991-3.988 1.791-3.988 3.991zm5.536 5.223c-2.238.666-4.858-.073-6.293-2.549-1.095-1.891-3.989-6.933-5.305-9.225-1.33 2.04-1.945 4.294-1.945 6.507 0 5.448 3.726 10.65 9.673 11.818l3.87-6.551zm2.158-9.214c1.864 1.734 2.271 4.542 1.007 6.719-.951 1.641-3.988 6.766-5.46 9.248 7.189.443 12.752-5.36 12.752-11.972 0-1.313-.22-2.66-.69-3.995h-7.609z"
/>
</svg>
<span>Chrome (coming soon)</span>
<span
class="icon"
v-if="chromeExtInstalled"
v-tooltip="$t('installed')"
>
<i class="material-icons">done</i>
</span>
</button>
<a
href="https://chrome.google.com/webstore/detail/postwoman-extension-for-c/amknoiejhlmhancpahfcfcfhllgkpbld"
target="_blank"
rel="noopener"
>
<button class="icon">
<svg
class="material-icons"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
>
<path
d="M2.897 4.181c2.43-2.828 5.763-4.181 9.072-4.181 4.288 0 8.535 2.273 10.717 6.554-2.722.001-6.984 0-9.293 0-1.674.001-2.755-.037-3.926.579-1.376.724-2.415 2.067-2.777 3.644l-3.793-6.596zm5.11 7.819c0 2.2 1.789 3.99 3.988 3.99s3.988-1.79 3.988-3.99-1.789-3.991-3.988-3.991-3.988 1.791-3.988 3.991zm5.536 5.223c-2.238.666-4.858-.073-6.293-2.549-1.095-1.891-3.989-6.933-5.305-9.225-1.33 2.04-1.945 4.294-1.945 6.507 0 5.448 3.726 10.65 9.673 11.818l3.87-6.551zm2.158-9.214c1.864 1.734 2.271 4.542 1.007 6.719-.951 1.641-3.988 6.766-5.46 9.248 7.189.443 12.752-5.36 12.752-11.972 0-1.313-.22-2.66-.69-3.995h-7.609z"
/>
</svg>
<span>Chrome</span>
<span
class="icon"
v-if="chromeExtInstalled"
v-tooltip="$t('installed')"
>
<i class="material-icons">done</i>
</span>
</button>
</a>
</div>
</div>
<div slot="footer"></div>
@@ -612,11 +665,15 @@
<script>
import intializePwa from "../assets/js/pwa";
import * as version from "../.postwoman/version.json";
import { hasChromeExtensionInstalled } from "../functions/strategies/ChromeStrategy";
import firebase from "firebase/app";
import { fb } from "../functions/fb";
export default {
components: {
logo: () => import("../components/logo"),
modal: () => import("../components/modal")
modal: () => import("../components/modal"),
login: () => import("../components/firebase/login")
},
methods: {
@@ -625,6 +682,21 @@ export default {
"nuxt-link-exact-active": this.$route.path === path,
"nuxt-link-active": this.$route.path === path
};
},
logout() {
fb.currentUser = null;
firebase
.auth()
.signOut()
.catch(err => {
this.$toast.show(err.message || err, {
icon: "error"
});
});
this.$toast.info(this.$t("logged_out"), {
icon: "vpn_key"
});
}
},
@@ -639,7 +711,8 @@ export default {
showShortcuts: false,
showSupport: false,
firefoxExtInstalled: window.firefoxExtSendRequest,
chromeExtInstalled: false
chromeExtInstalled: window.chrome && hasChromeExtensionInstalled(),
fb
};
},
@@ -760,7 +833,7 @@ export default {
watch: {
$route() {
this.$toast.clear();
// this.$toast.clear();
}
},

1038
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -26,17 +26,19 @@
"@nuxtjs/sitemap": "^2.0.1",
"@nuxtjs/toast": "^3.3.0",
"ace-builds": "^1.4.8",
"firebase": "^7.7.0",
"graphql": "^14.5.8",
"nuxt": "^2.11.0",
"nuxt-i18n": "^6.4.1",
"v-tooltip": "^2.0.2",
"nuxt-i18n": "^6.5.0",
"v-tooltip": "^2.0.3",
"vue-virtual-scroll-list": "^1.4.4",
"vuefire": "^2.2.1",
"vuejs-auto-complete": "^0.9.0",
"vuex-persist": "^2.2.0",
"yargs-parser": "^16.1.0"
},
"devDependencies": {
"cypress": "^3.8.2",
"cypress": "^3.8.3",
"node-sass": "^4.13.1",
"sass-loader": "^8.0.2",
"start-server-and-test": "^1.10.6"

View File

@@ -757,9 +757,7 @@ export default {
}
}
this.gqlTypes = types;
this.$refs.queryEditor.setValidationSchema(schema);
this.$nuxt.$loading.finish();
const duration = Date.now() - startTime;
this.$toast.info(this.$t("finished_in", { duration }), {

View File

@@ -28,8 +28,8 @@
v-model="preRequestScript"
:lang="'javascript'"
:options="{
maxLines: responseBodyMaxLines,
minLines: '16',
maxLines: '16',
minLines: '8',
fontSize: '16px',
autoScrollEditorIntoView: true,
showPrintMargin: false,
@@ -282,6 +282,23 @@
>close</i
>
</button>
<button
:class="'icon' + (testsEnabled ? ' info-response' : '')"
id="preRequestScriptButto"
v-tooltip.bottom="{
content: !testsEnabled ? 'Enable Tests' : 'Disable Tests'
}"
@click="testsEnabled = !testsEnabled"
>
<i
class="material-icons"
:class="testsEnabled"
v-if="!testsEnabled"
>
assignment_turned_in
</i>
<i class="material-icons" :class="testsEnabled" v-else>close</i>
</button>
</span>
<span>
<button
@@ -316,6 +333,74 @@
</div>
</pw-section>
<pw-section
v-if="testsEnabled"
class="orange"
label="Tests"
ref="postRequestTests"
>
<ul>
<li>
<div class="flex-wrap">
<label for="generatedCode">{{ $t("javascript_code") }}</label>
<div>
<a
href="https://github.com/liyasthomas/postwoman/wiki/Post-Requests-Tests"
target="_blank"
rel="noopener"
>
<button class="icon" v-tooltip="$t('wiki')">
<i class="material-icons">help</i>
</button>
</a>
</div>
</div>
<Editor
v-model="testScript"
:lang="'javascript'"
:options="{
maxLines: '16',
minLines: '8',
fontSize: '16px',
autoScrollEditorIntoView: true,
showPrintMargin: false,
useWorker: false
}"
/>
<div v-if="testReports">
<div class="flex-wrap">
<label>Test Reports</label>
<div>
<button
class="icon"
@click="clearContent('tests', $event)"
v-tooltip.bottom="$t('clear')"
>
<i class="material-icons">clear_all</i>
</button>
</div>
</div>
<div v-for="testReport in testReports">
<div v-if="testReport.startBlock" class="info">
<h4>{{ testReport.startBlock }}</h4>
</div>
<p v-else-if="testReport.result" class="flex-wrap info">
<span :class="testReport.styles.class">
<i class="material-icons">
{{ testReport.styles.icon }}
</i>
<span>&nbsp; {{ testReport.result }}</span>
<span v-if="testReport.message">
<label>&nbsp; &nbsp; {{ testReport.message }}</label>
</span>
</span>
</p>
<div v-else-if="testReport.endBlock"><hr /></div>
</div>
</div>
</li>
</ul>
</pw-section>
<section id="options">
<input id="tab-one" type="radio" name="options" checked="checked" />
<label for="tab-one">{{ $t("authentication") }}</label>
@@ -846,6 +931,26 @@
<collections />
</pw-section>
</div>
<input id="sync-tab" type="radio" name="side" />
<label for="sync-tab">{{ $t("sync") }}</label>
<div class="tab">
<pw-section
v-if="fb.currentUser"
class="pink"
label="Sync"
ref="sync"
>
<inputform />
<ballsfeed />
</pw-section>
<pw-section v-else>
<ul>
<li>
<label>{{ $t("login_first") }}</label>
</li>
</ul>
</pw-section>
</div>
</section>
</aside>
@@ -1132,10 +1237,12 @@ import querystring from "querystring";
import textareaAutoHeight from "../directives/textareaAutoHeight";
import parseCurlCommand from "../assets/js/curlparser.js";
import getEnvironmentVariablesFromScript from "../functions/preRequest";
import runTestScriptWithVariables from "../functions/postwomanTesting";
import parseTemplateString from "../functions/templating";
import AceEditor from "../components/ace-editor";
import { tokenRequest, oauthRedirect } from "../assets/js/oauth";
import { sendNetworkRequest } from "../functions/network";
import { fb } from "../functions/fb";
const statusCategories = [
{
@@ -1200,13 +1307,18 @@ export default {
autocomplete: () => import("../components/autocomplete"),
collections: () => import("../components/collections"),
saveRequestAs: () => import("../components/collections/saveRequestAs"),
Editor: AceEditor
Editor: AceEditor,
inputform: () => import("../components/firebase/inputform"),
ballsfeed: () => import("../components/firebase/feeds")
},
data() {
return {
showModal: false,
showPreRequestScript: false,
testsEnabled: false,
testScript: "// pw.expect('variable').toBe('value');",
preRequestScript: "// pw.env.set('variable', 'value');",
testReports: null,
copyButton: '<i class="material-icons">file_copy</i>',
downloadButton: '<i class="material-icons">get_app</i>',
doneButton: '<i class="material-icons">done</i>',
@@ -1370,12 +1482,12 @@ export default {
],
showRequestModal: false,
editRequest: {},
urlExcludes: {},
responseBodyText: "",
responseBodyType: "text",
responseBodyMaxLines: 16,
activeSidebar: true
activeSidebar: true,
fb
};
},
watch: {
@@ -2106,7 +2218,23 @@ export default {
star: false
};
this.$refs.historyComponent.addEntry(entry);
if (fb.currentUser !== null) {
if (fb.currentSettings[1].value) {
fb.writeHistory(entry);
}
}
})();
// tests
const syntheticResponse = {
status: this.response.status,
body: this.response.body,
headers: this.response.headers
};
const { testResults } = runTestScriptWithVariables(this.testScript, {
response: syntheticResponse
});
this.testReports = testResults;
} catch (error) {
console.error(error);
if (error.response) {
@@ -2127,6 +2255,11 @@ export default {
preRequestScript: this.preRequestScript
};
this.$refs.historyComponent.addEntry(entry);
if (fb.currentUser !== null) {
if (fb.currentSettings[1].value) {
fb.writeHistory(entry);
}
}
return;
} else {
this.response.status = error.message;
@@ -2139,7 +2272,7 @@ export default {
icon: "help",
duration: 8000,
action: {
text: "Settings",
text: this.$t("yes"),
onClick: (e, toastObject) => {
this.$router.push({ path: "/settings" });
}
@@ -2483,6 +2616,9 @@ export default {
break;
case "tokenReqs":
this.tokenReqs = [];
case "tests":
this.testReports = null;
break;
default:
(this.label = ""),
(this.method = "GET"),

View File

@@ -1,5 +1,88 @@
<template>
<div class="page">
<pw-section class="green" :label="$t('account')" ref="account">
<ul>
<li>
<div v-if="fb.currentUser">
<button class="icon">
<img
v-if="fb.currentUser.photoURL"
:src="fb.currentUser.photoURL"
class="material-icons"
/>
<i v-else class="material-icons">account_circle</i>
<span>
{{ fb.currentUser.displayName || "Name not found" }}
</span>
</button>
<br />
<button class="icon">
<i class="material-icons">email</i>
<span>
{{ fb.currentUser.email || "Email not found" }}
</span>
</button>
<br />
<button class="icon" @click="logout">
<i class="material-icons">exit_to_app</i>
<span>{{ $t("logout") }}</span>
</button>
<br />
<p v-for="setting in fb.currentSettings" :key="setting.id">
<pw-toggle
:key="setting.name"
:on="setting.value"
@change="toggleSettings(setting.name, setting.value)"
>
{{ $t(setting.name) + " " + $t("sync") }}
{{ setting.value ? $t("enabled") : $t("disabled") }}
</pw-toggle>
</p>
<p v-if="fb.currentSettings.length == 0">
<button class="" @click="initSettings">
<i class="material-icons">sync</i>
<span>{{ $t("turn_on") + " " + $t("sync") }}</span>
</button>
</p>
</div>
<div v-else>
<label>{{ $t("login_with") }}</label>
<p>
<button class="icon" @click="signInWithGoogle">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
class="material-icons"
>
<path
d="M12.24 10.285V14.4h6.806c-.275 1.765-2.056 5.174-6.806 5.174-4.095 0-7.439-3.389-7.439-7.574s3.345-7.574 7.439-7.574c2.33 0 3.891.989 4.785 1.849l3.254-3.138C18.189 1.186 15.479 0 12.24 0c-6.635 0-12 5.365-12 12s5.365 12 12 12c6.926 0 11.52-4.869 11.52-11.726 0-.788-.085-1.39-.189-1.989H12.24z"
/>
</svg>
<span>Google</span>
</button>
<br />
<button class="icon" @click="signInWithGithub">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
class="material-icons"
>
<path
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"
/>
</svg>
<span>GitHub</span>
</button>
</p>
</div>
</li>
</ul>
</pw-section>
<pw-section class="cyan" :label="$t('theme')" ref="theme">
<ul>
<li>
@@ -89,7 +172,7 @@
<label for="url">{{ $t("url") }}</label>
<button
class="icon"
@click="settings.PROXY_URL = `https://postwoman.apollotv.xyz/`"
@click="resetProxy"
v-tooltip.bottom="$t('reset_default')"
>
<i class="material-icons">clear_all</i>
@@ -137,6 +220,9 @@
<style scoped lang="scss"></style>
<script>
import firebase from "firebase/app";
import { fb } from "../functions/fb";
export default {
components: {
"pw-section": () => import("../components/section"),
@@ -238,7 +324,10 @@ export default {
this.$store.state.postwoman.settings.PROXY_URL ||
"https://postwoman.apollotv.xyz/",
PROXY_KEY: this.$store.state.postwoman.settings.PROXY_KEY || ""
}
},
doneButton: '<i class="material-icons">done</i>',
fb
};
},
@@ -289,8 +378,99 @@ export default {
toggleSetting(key) {
this.settings[key] = !this.settings[key];
this.$store.commit("postwoman/applySetting", [key, this.settings[key]]);
},
logout() {
fb.currentUser = null;
firebase
.auth()
.signOut()
.catch(err => {
this.$toast.show(err.message || err, {
icon: "error"
});
});
this.$toast.info(this.$t("logged_out"), {
icon: "vpn_key"
});
},
signInWithGoogle() {
const provider = new firebase.auth.GoogleAuthProvider();
firebase
.auth()
.signInWithPopup(provider)
.then(res => {
if (res.additionalUserInfo.isNewUser) {
this.$toast.info(this.$t("turn_on") + " " + this.$t("sync"), {
icon: "sync",
duration: null,
closeOnSwipe: false,
action: {
text: this.$t("yes"),
onClick: (e, toastObject) => {
fb.writeSettings("syncHistory", true);
fb.writeSettings("syncCollections", false);
this.$router.push({ path: "/settings" });
toastObject.remove();
}
}
});
}
})
.catch(err => {
this.$toast.show(err.message || err, {
icon: "error"
});
});
},
signInWithGithub() {
const provider = new firebase.auth.GithubAuthProvider();
firebase
.auth()
.signInWithPopup(provider)
.then(res => {
if (res.additionalUserInfo.isNewUser) {
this.$toast.info(this.$t("turn_on") + " " + this.$t("sync"), {
icon: "sync",
duration: null,
closeOnSwipe: false,
action: {
text: this.$t("yes"),
onClick: (e, toastObject) => {
fb.writeSettings("syncHistory", true);
fb.writeSettings("syncCollections", false);
this.$router.push({ path: "/settings" });
toastObject.remove();
}
}
});
}
})
.catch(err => {
this.$toast.show(err.message || err, {
icon: "error"
});
});
},
toggleSettings(s, v) {
fb.writeSettings(s, !v);
},
initSettings() {
fb.writeSettings("syncHistory", true);
fb.writeSettings("syncCollections", false);
},
resetProxy(e) {
this.settings.PROXY_URL = `https://postwoman.apollotv.xyz/`;
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
);
}
},
beforeMount() {
this.settings.THEME_COLOR = this.getActiveColor();
},

View File

@@ -111,10 +111,10 @@ export const mutations = {
},
addNewCollection({ collections }, collection) {
const { name } = collection
const duplicateCollection = collections.some(item => item.name === name)
const { name } = collection;
const duplicateCollection = collections.some(item => item.name === name);
if (duplicateCollection) {
this.$toast.info('Duplicate collection');
this.$toast.info("Duplicate collection");
return;
}
collections.push({
@@ -132,6 +132,12 @@ export const mutations = {
editCollection({ collections }, payload) {
const { collection, collectionIndex } = payload;
const { name } = collection;
const duplicateCollection = collections.some(item => item.name === name);
if (duplicateCollection) {
this.$toast.info("Duplicate collection");
return;
}
collections[collectionIndex] = collection;
},