Compare commits

..

435 Commits

Author SHA1 Message Date
Liyas Thomas
3f727d6f71 Merge branch 'master' of https://github.com/liyasthomas/postwoman 2020-01-04 06:57:53 +05:30
Liyas Thomas
99acc4921c ⬆️ Bumped version to 1.5.0 2020-01-04 06:55:44 +05:30
Liyas Thomas
db7dcba1b9 Merge pull request #472 from liyasthomas/dependabot/npm_and_yarn/nuxtjs/axios-5.9.2
⬆️ Bump @nuxtjs/axios from 5.9.0 to 5.9.2
2020-01-04 06:02:34 +05:30
dependabot-preview[bot]
8f76d3fa58 ⬆️ Bump @nuxtjs/axios from 5.9.0 to 5.9.2
Bumps [@nuxtjs/axios](https://github.com/nuxt-community/axios-module) from 5.9.0 to 5.9.2.
- [Release notes](https://github.com/nuxt-community/axios-module/releases)
- [Changelog](https://github.com/nuxt-community/axios-module/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/nuxt-community/axios-module/compare/v5.9.0...v5.9.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-04 00:13:01 +00:00
Liyas Thomas
0930b1ada8 🐛 Better URL validation, Fixed #471 2020-01-03 21:07:41 +05:30
Liyas Thomas
35df7c6429 💚 Fixing CI Build 2020-01-01 13:51:28 +05:30
Liyas Thomas
e679e8c5f4 Added OAuth 2.0 authentication. Fixed #358 2020-01-01 13:36:55 +05:30
Liyas Thomas
d43a655116 💲 Updated Open Collective link 2020-01-01 10:29:51 +05:30
Liyas Thomas
56a4ca0e21 🐛 Fixed clear button on variables list 2019-12-31 19:38:26 +05:30
Liyas Thomas
f17b126dd4 Merge pull request #464 from pushrbx/feature/graphql-vars
Added variables to graphql page.
2019-12-31 19:03:40 +05:30
pushrbx
1ac144e3a7 🎉 Added variables to graphql page (w/ lame type validation). 2019-12-31 13:09:26 +00:00
Liyas Thomas
13402a5aa5 Added Gitpod dev env 2019-12-31 08:50:35 +05:30
Liyas Thomas
92a0cc245f i18n (#463)
i18n

Co-authored-by: Tanbir Hasan <tanbir2025@gmail.com>
Co-authored-by: Gabriel Schneider <57860382+gabschne@users.noreply.github.com>
2019-12-31 08:46:40 +05:30
Liyas Thomas
8b9a2c5f7e Merge branch 'master' into i18n 2019-12-31 08:38:05 +05:30
Liyas Thomas
bc10e4304f Added Gitpod dev env, removed two stale translations 2019-12-31 08:35:27 +05:30
Liyas Thomas
d40de785b7 Lint and minor UI improvements 2019-12-29 06:17:00 +05:30
Liyas Thomas
9ff02eefb8 🔥 Hid empty fields 2019-12-29 05:08:55 +05:30
Liyas Thomas
e8837e69a0 Merge pull request #460 from liyasthomas/dependabot/npm_and_yarn/cypress-3.8.1
⬆️ Bump cypress from 3.8.0 to 3.8.1
2019-12-28 07:47:16 +05:30
dependabot-preview[bot]
9d02f2687d ⬆️ Bump cypress from 3.8.0 to 3.8.1
Bumps [cypress](https://github.com/cypress-io/cypress) from 3.8.0 to 3.8.1.
- [Release notes](https://github.com/cypress-io/cypress/releases)
- [Commits](https://github.com/cypress-io/cypress/compare/v3.8.0...v3.8.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-28 00:13:41 +00:00
Liyas Thomas
9f2ecd619f ✏️ Typo on CLI repo link 2019-12-26 13:31:01 +05:30
Liyas Thomas
6b899b2ce0 Merge pull request #459 from gabschne/i18n
i18n(de-DE): improve some translations
2019-12-26 08:32:55 +05:30
gabschne
d5cb66079b i18n(de-DE): improve some translations 2019-12-26 01:56:24 +01:00
gabschne
5690599241 i18n(de-DE): improve some translations 2019-12-26 01:01:23 +01:00
Liyas Thomas
3ee2bae78d 🐛 Fixes #456 2019-12-23 13:15:30 +05:30
Liyas Thomas
21041fc6da Merge pull request #451 from liyasthomas/doc
API documentation page
2019-12-23 08:24:53 +05:30
Liyas Thomas
2b40db285e Introducing API Documentation 2019-12-23 08:16:45 +05:30
Liyas Thomas
c3a6cc133f Introducing API Documentation 2019-12-22 23:28:36 +05:30
Liyas Thomas
10f6bb9cc6 🐛 Added error handler 2019-12-22 15:49:26 +05:30
Liyas Thomas
5589c61423 🎉 Display actual Documentation 2019-12-22 15:26:13 +05:30
Liyas Thomas
158c34d091 Initial iteration on Collection 2019-12-22 09:20:38 +05:30
Liyas Thomas
99f182599a Merge pull request #455 from hmtanbir/i18n
bn-BD i18n
2019-12-21 21:23:02 +05:30
hmtanbir
216bd4e7b4 add bangla i18n 2019-12-21 10:30:04 +06:00
Liyas Thomas
ecfc7c84c3 Merge branch 'doc' of https://github.com/liyasthomas/postwoman into doc 2019-12-21 08:44:52 +05:30
Liyas Thomas
d4819bcd0a 🎉 Added navigation link to Documentation page in default layour 2019-12-21 08:44:10 +05:30
Liyas Thomas
b067a4723b Merge branch 'master' into doc 2019-12-21 08:14:58 +05:30
Liyas Thomas
9217ebf75e Merge pull request #450 from liyasthomas/dependabot/npm_and_yarn/nuxtjs/axios-5.9.0
⬆️ Bump @nuxtjs/axios from 5.8.0 to 5.9.0
2019-12-21 06:28:34 +05:30
dependabot-preview[bot]
305a8f74b0 ⬆️ Bump @nuxtjs/axios from 5.8.0 to 5.9.0
Bumps [@nuxtjs/axios](https://github.com/nuxt-community/axios-module) from 5.8.0 to 5.9.0.
- [Release notes](https://github.com/nuxt-community/axios-module/releases)
- [Changelog](https://github.com/nuxt-community/axios-module/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/nuxt-community/axios-module/compare/v5.8.0...v5.9.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-21 00:33:16 +00:00
Liyas Thomas
a3666b3d44 ⬆️ Bump nuxt from 2.10.2 to 2.11.0 (#449)
⬆️ Bump nuxt from 2.10.2 to 2.11.0

Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com>
2019-12-21 06:01:18 +05:30
dependabot-preview[bot]
182bca9361 ⬆️ Bump nuxt from 2.10.2 to 2.11.0
Bumps [nuxt](https://github.com/nuxt/nuxt.js) from 2.10.2 to 2.11.0.
- [Release notes](https://github.com/nuxt/nuxt.js/releases)
- [Changelog](https://github.com/nuxt/nuxt.js/blob/dev/RELEASE_PLAN.md)
- [Commits](https://github.com/nuxt/nuxt.js/compare/v2.10.2...v2.11.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-21 00:13:26 +00:00
Liyas Thomas
f0868f383b 🎉 API documentation page 2019-12-20 14:40:16 +05:30
Liyas Thomas
001c4818a0 ✏️ Added badge name 2019-12-20 10:05:59 +05:30
Liyas Thomas
0d47a1a1c2 ✏️ Fixed table width 2019-12-20 09:54:13 +05:30
Liyas Thomas
75f4d8e09c ✏️ Put badges inside table 2019-12-20 09:50:48 +05:30
Liyas Thomas
2e5d8b330b ✏️ Updated wwith organization and add-ons links 2019-12-20 09:08:39 +05:30
Liyas Thomas
42e0200956 🐛 Fixed #446 and crash on closing file picker for raw request body without selecting a file 2019-12-20 08:19:14 +05:30
Liyas Thomas
780bc55a96 Various UI tweaks (#439)
Various UI tweaks

Co-authored-by: Liyas Thomas <liyasthomas@gmail.com>
2019-12-18 00:54:02 +05:30
Liyas Thomas
bc6ea34f14 🎨 Various UI tweaks 2019-12-18 00:43:15 +05:30
Liyas Thomas
ae237f1ad3 🐛 Fixes #435 2019-12-17 06:45:24 +05:30
Liyas Thomas
7451a0bcc4 Merge pull request #438 from liyasthomas/i18n
i18n
2019-12-17 06:03:31 +05:30
Liyas Thomas
ffed1dbc90 Merge branch 'master' into i18n 2019-12-17 05:50:19 +05:30
Liyas Thomas
3ffe5559e7 🌐 Added more internationalization vocabulary 2019-12-16 23:26:46 +05:30
Liyas Thomas
2c93e2f783 🌐 Added more internationalization vocabulary 2019-12-16 23:21:32 +05:30
Liyas Thomas
7ef5919ba1 Burmese translation added (#437)
Burmese translation added
2019-12-16 21:12:54 +05:30
Zayar Tun
4c19a7d598 Burmese translation added 2019-12-16 21:46:00 +06:30
Liyas Thomas
feb782270b 🎨 Toast button now align to end 2019-12-15 21:46:55 +05:30
Liyas Thomas
29c6109ea3 Merge pull request #432 from liyasthomas/refactor/enhancements
chore: stick to Vue.js best practices
2019-12-15 19:44:20 +05:30
jamesgeorge007
ffe4796f2c refactor: make use of v-bind directive shorthand
vue.js best practices
2019-12-15 19:23:53 +05:30
jamesgeorge007
5762cea9bd refactor: make use of v-bind directive shorthand
vue.js best practices
2019-12-15 19:23:09 +05:30
jamesgeorge007
7b0a1c4266 refactor: make use of v-bind directive shorthand
vue.js best practices
2019-12-15 19:22:37 +05:30
jamesgeorge007
d2086b1661 refactor: make use of v-bind directive shorthand
vue.js best practices
2019-12-15 19:21:25 +05:30
jamesgeorge007
c50cbc9750 refactor: make use of v-bind directive shorthand
vue.js best practices
2019-12-15 19:20:31 +05:30
jamesgeorge007
24ee395b73 refactor: make use of v-bind directive shorthand
vue.js best practices
2019-12-15 19:14:44 +05:30
jamesgeorge007
48bd772171 refactor: make use of v-bind directive shorthand
vue.js best practices
2019-12-15 19:13:53 +05:30
jamesgeorge007
928ace5ba6 refactor: use property shorthand for consistency 2019-12-15 19:03:39 +05:30
jamesgeorge007
0791d196d4 refactor: use property shorthand for consistency 2019-12-15 19:03:18 +05:30
jamesgeorge007
9223044967 refactor: use property shorthand for consistency 2019-12-15 19:02:37 +05:30
jamesgeorge007
998a925fd1 refactor: make request component self closing 2019-12-15 19:02:03 +05:30
jamesgeorge007
f49bfb4d74 refactor: use property shorthand for consistency 2019-12-15 19:01:31 +05:30
jamesgeorge007
b20cb040b0 refactor: make collection component self closing 2019-12-15 19:00:31 +05:30
jamesgeorge007
82096f3a1e refactor: use property shorthand for consistency 2019-12-15 18:59:45 +05:30
jamesgeorge007
fcc6f5aa76 refactor: make history component self closing 2019-12-15 18:55:29 +05:30
jamesgeorge007
4c82ef89fb refactor: make component tag self closing 2019-12-15 18:52:34 +05:30
Liyas Thomas
9b7141b1f4 Styled select input (#431)
Styled select input

Co-authored-by: Liyas Thomas <liyasthomas@gmail.com>
2019-12-15 05:50:47 +05:30
Liyas Thomas
965133d6e2 🎨 Styled select input 2019-12-15 05:29:03 +05:30
Liyas Thomas
498b3f80bf Bumped dependencies and Improved UI contrast (#430)
Bumped dependencies and Improved UI contrast

Co-authored-by: Liyas Thomas <liyasthomas@gmail.com>
2019-12-14 15:44:50 +05:30
Liyas Thomas
6cf9044db6 🎨 Updated hex to rgba 2019-12-14 15:33:50 +05:30
Liyas Thomas
acc80cff74 ⬆️ Bumped dependencies
🎨 Improved UI contrast
2019-12-14 15:23:10 +05:30
Liyas Thomas
9e2407b7f1 Merge pull request #429 from liyasthomas/dependabot/npm_and_yarn/cypress-3.8.0
⬆️ Bump cypress from 3.7.0 to 3.8.0
2019-12-14 07:40:42 +05:30
dependabot-preview[bot]
6da9beb273 ⬆️ Bump cypress from 3.7.0 to 3.8.0
Bumps [cypress](https://github.com/cypress-io/cypress) from 3.7.0 to 3.8.0.
- [Release notes](https://github.com/cypress-io/cypress/releases)
- [Commits](https://github.com/cypress-io/cypress/compare/v3.7.0...v3.8.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-14 00:14:17 +00:00
Liyas Thomas
1104f22f19 Merge pull request #428 from liyasthomas/i18n
I18n
2019-12-13 13:52:15 +05:30
Liyas Thomas
cd272ab0c8 Merge pull request #427 from reefqi037/I18n-Japanese-Translation
I18n Japanese translation added
2019-12-13 13:09:48 +05:30
Abdul Rifqi Al Abqary
34dbec4a5c add newline 2019-12-13 15:38:09 +09:00
Abdul Rifqi Al Abqary
3f0608fd9c I18n Japanese translation added 2019-12-13 15:34:59 +09:00
Liyas Thomas
17a6b03d00 Even (#424)
Even

Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com>
Co-authored-by: Liyas Thomas <liyasthomas@gmail.com>
Co-authored-by: Alexandre Reis <alex.cst.reis@gmail.com>
Co-authored-by: Andrew Bastin <andrewbastin.k@gmail.com>
2019-12-13 04:56:15 +05:30
Liyas Thomas
5efb921a6b I18n (#423)
I18n

Co-authored-by: William Surya Permana <zarambie_game@yahoo.com>
Co-authored-by: N Jannasch <NJannasch@users.noreply.github.com>
2019-12-13 04:48:26 +05:30
Liyas Thomas
01d4443a4f I18n German translation added (#422)
I18n German translation added
2019-12-13 04:38:15 +05:30
N Jannasch
1591205f46 Create de-DE.js 2019-12-12 17:35:59 -05:00
N Jannasch
ad005d99d2 Create de-DE.js 2019-12-12 17:34:37 -05:00
Andrew Bastin
27e1541a6d Merge pull request #421 from AndrewBastin/feat/header_completion
Header key autocompletion
2019-12-11 18:55:13 -05:00
Andrew Bastin
9fb966f705 GraphQL header keys now offer completion 2019-12-11 18:34:46 -05:00
Andrew Bastin
096b981247 Updated default Autocomplete Component placeholder 2019-12-11 17:46:13 -05:00
Andrew Bastin
cea9ac3965 Header Key values now display suggestions for common headers 2019-12-11 17:29:53 -05:00
Andrew Bastin
f446c9acc1 Generalized AutoComplete Component code 2019-12-11 17:28:32 -05:00
Liyas Thomas
870521c004 Merge pull request #410 from adevr/bug/save-request
Fixing bug on request saving
2019-12-11 09:07:36 +05:30
Liyas Thomas
05114b6dfc Even 2019-12-11 08:58:54 +05:30
Liyas Thomas
945a83625d 🐛 Fixed broken i18n route on toggle 2019-12-11 08:38:26 +05:30
Liyas Thomas
e2d7c0225e 🐛 Fixes #417 2019-12-11 07:07:31 +05:30
Liyas Thomas
55e5444a71 Merge pull request #416 from williamsp/patch-1
Update id-ID.js
2019-12-10 22:15:45 +05:30
William Surya Permana
a3e8a4a41f Update id-ID.js
Fix untranslated "proxy"
2019-12-10 23:41:41 +07:00
Liyas Thomas
b91798e8b8 Merge pull request #414 from williamsp/patch-1
Improving translation for id-ID
2019-12-10 22:03:43 +05:30
Liyas Thomas
d284002803 Zap 2019-12-10 21:58:08 +05:30
William Surya Permana
74e6bf50b1 Improving translation for id-ID
Fix word choice, and use capitalization case from en-US (no longer Capitalized Each Word)
2019-12-10 23:25:41 +07:00
Liyas Thomas
60ba539104 🐛 Fixed opaque select element, curved modals, better disabled color scheme 2019-12-09 09:40:47 +05:30
Liyas Thomas
979909ad57 🎨 Updated color schemes 2019-12-09 09:05:03 +05:30
adevr
c4bd471516 Fixing bug on request saving
This bug appeared when saving a request with no collections available
2019-12-08 23:21:53 +00:00
Liyas Thomas
cd8b4d0dd1 💫 Updating animations and transitions 2019-12-08 22:38:32 +05:30
Liyas Thomas
d018ebda7e 🐛 Fixed abnormal toast margin on mobile devices 2019-12-08 16:10:26 +05:30
Liyas Thomas
5b9aeb70d9 🐛 Fixed #409 2019-12-08 16:05:20 +05:30
Liyas Thomas
35d551f05e 🐛 Fixed toast poition on mobile devices 2019-12-08 10:01:33 +05:30
Liyas Thomas
a32eb24f8c Bottom navbar on mobile device, minor UI revamp 2019-12-08 09:20:19 +05:30
Liyas Thomas
5c7f3c282b Bottom navbar on mobile device, minor UI revamp 2019-12-08 09:20:09 +05:30
Liyas Thomas
c19c399508 🎉 Added icon button animation 2019-12-08 01:08:49 +05:30
Liyas Thomas
4d24d49a0b ✏️ Updated features list 2019-12-07 10:30:28 +05:30
Liyas Thomas
cbe214113c Merge pull request #406 from liyasthomas/dependabot/npm_and_yarn/vue-virtual-scroll-list-1.4.4
⬆️ Bump vue-virtual-scroll-list from 1.4.3 to 1.4.4
2019-12-07 07:16:16 +05:30
Liyas Thomas
fdc2d2cb17 Merge branch 'master' into dependabot/npm_and_yarn/vue-virtual-scroll-list-1.4.4 2019-12-07 06:43:49 +05:30
Liyas Thomas
eae1d22a2f Merge pull request #405 from liyasthomas/dependabot/npm_and_yarn/nuxt-i18n-6.4.1
⬆️ Bump nuxt-i18n from 6.4.0 to 6.4.1
2019-12-07 06:42:40 +05:30
dependabot-preview[bot]
3d66a7deb9 ⬆️ Bump nuxt-i18n from 6.4.0 to 6.4.1
Bumps [nuxt-i18n](https://github.com/nuxt-community/nuxt-i18n) from 6.4.0 to 6.4.1.
- [Release notes](https://github.com/nuxt-community/nuxt-i18n/releases)
- [Changelog](https://github.com/nuxt-community/nuxt-i18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nuxt-community/nuxt-i18n/compare/v6.4.0...v6.4.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-07 01:02:36 +00:00
dependabot-preview[bot]
a4022dc70c ⬆️ Bump vue-virtual-scroll-list from 1.4.3 to 1.4.4
Bumps [vue-virtual-scroll-list](https://github.com/tangbc/vue-virtual-scroll-list) from 1.4.3 to 1.4.4.
- [Release notes](https://github.com/tangbc/vue-virtual-scroll-list/releases)
- [Commits](https://github.com/tangbc/vue-virtual-scroll-list/compare/v1.4.3...v1.4.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-07 01:02:35 +00:00
Liyas Thomas
f82c0cdb4f Merge pull request #407 from liyasthomas/dependabot/npm_and_yarn/nuxtjs/google-analytics-2.2.2
⬆️ Bump @nuxtjs/google-analytics from 2.2.1 to 2.2.2
2019-12-07 06:30:42 +05:30
dependabot-preview[bot]
6e208c3766 ⬆️ Bump @nuxtjs/google-analytics from 2.2.1 to 2.2.2
Bumps [@nuxtjs/google-analytics](https://github.com/nuxt-community/analytics-module) from 2.2.1 to 2.2.2.
- [Release notes](https://github.com/nuxt-community/analytics-module/releases)
- [Changelog](https://github.com/nuxt-community/analytics-module/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nuxt-community/analytics-module/compare/v2.2.1...v2.2.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-12-07 00:15:10 +00:00
Liyas Thomas
777fe9b42a Merge pull request #404 from liyasthomas/i18n
I18n
2019-12-07 02:31:13 +05:30
yubathom
afbf21c47f Fix buttons translations 2019-12-06 16:44:20 -03:00
Gustavo Bezerra
461c30580f Fixing messages in pt-BR 2019-12-06 16:17:38 -03:00
Gustavo Bezerra
82cdcc1cce Improved lang pt-BR. Fixing translate 2019-12-06 16:17:38 -03:00
Gustavo Bezerra
3efcaf4921 Improved lang pt-BR 2019-12-06 16:17:37 -03:00
Liyas Thomas
2be4b672d5 🎨 Text selection color now matches theme (accent color) 2019-12-06 08:59:15 +05:30
Liyas Thomas
2b4d743d79 💄 Scoped styles 2019-12-06 07:11:38 +05:30
Liyas Thomas
c80634b026 Added preload to scripts, sttyles and fonts. Moved font assets to static folder 2019-12-05 06:17:41 +05:30
Liyas Thomas
0028d03e1b 🎨 Minor UI update 2019-12-05 05:51:43 +05:30
Liyas Thomas
d687c9f36d Custom methods support (#400)
Custom methods support

Co-authored-by: Liyas Thomas <liyasthomas@gmail.com>
2019-12-04 21:51:59 +05:30
Liyas Thomas
5fbf4879ae 🐛 Fixes #399 2019-12-04 21:43:16 +05:30
Liyas Thomas
a719dff1f7 Updating tests 2019-12-04 21:41:58 +05:30
Liyas Thomas
d99170f0d9 Merge branch 'master' into methods 2019-12-04 20:34:19 +05:30
Liyas Thomas
7d5a8499c3 🎉 Custom methods support 2019-12-04 20:19:47 +05:30
Liyas Thomas
1cfaf0bd57 Merge pull request #391 from liyasthomas/app-ui
App UI
2019-12-02 23:00:45 +05:30
Liyas Thomas
bc3c608277 🐛 Fixed connect icon 2019-12-02 22:52:11 +05:30
Liyas Thomas
2f09995306 🎨 Hid sidebar toggle button 2019-12-02 22:29:10 +05:30
Liyas Thomas
72acdeaab9 Improved icon toggle 2019-12-02 20:50:20 +05:30
Liyas Thomas
0bfc0256a6 Optimized UI components 2019-12-02 18:05:10 +05:30
Liyas Thomas
c1a733af53 💄 Minor stylings 2019-12-02 17:12:30 +05:30
Liyas Thomas
c3544076ba 🎉 Toggle sidebar 2019-12-02 13:49:52 +05:30
Liyas Thomas
ae528f6302 🎨 Redesigned color swatches 2019-12-01 06:20:37 +05:30
Liyas Thomas
6a63325f10 Merge pull request #383 from liyasthomas/i18n
i18n
2019-12-01 04:23:24 +05:30
Liyas Thomas
395d244e04 Merge branch 'master' into i18n 2019-12-01 03:29:29 +05:30
Liyas Thomas
d9f0e61375 Added Turkish Language Support (#382)
Added Turkish Language Support
2019-12-01 03:27:14 +05:30
Ali Anıl Koçak
b3751ec4bf nuxt.config.js edited for Turkish Language support 2019-11-30 21:39:58 +00:00
Ali Anıl Koçak
a11a24bfe2 Create tr-TR.js 2019-11-30 21:38:49 +00:00
Liyas Thomas
b31de72ccc Translated new words to Farsi lang (#380)
Translated new words to Farsi lang
2019-11-30 18:56:00 +05:30
Hossein Nedaee
fa4c08dcc5 Translated new words to Farsi lang 2019-11-30 16:44:02 +03:30
Liyas Thomas
d0aa75c792 Two Way Data Binding (v-model) to Ace Editor component (#379)
Two Way Data Binding (v-model) to Ace Editor component
2019-11-30 13:56:40 +05:30
Andrew Bastin
492a5bd5e9 Merge branch 'master' into feat/two_way_ace 2019-11-30 02:42:35 -05:00
Liyas Thomas
772fdd5e87 Merge pull request #378 from peterpeterparker/twitter-card-img
fix: twitter summary card image url
2019-11-30 13:10:33 +05:30
Andrew Bastin
c4116d6819 Added placeholder pre-request script value 2019-11-30 02:26:00 -05:00
Andrew Bastin
050a53af0d Changed pre request script field to use the ace-editor 2019-11-30 02:24:31 -05:00
peterpeterparker
a42136c419 fix: twitter summary card image url 2019-11-30 08:22:54 +01:00
Andrew Bastin
c5d5c15b11 Changed the GQL query entry to use ace-editor 2019-11-30 02:09:34 -05:00
Andrew Bastin
2360803e44 Added v-model support to ace-editor 2019-11-30 02:08:09 -05:00
Liyas Thomas
3f5752247b Added nav shortcuts to GraphQL query and response, updated Graph… (#377)
Added nav shortcuts to GraphQL query and response, updated GraphQL shortcut icons
2019-11-30 08:40:59 +05:30
Andrew Bastin
1e85a649db Added shortcuts to query and response, updated shortcut icons 2019-11-29 21:56:58 -05:00
Liyas Thomas
84eed2aab2 Bump cypress from 3.6.1 to 3.7.0 (#376)
Bump cypress from 3.6.1 to 3.7.0

Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com>
Co-authored-by: Liyas Thomas <liyascthomas@gmail.com>
2019-11-30 06:22:24 +05:30
Liyas Thomas
32f5e784e8 Merge branch 'master' into dependabot/npm_and_yarn/cypress-3.7.0 2019-11-30 06:10:29 +05:30
Liyas Thomas
53e391982f Bump vuex-persist from 2.1.1 to 2.2.0 (#375)
Bump vuex-persist from 2.1.1 to 2.2.0

Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com>
Co-authored-by: Liyas Thomas <liyascthomas@gmail.com>
2019-11-30 06:05:48 +05:30
Liyas Thomas
0f8adf13ae Merge branch 'master' into dependabot/npm_and_yarn/cypress-3.7.0 2019-11-30 05:59:25 +05:30
Liyas Thomas
a91e265097 Merge branch 'master' into dependabot/npm_and_yarn/vuex-persist-2.2.0 2019-11-30 05:58:07 +05:30
Liyas Thomas
b7fc72004f ⚗️ Page animation 2019-11-30 05:54:47 +05:30
dependabot-preview[bot]
9927239ec9 Bump cypress from 3.6.1 to 3.7.0
Bumps [cypress](https://github.com/cypress-io/cypress) from 3.6.1 to 3.7.0.
- [Release notes](https://github.com/cypress-io/cypress/releases)
- [Commits](https://github.com/cypress-io/cypress/compare/v3.6.1...v3.7.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-30 00:14:41 +00:00
dependabot-preview[bot]
cff94a1672 Bump vuex-persist from 2.1.1 to 2.2.0
Bumps [vuex-persist](https://github.com/championswimmer/vuex-persist) from 2.1.1 to 2.2.0.
- [Release notes](https://github.com/championswimmer/vuex-persist/releases)
- [Changelog](https://github.com/championswimmer/vuex-persist/blob/master/CHANGELOG.md)
- [Commits](https://github.com/championswimmer/vuex-persist/compare/v2.1.1...v2.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-30 00:13:42 +00:00
Liyas Thomas
a0191bafe7 🐛 Fixed browser default shortcut mapping fixes #374 2019-11-29 14:53:44 +05:30
Liyas Thomas
f2262c0e19 📸 Updated screenshots 2019-11-29 12:19:17 +05:30
Liyas Thomas
068d251b64 Lint 2019-11-29 11:25:13 +05:30
Liyas Thomas
1872dacb5e Use GraphQL logo for GraphQL tab (#371)
Use GraphQL logo for GraphQL tab
2019-11-29 08:42:01 +05:30
Liyas Thomas
ef162dd963 Merge pull request #372 from EdikWang/i18n
I18n
2019-11-29 07:39:44 +05:30
Edik
2a19285d3c Added font assets 2019-11-29 09:58:10 +08:00
NBTX
38a9a75b2d Use GraphQL logo for GraphQL tab 2019-11-28 19:48:49 -06:00
Liyas Thomas
6959a4510e I18n (#366)
I18n

Co-authored-by: wahid <wahid@gamatechno.com>
Co-authored-by: LaurentBrieu <laurent.brieu@mediapart.fr>
Co-authored-by: Abdul R. Wahid <wahid.dulrohman@gmail.com>
Co-authored-by: adlpaf <adlpaf@angels>
2019-11-29 04:45:43 +05:30
Liyas Thomas
fe383d32a7 optimized font assets 2019-11-29 04:38:01 +05:30
Liyas Thomas
560bdb139a Added font assets 2019-11-29 04:24:36 +05:30
Liyas Thomas
fe14286bc8 Merge pull request #369 from wahwahid/i18n
Update i18n keywords for Bahasa Indonesia
2019-11-28 22:51:06 +05:30
Liyas Thomas
7584b489ac Merge pull request #368 from adlpaf/i18n
Intent to translate to Spanish on I18n
2019-11-28 22:43:16 +05:30
wahwahid
84461ffa35 Fix Capitalize in Bahasa Indonesia Support Lang 2019-11-29 00:02:07 +07:00
adlpaf
d89c652622 Translated to Spanish 2019-11-28 13:56:56 -03:00
adlpaf
9d19d26d8e Translated to Spanish 2019-11-28 13:43:34 -03:00
wahwahid
e307d51f24 Update keywords i18n for Bahasa Indonesia 2019-11-28 23:15:32 +07:00
Edik
4632e281a6 Merge pull request #3 from liyasthomas/i18n
I18n
2019-11-28 23:57:23 +08:00
Liyas Thomas
ab4f961795 Merge branch 'master' into i18n 2019-11-28 21:20:19 +05:30
Abdul R. Wahid
9859a34e90 Merge pull request #1 from liyasthomas/i18n
I18n
2019-11-28 22:35:41 +07:00
Liyas Thomas
b10a209daf Improving performance 2019-11-28 20:41:52 +05:30
Liyas Thomas
2a81c2611b Merge pull request #364 from LaurentBrieu/add-translations-for-fr-en-catalogues
Add translations for FR/EN catalogues
2019-11-28 18:07:22 +05:30
Edik
8d98c8ad16 Merge pull request #1 from liyasthomas/i18n
I18n
2019-11-28 20:31:10 +08:00
LaurentBrieu
1c12c66b31 Add translations for FR/EN catalogues 2019-11-28 13:27:52 +01:00
Liyas Thomas
cb79567942 Merge pull request #362 from wahwahid/i18n-id
Added Bahasa Indonesia language support
2019-11-28 08:31:24 +05:30
wahid
c35a9c64f6 Added Bahasa Indonesia language support 2019-11-28 09:51:42 +07:00
Liyas Thomas
95832eb657 Merge pull request #361 from liyasthomas/i18n
i18n
2019-11-28 08:14:30 +05:30
Liyas Thomas
ee53c12c35 Merge branch 'master' into i18n 2019-11-28 08:07:01 +05:30
Liyas Thomas
c3d2d928b3 Add Simplified Chinese language (#360)
Add Simplified Chinese language
2019-11-28 08:01:53 +05:30
Liyas Thomas
87e598b5f0 Merge branch 'i18n' into i18n 2019-11-28 07:48:39 +05:30
Liyas Thomas
f61cbba8cb 🐛 Fixed i18n routing 2019-11-28 07:45:35 +05:30
Edik
a4089efe85 Add Simplified Chinese language 2019-11-28 09:38:31 +08:00
Liyas Thomas
781d8e3b68 Merge pull request #359 from tetri/patch-1
Added Brazilian Portuguese language support
2019-11-28 04:49:14 +05:30
Tetri Mesquita
cf81a970cc Added Brazilian Portuguese language support 2019-11-27 20:01:34 -03:00
Liyas Thomas
367d73ef23 i18n 2019-11-28 00:38:23 +05:30
Tetri Mesquita
314084d092 Added Brazilian Portuguese language support 2019-11-27 15:59:09 -03:00
Liyas Thomas
e4441d129c Merge pull request #357 from hosseinnedaee/i18n
Added Farsi language support
2019-11-27 23:28:57 +05:30
Hossein Nedaee
292550f6b5 Added Farsi language support 2019-11-27 21:03:02 +03:30
Liyas Thomas
93364afc98 Merge pull request #355 from thomasbnt/i18n
Adding french language basic
2019-11-27 21:34:37 +05:30
Thomas Bnt
558b961afa Forgotten space 2019-11-27 16:55:15 +01:00
Thomas Bnt
d99b5cf525 Added French language (basic config) 2019-11-27 16:49:59 +01:00
Liyas Thomas
c75e4a52eb Updated test 2019-11-27 20:22:32 +05:30
Liyas Thomas
0ac01fe8e5 Updated test 2019-11-27 20:15:47 +05:30
Liyas Thomas
13615e06e9 🐛 Fixes #353 2019-11-27 19:52:03 +05:30
Liyas Thomas
623b177eb0 Basic i18n support (#351)
Basic i18n support
2019-11-27 17:40:32 +05:30
Liyas Thomas
a74522c465 Merge branch 'master' into i18n 2019-11-27 17:33:16 +05:30
Liyas Thomas
4f5788fe31 Merge pull request #344 from athul/athul-patch
♻️ Refactor Functions
2019-11-27 17:22:30 +05:30
Liyas Thomas
d739af3d4b Merge branch 'master' into athul-patch 2019-11-27 17:14:50 +05:30
Liyas Thomas
3a2284cf99 ES6 2019-11-27 17:04:43 +05:30
Liyas Thomas
9019babf6d Merge branch 'master' into i18n 2019-11-27 15:44:02 +05:30
Liyas Thomas
5382cd8d5f 🐛 Fixed SSE connection closing issues. Fixes #349 2019-11-27 15:35:39 +05:30
Liyas Thomas
37c41086d2 Undo header/param/body param deletion (#350)
Undo header/param/body param deletion
2019-11-27 15:09:56 +05:30
Liyas Thomas
2697cce6dd 🎉 Basic i18n support 2019-11-27 14:15:11 +05:30
Andrew Bastin
294b26787b Added undo functionality to the index page 2019-11-26 23:01:03 -05:00
Andrew Bastin
b67de81616 Added undo button for undoing removing headers 2019-11-26 22:46:33 -05:00
Liyas Thomas
36568d5720 🐛 Fixed build + refactored all js files 2019-11-27 06:54:32 +05:30
Liyas Thomas
dcf1966719 Merge branch 'master' into athul-patch 2019-11-27 05:57:53 +05:30
Liyas Thomas
33cbc9b525 Added ability to run GraphQL queries (#346)
Added ability to run GraphQL queries
2019-11-27 04:52:56 +05:30
Andrew Bastin
d2115ab004 Added ability to copy GQL response 2019-11-26 16:55:43 -05:00
Andrew Bastin
9cbd6ea7b7 Added ability to copy GQL query 2019-11-26 16:48:13 -05:00
Andrew Bastin
ded69f979e Entered GQL query is persisted 2019-11-26 15:44:15 -05:00
Andrew Bastin
7fab6f4732 Added query field to the GQL state 2019-11-26 15:43:06 -05:00
Andrew Bastin
9ad822577b Added ability to do GraphQL queries 2019-11-26 15:37:41 -05:00
Athul Cyriac Ajay
bdaac40435 Deleting Comments
Co-Authored-By: James George <jamesgeorge998001@gmail.com>
2019-11-26 21:03:53 +05:30
James George
19b43e152a Merge branch 'master' into athul-patch 2019-11-26 20:57:23 +05:30
Liyas Thomas
c4c320da83 🚨 Lint 2019-11-26 20:01:48 +05:30
athul
43cd6504b6 Edited as per @jamesgeorge007 's said 2019-11-26 19:08:28 +05:30
athul
cb8734bba7 Revert "Resolves @jamegeorge007 's Review"
This reverts commit 57860c17d9.
2019-11-26 19:03:06 +05:30
athul
57860c17d9 Resolves @jamegeorge007 's Review 2019-11-26 18:59:19 +05:30
Athul Cyriac Ajay
c56c162045 Update assets/js/curlparser.js
Co-Authored-By: James George <jamesgeorge998001@gmail.com>
2019-11-26 18:50:42 +05:30
Liyas Thomas
249407403d Merge branch 'master' into athul-patch 2019-11-26 18:44:31 +05:30
Liyas Thomas
1aa5ec6aa4 Merge pull request #345 from NBTX/master
Add Proxy URL option
2019-11-26 18:34:47 +05:30
athul
f129ead9a0 Merge branch 'athul-patch' of github.com:athul/postwoman into athul-patch 2019-11-26 18:32:03 +05:30
athul
321a45615a Formatted 2019-11-26 18:31:55 +05:30
NBTX
dd280732d1 Add Proxy URL option 2019-11-26 06:53:12 -06:00
Athul Cyriac Ajay
8966e6fd55 Delete yarn.lock 2019-11-26 18:22:41 +05:30
athul
3523b5f2c7 ♻️ Refactor Functions 2019-11-26 18:19:51 +05:30
Liyas Thomas
2f727b1a1e refactor: minor improvements (#343)
refactor: minor improvements
2019-11-26 17:44:11 +05:30
jamesgeorge007
6e537eed58 fix: make headers property writable 2019-11-26 15:41:53 +05:30
jamesgeorge007
ffb8fd0172 refactor(index): use directive shorthand notation
for consistency
2019-11-26 14:37:32 +05:30
jamesgeorge007
ba1410c7f4 refactor(index): self closing components 2019-11-26 14:34:40 +05:30
jamesgeorge007
61f8e36383 refactor(folder): self closing component 2019-11-26 14:32:18 +05:30
jamesgeorge007
20a7094d33 refactor(index): us Array.includes 2019-11-26 14:27:51 +05:30
jamesgeorge007
06d7534462 refactor(realtime): replace instances of var with const 2019-11-26 14:25:40 +05:30
jamesgeorge007
b3680224cc refactor(index): replace instances of var with const 2019-11-26 14:24:27 +05:30
jamesgeorge007
113bf14718 refactor(graphql): replace instances of var with const 2019-11-26 14:20:57 +05:30
Andrew Bastin
937df4486e Merge pull request #341 from AndrewBastin/feat/gql_req_header
GraphQL Request Headers
2019-11-26 00:06:59 -05:00
Andrew Bastin
5f79ca2872 Fixed header inclusion mistake 2019-11-25 23:42:41 -05:00
Andrew Bastin
e999d7428a Merge remote-tracking branch 'upstream/master' into feat/gql_req_header 2019-11-25 22:52:23 -05:00
Andrew Bastin
146df237f2 Added Headers for GraphQL requests 2019-11-25 22:48:36 -05:00
Liyas Thomas
d802945ec7 Separate dockerfile layers and add volume (#340)
Separate dockerfile layers and add volume
2019-11-26 08:56:52 +05:30
Andrew Bastin Kalloor Biju
122782f244 Added headers field to state and added mutations to handle header list updates 2019-11-25 22:25:22 -05:00
Vítor Xoteslem
ff006a254a Separate dockerfile layers and add volume 2019-11-26 00:03:55 -03:00
Liyas Thomas
c1d11e7489 🐛 Fixed incorrect badge label 2019-11-26 07:41:03 +05:30
Liyas Thomas
7d78d34de0 🐛 Fixed incorrect badge label 2019-11-25 21:57:15 +05:30
Liyas Thomas
5f97f49f28 ✏️ Writing docs 2019-11-25 20:45:13 +05:30
Liyas Thomas
f63bb11cc3 🍭 Updated funding links 2019-11-25 09:36:43 +05:30
Liyas Thomas
b23f0a9c16 Refactoring code (#332)
Refactoring code

Co-authored-by: Liyas Thomas <liyasthomas@gmail.com>
2019-11-25 06:09:58 +05:30
Liyas Thomas
e609300533 Merge branch 'master' into refactor 2019-11-25 06:03:39 +05:30
Liyas Thomas
f623b31220 ♻️ Refactoring code 2019-11-25 05:51:48 +05:30
Liyas Thomas
a17239ca31 ♻️ Refactoring code 2019-11-25 05:44:44 +05:30
Liyas Thomas
f2a35a7716 SSE (#330)
SSE

Co-authored-by: Liyas Thomas <liyasthomas@gmail.com>
2019-11-25 05:20:41 +05:30
Liyas Thomas
0383403cce Adds Server Sent Events debug support 2019-11-25 05:13:35 +05:30
Liyas Thomas
57b71ce4ea Merge branch 'sse' of https://github.com/liyasthomas/postwoman into sse 2019-11-24 18:46:01 +05:30
Liyas Thomas
f6752e9743 SSE mvp 2019-11-24 18:45:26 +05:30
Liyas Thomas
45fa84d5ae Merge branch 'master' into sse 2019-11-24 17:39:32 +05:30
Liyas Thomas
873b97b052 🎉 Initial SSE MVP 2019-11-24 08:48:50 +05:30
Liyas Thomas
7a25f4c13c 💫 Updated Support us section 2019-11-23 18:15:15 +05:30
Liyas Thomas
48e9171153 Improving accessibility 2019-11-23 15:25:30 +05:30
Liyas Thomas
1dbea4d39a Initial SSE MVP 2019-11-23 14:31:15 +05:30
Liyas Thomas
edba562a99 Added download & expand button for GraphQL schema response 2019-11-23 10:31:53 +05:30
Liyas Thomas
60368341ed ⬆️ Bump vue-virtual-scroll-list from 1.4.2 to 1.4.3 (#328)
⬆️ Bump vue-virtual-scroll-list from 1.4.2 to 1.4.3

Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com>
2019-11-23 08:34:52 +05:30
dependabot-preview[bot]
ab24faaa55 ⬆️ Bump vue-virtual-scroll-list from 1.4.2 to 1.4.3
Bumps [vue-virtual-scroll-list](https://github.com/tangbc/vue-virtual-scroll-list) from 1.4.2 to 1.4.3.
- [Release notes](https://github.com/tangbc/vue-virtual-scroll-list/releases)
- [Commits](https://github.com/tangbc/vue-virtual-scroll-list/compare/v1.4.2...v1.4.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-23 00:13:30 +00:00
Liyas Thomas
e79b113907 Merge pull request #322 from AndrewBastin/feat/gql_proxy
GraphQL introspection requests now support and respect proxying
2019-11-21 23:31:20 +05:30
Liyas Thomas
fb69fcee3c Merge branch 'master' into feat/gql_proxy 2019-11-21 22:11:36 +05:30
Andrew Bastin
41ff83821b GraphQL introspection requests now support and respect Proxying 2019-11-21 11:31:58 -05:00
Liyas Thomas
463ef82255 Added Expand/Collapse response button. Fixes #320 2019-11-21 20:28:06 +05:30
Liyas Thomas
5d011b09ae GraphQL endpoint field is now persisted (#319)
GraphQL endpoint field is now persisted
2019-11-21 10:49:04 +05:30
Andrew Bastin
638f3f1a05 GraphQL endpoint URL is now persisted 2019-11-21 00:02:30 -05:00
Andrew Bastin
879fc58d9c Added mutation for working with the GQL store 2019-11-21 00:01:12 -05:00
Andrew Bastin
2c139c2a65 Added GQL object to global store 2019-11-21 00:00:15 -05:00
Liyas Thomas
4c9c9a2240 🚨 Lint 2019-11-21 09:11:50 +05:30
Liyas Thomas
354ad3983f 🎨 Updated GraphQL docs section styles 2019-11-21 07:09:17 +05:30
Liyas Thomas
8d99d4aa99 :liptick: Minor UI update 2019-11-21 06:55:37 +05:30
Liyas Thomas
1ab2de9c69 Merge pull request #318 from AndrewBastin/feat/gql_copy_schema
Added button to copy GraphQL schema
2019-11-21 02:49:08 +05:30
Andrew Bastin
6a938cdcca Added copy schema button to copy schema string to clipboard 2019-11-20 17:49:42 +00:00
Liyas Thomas
0c705bfa6d ✏️ Added GraphQL support to feature list 2019-11-20 20:29:23 +05:30
Liyas Thomas
6169f1c150 chore(refactor): switch to async/await approach (#317)
chore(refactor): switch to async/await approach
2019-11-20 19:43:22 +05:30
jamesgeorge007
3639ed8f70 fix: add async nature 2019-11-20 18:11:07 +05:30
jamesgeorge007
2083e02698 fix: typo 2019-11-20 18:08:30 +05:30
jamesgeorge007
a7d483ea1b fix: lint 2019-11-20 18:07:52 +05:30
jamesgeorge007
a0dd02ec07 fix: lint 2019-11-20 18:07:33 +05:30
jamesgeorge007
929d955237 fix: minor tweak 2019-11-20 18:06:19 +05:30
jamesgeorge007
f61eeebc8f fix: lint 2019-11-20 18:05:46 +05:30
jamesgeorge007
f8c3d1e6db refactor: use async await approach 2019-11-20 18:00:17 +05:30
Liyas Thomas
38513d3eed GraphQL Support (#311)
GraphQL Support

Co-authored-by: Liyas Thomas <liyasthomas@gmail.com>
2019-11-20 12:04:19 +05:30
Andrew Bastin
051259419c Merge branch 'master' into master 2019-11-20 01:09:36 -05:00
Liyas Thomas
fad28ee40b Compact UI. fixe #314 2019-11-20 06:16:02 +05:30
Liyas Thomas
1d9778226c feat: use alpine for Dockerfile (#316)
feat: use alpine for Dockerfile
2019-11-20 05:45:21 +05:30
Colin Nelson
f1dab84571 Merge branch 'master' into dockerfile-alpine 2019-11-19 15:58:46 -08:00
Liyas Thomas
c413317970 📸 Updated screenshots 2019-11-20 05:27:00 +05:30
Andrew Bastin
631c8b625b Removed debug console logs 2019-11-19 15:42:28 -05:00
Colin Nelson
2dd9683eb1 feat: use alpine for Dockerfile
Reduces resultant image size to ~942MB (was 1.55GB).
2019-11-19 10:54:16 -08:00
Andrew Bastin
f7faac1afc Added deprecated label for deprecated GQL fields 2019-11-19 12:06:47 -05:00
Liyas Thomas
91d0422f53 Minor UI stylings 2019-11-19 20:29:18 +05:30
Liyas Thomas
a22090e3df Added scroll for overflowing Docs section 2019-11-19 20:13:46 +05:30
Liyas Thomas
62f52a0be1 🐛 Fixed gqlType 2019-11-19 09:53:02 +05:30
Liyas Thomas
eca1dc8e66 Moved Cocs section to right sidebar (will fix overflow issue later today) + Basic lint 2019-11-19 08:55:57 +05:30
Andrew Bastin
8e3542863a Filtered unwanted type entries 2019-11-18 21:53:13 -05:00
Andrew Bastin
34be6ce795 Added GraphQL types section in docs 2019-11-18 15:17:33 -05:00
Andrew Bastin
2d995b87b1 Added GraphQL type component 2019-11-18 15:17:07 -05:00
Andrew Bastin
edbb81d089 Added a null guard for args field 2019-11-18 15:14:26 -05:00
Andrew Bastin
6c4fbb501c Fixed margin mistake in field-desc 2019-11-18 14:58:37 -05:00
Andrew Bastin
5f3ca632cb Added docs section with query,mutation and subscription lists 2019-11-18 14:34:31 -05:00
Andrew Bastin
3db28e4f22 Added GraphQL field component 2019-11-18 14:34:00 -05:00
Liyas Thomas
79a7b3c985 🌱 Error handlers 2019-11-18 22:20:18 +05:30
Liyas Thomas
109d57b4b4 Merge branch 'master' into master 2019-11-18 19:58:51 +05:30
Liyas Thomas
71779d560a Added loader, changed webSocket icon 2019-11-18 19:55:54 +05:30
Liyas Thomas
967bf49db0 Lint 2019-11-18 18:02:44 +05:30
Liyas Thomas
3cedd48503 Merge branch 'master' into master 2019-11-18 07:12:59 +05:30
Liyas Thomas
0c303b63bd Merge pull request #310 from liyasthomas/app-ui
 Minor UI updates
2019-11-18 07:11:01 +05:30
Liyas Thomas
ef070dbad7 Merge branch 'master' into app-ui 2019-11-18 07:04:07 +05:30
liyasthomas
d88e777f80 Minor UI updates 2019-11-18 06:32:30 +05:30
Andrew Bastin
cffdd56522 Added GraphQL page to the sidebar 2019-11-17 19:48:53 -05:00
Andrew Bastin
d44b821a04 Added GraphQL page 2019-11-17 19:48:29 -05:00
Andrew Bastin
0c6a59282e Added graphql as dependency 2019-11-17 18:00:01 -05:00
Liyas Thomas
3ba2aa922f App ui (#309)
App ui
2019-11-17 15:13:48 +05:30
liyasthomas
ce8e2c6684 Right secondary sidebar 2019-11-17 15:04:06 +05:30
liyasthomas
d3aa8e03a2 Moved sidebar to left 2019-11-17 11:58:40 +05:30
liyasthomas
3ae9c49029 Moved History and Collection sections to right side bar 2019-11-17 08:25:07 +05:30
liyasthomas
bac0db10a6 UI optimizations 2019-11-17 05:03:57 +05:30
liyasthomas
a40d67138b 🎨 Moved History & Collection section to sticky right nav (initial upload). 2019-11-17 03:26:26 +05:30
Liyas Thomas
a8f6df16a8 🐛 Fixed entry animation on few modals 2019-11-16 14:14:53 +05:30
Liyas Thomas
63f23118b6 Merge branch 'master' of https://github.com/liyasthomas/postwoman 2019-11-16 11:21:26 +05:30
Liyas Thomas
71de9cfec5 🐛 Fixed Edit foldernot working, added critical render for Collection component 2019-11-16 11:20:36 +05:30
Liyas Thomas
5f8729536c 💩 Removed unused parameters 2019-11-16 11:20:35 +05:30
dependabot-preview[bot]
461dd21806 ⬆️ Bump @nuxtjs/sitemap from 2.0.0 to 2.0.1
Bumps [@nuxtjs/sitemap](https://github.com/nuxt-community/sitemap-module) from 2.0.0 to 2.0.1.
- [Release notes](https://github.com/nuxt-community/sitemap-module/releases)
- [Changelog](https://github.com/nuxt-community/sitemap-module/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/nuxt-community/sitemap-module/compare/v2.0.0...v2.0.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-16 11:20:34 +05:30
Liyas Thomas
d5a44fdec4 ⬆️ Bump @nuxtjs/sitemap from 2.0.0 to 2.0.1 (#307)
⬆️ Bump @nuxtjs/sitemap from 2.0.0 to 2.0.1

Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com>
2019-11-16 08:56:32 +05:30
dependabot-preview[bot]
0fd96aa92e ⬆️ Bump @nuxtjs/sitemap from 2.0.0 to 2.0.1
Bumps [@nuxtjs/sitemap](https://github.com/nuxt-community/sitemap-module) from 2.0.0 to 2.0.1.
- [Release notes](https://github.com/nuxt-community/sitemap-module/releases)
- [Changelog](https://github.com/nuxt-community/sitemap-module/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/nuxt-community/sitemap-module/compare/v2.0.0...v2.0.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-16 00:13:43 +00:00
Liyas Thomas
3ba6de6f34 Lazy (#306)
Lazy

Co-authored-by: Liyas Thomas <liyasthomas@gmail.com>
2019-11-16 01:03:44 +05:30
Liyas Thomas
d214be027d 🐛 Fixed critical render for essential components 2019-11-16 00:51:16 +05:30
Liyas Thomas
af7273e7eb Lazy components 2019-11-16 00:32:27 +05:30
Liyas Thomas
69971198af ⚗ Lazy component import 2019-11-16 00:25:05 +05:30
Liyas Thomas
23a681f214 Merge pull request #305 from liyasthomas/shortcuts
 Added "Keyboard shortcuts" to features list
2019-11-15 05:08:40 +05:30
Liyas Thomas
7516524d38 Added "Keyboard shortcuts" to features list 2019-11-15 00:05:51 +05:30
Liyas Thomas
474711431e More shortcuts (#304)
 More shortcuts

Co-authored-by: Liyas Thomas <liyasthomas@gmail.com>
2019-11-14 23:41:30 +05:30
Liyas Thomas
3cea9de8fe More shortcuts 2019-11-14 23:18:44 +05:30
Liyas Thomas
9235b0ffb6 Keyboard shortcuts (#303)
Keyboard shortcuts

Co-authored-by: Liyas Thomas <liyasthomas@gmail.com>
2019-11-14 19:09:40 +05:30
Liyas Thomas
a159275dba Polished Shortcuts modal 2019-11-14 19:02:44 +05:30
Liyas Thomas
105005aa07 Merge branch 'shortcuts' of https://github.com/liyasthomas/postwoman into shortcuts 2019-11-14 18:28:40 +05:30
Liyas Thomas
40a8d45ab0 More shortcuts 2019-11-14 17:43:45 +05:30
Liyas Thomas
009eae83a6 Keyboard shortcuts 2019-11-14 16:28:17 +05:30
Liyas Thomas
c146879fd3 Lint (#301)
 Lint
2019-11-14 10:18:58 +05:30
Liyas Thomas
00c6e22861 Lint 2019-11-14 10:10:02 +05:30
Liyas Thomas
939a74b7be 💄 Minor UI improvements (#300)
💄 Minor UI improvements

Co-authored-by: Liyas Thomas <liyasthomas@gmail.com>
2019-11-14 05:30:47 +05:30
Liyas Thomas
a53db858e3 Merge branch 'app-ui' of https://github.com/liyasthomas/postwoman into app-ui 2019-11-14 05:26:58 +05:30
Liyas Thomas
38da938ec1 🔎 Improving Lighthouse score 2019-11-14 05:25:12 +05:30
Liyas Thomas
8cf1a37633 Merge branch 'master' into app-ui 2019-11-14 05:07:16 +05:30
Liyas Thomas
9de8c4cf04 💄 Minor UI improvements 2019-11-14 05:00:44 +05:30
Liyas Thomas
40be148c9b 📱 Popovers on mobile devices (#297)
📱 Popovers on mobile devices

Co-authored-by: Liyas Thomas <liyasthomas@gmail.com>
2019-11-13 21:16:55 +05:30
Liyas Thomas
dfbb563b6f Added payload upload feature. Fixes #298 2019-11-13 21:04:49 +05:30
Liyas Thomas
ab76afb322 Merge branch 'app-ui' of https://github.com/liyasthomas/postwoman into app-ui 2019-11-13 19:20:26 +05:30
Liyas Thomas
4b3593d081 🐛 Fixed huge padding in auto-complete 2019-11-13 19:18:34 +05:30
Liyas Thomas
210e182d7e ✏️ Typo 2019-11-13 16:56:14 +05:30
Liyas Thomas
6f1154a1f8 Merge branch 'app-ui' of https://github.com/liyasthomas/postwoman into app-ui 2019-11-13 09:30:23 +05:30
Liyas Thomas
d935ff4b3e ✏️ Initial docs upload 2019-11-13 09:29:42 +05:30
Liyas Thomas
cd92d87c5d Merge branch 'master' into app-ui 2019-11-13 07:06:41 +05:30
Liyas Thomas
e8ac8ac0ab 📱 Popovers 2019-11-13 06:57:09 +05:30
Liyas Thomas
7ae7bdd670 Merge pull request #296 from liyasthomas/app-ui
Moved "Generate code" section to modal
2019-11-13 04:50:10 +05:30
Liyas Thomas
1dbb89df34 ⚗️ Popover 2019-11-12 22:35:46 +05:30
Liyas Thomas
b9908f68f9 Fixed abnormal popover position 2019-11-12 22:27:14 +05:30
Liyas Thomas
b839e8183f Moved Generate code section to modal 2019-11-12 16:05:33 +05:30
Liyas Thomas
51b370efa6 Minor UI changes (#295)
Minor UI changes
2019-11-12 10:57:56 +05:30
Liyas Thomas
f65e67d86a 🐛 Fixed invisible Install PWA button 2019-11-12 10:44:52 +05:30
Liyas Thomas
653e42c2b9 🚨 Lint 2019-11-12 10:22:50 +05:30
Liyas Thomas
3b6c8247c5 Minor UI changes 2019-11-12 09:48:57 +05:30
Hossein Nedaee
f457cc5107 Merge pull request #292 from hosseinnedaee/implement-ace-instead-highlightjs
Replace highlight.js with ace editor.
2019-11-12 06:58:51 +03:30
Liyas Thomas
f9e62f3237 Merge branch 'master' into implement-ace-instead-highlightjs 2019-11-12 07:24:47 +05:30
Hossein Nedaee
4ca78a2fe5 Make lang prop dynamic. 2019-11-11 21:44:29 +03:30
Hossein Nedaee
179010ddbf Change ace-editor theme by PW theme changing. 2019-11-11 20:44:24 +03:30
Liyas Thomas
4cca931d9d 🔍 SEO optimizations 2019-11-11 19:23:35 +05:30
Liyas Thomas
3c2743510b 🔍 SEO optimizations 2019-11-11 19:01:49 +05:30
Hossein Nedaee
716434d59e Reduce response body font size 2019-11-10 21:08:57 +03:30
Hossein Nedaee
4accbda497 Change ace editor font-family 2019-11-10 21:03:20 +03:30
Liyas Thomas
9f0512e81e 📱 Responsive History section for mobile devices 2019-11-10 21:49:26 +05:30
Liyas Thomas
10b699a6f7 Favorite (star) History entries 2019-11-10 12:08:10 +05:30
Hossein Nedaee
1a9b4cdbf5 Replace highlight.js with ace editor. 2019-11-09 22:58:05 +03:30
Liyas Thomas
ee8f133ebb ⚗️ Hid commiit hash and variant from footer 2019-11-09 21:31:20 +05:30
Liyas Thomas
b193625fb6 🎨 Version and hash on footer 2019-11-09 21:10:00 +05:30
Liyas Thomas
ca3abed605 🔥 Better boolean conditions 2019-11-09 20:43:48 +05:30
liyasthomas
3b2fd26bd9 Merge branch 'master' of https://github.com/liyasthomas/postwoman 2019-11-09 14:31:54 +05:30
liyasthomas
1b21187397 Better History section 2019-11-09 14:31:07 +05:30
liyasthomas
c2519bdb7d Added pw.env.set() for storing environment variables 2019-11-09 12:17:50 +05:30
Liyas Thomas
797edc50f4 Checking if seciton exist before accessing its properties (#288)
Checking if seciton exist before accessing its properties
2019-11-09 07:50:09 +05:30
liyasthomas
6ffbd88d92 ✏️ Updated meta 2019-11-09 07:44:22 +05:30
liyasthomas
377cd2ba1f Merge branch 'master' of https://github.com/liyasthomas/postwoman 2019-11-09 07:19:51 +05:30
liyasthomas
14a67fa698 🐛 Fixed #275 2019-11-09 07:18:53 +05:30
Liyas Thomas
efe1c7ba45 ⬆️ Bump cypress from 3.6.0 to 3.6.1 (#290)
⬆️ Bump cypress from 3.6.0 to 3.6.1

Co-authored-by: null <27856297+dependabot-preview[bot]@users.noreply.github.com>
2019-11-09 05:52:27 +05:30
dependabot-preview[bot]
96cf5f43d2 ⬆️ Bump cypress from 3.6.0 to 3.6.1
Bumps [cypress](https://github.com/cypress-io/cypress) from 3.6.0 to 3.6.1.
- [Release notes](https://github.com/cypress-io/cypress/releases)
- [Commits](https://github.com/cypress-io/cypress/compare/v3.6.0...v3.6.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-11-09 00:14:29 +00:00
liyasthomas
4ed461bc69 ✏️ Updated link 2019-11-09 00:45:58 +05:30
liyasthomas
78fd2d5399 🐛 Fixed overflow on WebSocket response box 2019-11-08 23:56:49 +05:30
liyasthomas
cf1d07e7a6 🐛 Fixed #289 2019-11-08 23:41:30 +05:30
liyasthomas
f71b940197 Adds expandable columns to History component for showing request duration and pre-request scripts if any. Fixes #233 #225 2019-11-08 23:22:48 +05:30
liyasthomas
aae182a9f8 Added preRequestScript and request duration to history entry 2019-11-08 22:26:43 +05:30
rafi993
2162f52e00 Checking if seciton is valid 2019-11-08 16:36:55 +05:30
Liyas Thomas
7a88d2d08c Fixes #281 (accessibility issues) 2019-11-08 09:08:35 +05:30
Liyas Thomas
896c4e7561 🐛 Fixed broken syntax highlighting 2019-11-08 00:52:45 +05:30
Liyas Thomas
c537477d3a 🐛 Better error prompt. Fixes #283 2019-11-08 00:28:58 +05:30
Liyas Thomas
2a9adfd180 Improving accessibility 2019-11-08 00:01:35 +05:30
Liyas Thomas
7a60cc25e9 :wheel_chair: Improving accessibility 2019-11-07 23:11:41 +05:30
Liyas Thomas
73255c9c75 Enhancement: make saving of collections, requests, folder more c… (#282)
Enhancement: make saving of collections, requests, folder more convenient
2019-11-07 16:19:33 +00:00
Markus Reisenhofer
840af00d6d Added event for new request as well 2019-11-07 16:26:19 +01:00
Markus Reisenhofer
c3a58eec8d Added enter key event for convenience reasons 2019-11-07 16:09:31 +01:00
Liyas Thomas
e18b8f6bb6 Improving accessibility, fixes #277 2019-11-07 09:29:08 +05:30
Liyas Thomas
48d4e69fc8 Improving accessibility, fixes #279 2019-11-07 09:19:37 +05:30
Liyas Thomas
c388eddc67 Added response URL, Path, Method and timestamp to downloaded response file 2019-11-07 08:59:04 +05:30
Liyas Thomas
dcf5c2a0d6 Merge pull request #280 from Daniellunsc/add-download-button
Add download button
2019-11-07 08:00:53 +05:30
Daniel Luna
7d070810d5 Updated README 2019-11-06 23:21:38 -03:00
Daniel Luna
5923c88a94 Added download button 2019-11-06 23:19:27 -03:00
Liyas Thomas
a45770119c Fix #271 Duplicated query string (#273)
Fix #271 Duplicated query string
2019-11-06 14:43:05 +05:30
RifqiAlAbqary
d3d3cda758 Fix #271 Duplicated query string 2019-11-06 18:05:13 +09:00
Liyas Thomas
8ae157a272 Fix #269 Incorrect code generation (#270)
Fix #269 Incorrect code generation
2019-11-06 13:20:00 +05:30
RifqiAlAbqary
8398db90ef Merge remote-tracking branch 'upstream/master' into fix-code-generation 2019-11-06 16:17:36 +09:00
RifqiAlAbqary
177585c998 Fix #269 Incorrect code generation 2019-11-06 16:17:03 +09:00
Liyas Thomas
7ac9c34820 ✏️ Added Wiki links to sections 2019-11-06 12:23:30 +05:30
Liyas Thomas
5e424bb64d 🐛 Fixed a critical bug, clear cookies to take effect 2019-11-06 09:25:55 +05:30
Liyas Thomas
d290b25f8a 🐛 Fixed a critical bug, clear cookies to take effect 2019-11-06 08:35:56 +05:30
Liyas Thomas
90c3ca47b9 🐛 Fixed light theme issues on highlightjs 2019-11-05 19:03:09 +05:30
Liyas Thomas
924a931568 📜 v1.0.0 changelog 2019-11-04 17:47:31 +05:30
86 changed files with 8701 additions and 4130 deletions

View File

@@ -52,15 +52,6 @@
"code"
]
},
{
"login": "terranblake",
"name": "Terran Blake",
"avatar_url": "https://avatars3.githubusercontent.com/u/8795767?v=4",
"profile": "https://www.lumahealth.io/",
"contributions": [
"code"
]
},
{
"login": "AndrewBastin",
"name": "Andrew Bastin",

3
.github/FUNDING.yml vendored
View File

@@ -1,4 +1,3 @@
ko_fi: liyasthomas
open_collective: liyasthomas
open_collective: postwoman
patreon: liyasthomas
custom: https://www.paypal.me/liyascthomas

View File

@@ -1,3 +1,159 @@
# Changelog
* [v0.1.0](https://github.com/liyasthomas/postwoman/releases/tag/v0.1.0) - Initial 🎉 Initial public release
## [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:**
- On Save Updated existing API [\#204](https://github.com/liyasthomas/postwoman/issues/204)
- 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))
- updated threshold and rootMargin for IntersectionObserver [\#182](https://github.com/liyasthomas/postwoman/pull/182) ([edisonaugusthy](https://github.com/edisonaugusthy))
- 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))
- Update PWA configuration [\#171](https://github.com/liyasthomas/postwoman/pull/171) ([NBTX](https://github.com/NBTX))
## [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

@@ -34,12 +34,12 @@ Examples of unacceptable behavior by participants include:
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
behavior. Maintainers are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
that are not aligned with our Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

View File

@@ -1,20 +1,20 @@
# Contributing
When contributing to this repository, please first discuss the change you wish to make via issue,
email, or any other method with the owners of this repository before making a change.
email, or any other method with the owners of this repository before making a change.
Please note we have a code of conduct, please follow it in all your interactions with the project.
## Pull Request Process
1. Ensure any install or build dependencies are removed before the end of the layer when doing a
1. Ensure any install or build dependencies are removed before the end of the layer when doing a
build.
2. Update the README.md with details of changes to the interface, this includes new environment
2. Update the README.md with details of changes to the interface, this includes new environment
variables, exposed ports, useful file locations and container parameters.
3. Increase the version numbers in any examples files and the README.md to the new version that this
Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/).
4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you
do not have permission to do that, you may request the second reviewer to merge it for you.
4. You may merge the Pull Request once you have the sign-off of two other developers, or if you
do not have permission to do that, you may request the second reviewer merge it for you.
## Code of Conduct
@@ -52,12 +52,12 @@ advances
### Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
behavior. Maintainers are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
that are not aligned with our Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

View File

@@ -1,12 +1,19 @@
FROM node:12.10.0-buster
FROM node:12.10.0-alpine
LABEL maintainer="Liyas Thomas (liyascthomas@gmail.com)"
# Add git as the prebuild target requires it to parse version information
RUN apk add --update --no-cache \
git
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm install
RUN npm run build
EXPOSE 3000

192
README.md
View File

@@ -10,7 +10,7 @@
</p>
<p>
[![Travis Build Status](https://img.shields.io/travis/com/liyasthomas/postwoman?logo=Travis)](https://travis-ci.com/liyasthomas/postwoman) [![GitHub release](https://img.shields.io/github/release/liyasthomas/postwoman/all?logo=GitHub)](https://github.com/liyasthomas/postwoman/releases/latest) [![Website](https://img.shields.io/website?url=https%3A%2F%2Fpostwoman.io)](https://postwoman.io) [![Contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen?style=flat)](CONTRIBUTING.md) [![All Contributors](https://img.shields.io/badge/all_contributors-13-orange.svg?style=flat-square)](#contributors) [![Financial Contributors on Open Collective](https://img.shields.io/opencollective/all/postwoman?logo=Open-Collective&label=financial+contributors)](https://opencollective.com/postwoman) [![Donate on PayPal](https://img.shields.io/badge/support-PayPal-blue?logo=PayPal)](https://www.paypal.me/liyascthomas) [![Chat on Telegram](https://img.shields.io/badge/chat-Telegram-blueviolet?logo=Telegram)](https://t.me/postwoman_app) [![Chat on Discord](https://img.shields.io/badge/chat-Discord-violet?logo=discord)](https://discord.gg/GAMWxmR) [![Tweet](https://img.shields.io/twitter/url?url=https%3A%2F%2Fpostwoman.io%2F)](https://twitter.com/intent/tweet?url=https%3A%2F%2Fpostwoman.io&text=%F0%9F%91%BD%20Postwoman%20%E2%80%A2%20API%20request%20builder%20-%20Helps%20you%20create%20your%20requests%20faster%2C%20saving%20you%20precious%20time%20on%20your%20development&original_referer=https%3A%2F%2Ftwitter.com%2Fshare%3Ftext%3D%25F0%259F%2591%25BD%2520Postwoman%2520%25E2%2580%25A2%2520API%2520request%2520builder%2520-%2520Helps%2520you%2520create%2520your%2520requests%2520faster%2C%2520saving%2520you%2520precious%2520time%2520on%2520your%2520development%26url%3Dhttps%3A%2F%2Fpostwoman.io%26hashtags%3Dpostwoman%26via%3Dliyasthomas&via=liyasthomas&hashtags=postwoman)
[![Travis Build Status](https://img.shields.io/travis/com/liyasthomas/postwoman?logo=Travis)](https://travis-ci.com/liyasthomas/postwoman) [![GitHub release](https://img.shields.io/github/release/liyasthomas/postwoman/all?logo=GitHub)](https://github.com/liyasthomas/postwoman/releases/latest) [![Website](https://img.shields.io/website?url=https%3A%2F%2Fpostwoman.io&logo=Postwoman)](https://postwoman.io) [![Contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen)](CONTRIBUTING.md) [![Financial Contributors on Open Collective](https://img.shields.io/opencollective/all/postwoman?logo=Open-Collective&label=financial+contributors)](https://opencollective.com/postwoman) [![Donate on PayPal](https://img.shields.io/badge/support-PayPal-blue?logo=PayPal)](https://www.paypal.me/liyascthomas) [![Chat on Telegram](https://img.shields.io/badge/chat-Telegram-blueviolet?logo=Telegram)](https://t.me/postwoman_app) [![Chat on Discord](https://img.shields.io/badge/chat-Discord-violet?logo=discord)](https://discord.gg/GAMWxmR) [![Tweet](https://img.shields.io/twitter/url?url=https%3A%2F%2Fpostwoman.io%2F)](https://twitter.com/intent/tweet?url=https%3A%2F%2Fpostwoman.io&text=%F0%9F%91%BD%20Postwoman%20%E2%80%A2%20API%20request%20builder%20-%20Helps%20you%20create%20your%20requests%20faster%2C%20saving%20you%20precious%20time%20on%20your%20development&original_referer=https%3A%2F%2Ftwitter.com%2Fshare%3Ftext%3D%25F0%259F%2591%25BD%2520Postwoman%2520%25E2%2580%25A2%2520API%2520request%2520builder%2520-%2520Helps%2520you%2520create%2520your%2520requests%2520faster%2C%2520saving%2520you%2520precious%2520time%2520on%2520your%2520development%26url%3Dhttps%3A%2F%2Fpostwoman.io%26hashtags%3Dpostwoman%26via%3Dliyasthomas&via=liyasthomas&hashtags=postwoman)
</p>
<p>
@@ -23,11 +23,11 @@
---
**Start here: _[Story behind Postwoman](https://dev.to/liyasthomas/i-created-postwoman-an-online-open-source-api-request-builder-41md)_**
**Read: _[Story behind Postwoman](https://dev.to/liyasthomas/i-created-postwoman-an-online-open-source-api-request-builder-41md), [Postwoman v1.0](https://dev.to/liyasthomas/postwoman-v1-0-a-free-fast-beautiful-alternative-to-postman-mn0)_**
**Chat here: _[Telegram](https://t.me/postwoman_app), [Discord](https://discord.gg/GAMWxmR)_**
**Chat: _[Telegram](https://t.me/postwoman_app), [Discord](https://discord.gg/GAMWxmR)_**
**Donate here: _[PayPal](https://www.paypal.me/liyascthomas), [Open Collective](https://opencollective.com/postwoman), [Patreon](https://www.patreon.com/liyasthomas)_**
**Donate: _[PayPal](https://www.paypal.me/liyascthomas), [Open Collective](https://opencollective.com/postwoman), [Patreon](https://www.patreon.com/liyasthomas)_**
<div align="center">
<br>
@@ -38,11 +38,9 @@
### Features ✨
❤️ **Lightweight**: Crafted with minimalistic UI design. Simple design is the best design.
❤️ **Lightweight**: Crafted with minimalistic UI design - simple design is the best design.
- Faster, lighter, cleaner, minimal & responsive
⚡️ **Fast**: Send requests and get/copy responses in real-time! Fast software is the best software.
⚡️ **Fast**: Send requests and get/copy responses in real-time - fast software is the best software.
**Methods:**
- `GET` - Retrieve information about the REST API resource
@@ -50,19 +48,20 @@
- `POST` - Create a REST API resource
- `PUT` - Update a REST API resource
- `DELETE` - Delete a REST API resource or related component
- `CONNECT` - Establishes a tunnel to the server identified by the target resource
- `OPTIONS` - Describe the communication options for the target resource
- `TRACE` - Performs a message loop-back test along the path to the target resource
- `PATCH` - Apply partial modifications to a REST API resource
- `<custom>` - Some APIs use custom request methods such as `LIST`. Type in your custom methods.
_History entries are synced with local session storage_
🌈 **Make it yours**: Customizable combinations for background, foreground and accent colors: because customization === freedom. [Customize now ✨](https://postwoman.io/settings).
🌈 **Make it yours**: Customizable combinations for background, foreground and accent colors: because customization is freedom. [Customize now ✨](https://postwoman.io/settings).
**Customizations:**
- Choose theme: Kinda Dark (default), Clearly White, Just Black and System theme
- Choose accent color: Green (default), Yellow, Pink, Red, Purple, Orange, Cyan and Blue
- Toggle multi-colored frames
- Toggle multi-colored headings
_Customized themes are also synced with local session storage_
_Customized themes are synced with local session storage_
🔥 **PWA**: Install as a [PWA](https://developers.google.com/web/progressive-web-apps) on your device.
@@ -74,24 +73,36 @@ _Customized themes are also synced with local session storage_
- [Desktop PWA](https://developers.google.com/web/progressive-web-apps/desktop) support (button in footer)
- ([full features](https://developers.google.com/web/progressive-web-apps))
🚀 **Request**: Retrieve data from a URL without having to do a full page refresh.
🚀 **Request**: Retrieve response from endpoint instantly.
- Choose `method`
- Enter `URL`
- Enter `Path`
- Enter `URL` and `Path`
- Send
**Features:**
- Copy/share public "Share URL"
- Generate request code for JavaScript XHR, Fetch and cURL
- Generate request code for `JavaScript XHR`, `Fetch` and `cURL`
- Copy generated request code to clipboard
- Import cURL
- Import `cURL`
- Label requests
🔌 **Web Socket**: Establish full-duplex communication channels over a single TCP connection.
🔌 **WebSocket**: Establish full-duplex communication channels over a single TCP connection.
- Send and receive data
- Send and receive data
- Basic authentication using username and password
- Token based authentication
🔐 **Authentication**: Allows to identity the end user.
📡 **Server Sent Events**: Receive a stream of updates from a server over a HTTP connection without resorting to polling.
🔮 **GraphQL**: GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data.
- Set endpoint and get schemas
- Multi-column docs
- Set custom request headers
- Query schema
- Get query response
🔐 **Authentication**: Allows to identify the end user.
**Types:**
- None
@@ -107,30 +118,32 @@ _Customized themes are also synced with local session storage_
📃 **Request Body**: Used to send and receive data via the REST API.
**Options:**
- Set Content Type
- Set `Content Type`
- Add or remove Parameter list
- Toggle between key-value and RAW input Parameter list
👋 **Responses**: Contains the status line, headers and the message/response body.
- Copy response to clipboard
- View preview for HTML responses
_HTML responses have "Preview HTML" feature_
- Download response to as a file
- View preview of HTML responses
**History**: Request entries are synced with local session storage to reuse with a single click.
**Fields:**
- Star
- Label
- Timestamp
- Method
- Status code
- URL
- Path
- Timestamp
- Duration
- Pre-request script
_History entries can be sorted by any fields_
_Histories can deleted one-by-one or all together_
_Histories can be deleted one-by-one or all together_
📁 **Collections**: Keep your API requests organized with collections and folders. Reuse them with a single click.
@@ -138,8 +151,6 @@ _Histories can deleted one-by-one or all together_
- Create infinite collections, folders and requests
- Edit, delete, move, export, import and replace
_Export, import and replace collections with JSON files_
_Collections are synced with local session storage_
🌐 **Proxy**: Enable Proxy Mode from Settings to access blocked APIs.
@@ -147,33 +158,86 @@ _Collections are synced with local session storage_
**Features:**
- Hide your IP address
- Fixes [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) (Cross Origin Resource Sharing) issues
- Access APIs served in non-HTTPS (`http://`, `localhost`, etc.)
- Access APIs served in non-HTTPS (`http://`)
- Use custom Proxy URL
_Proxy is hosted by ApolloTV - [Privacy policy](https://apollotv.xyz/legal)_
_Official Postwoman Proxy is hosted by ApolloTV - **[Privacy policy](https://apollotv.xyz/legal)**_
📜 **Pre-Request Scripts β**: Snippets of code associated with a request that are executed before the request is sent.
**Use-cases:**
- Including the timestamp in the request headers
- Sending a random alphanumeric string in the URL parameters
_Pre-Request Scripts is an experimental feature and is in Public Beta testing_
- Include timestamp in the request headers
- Send a random alphanumeric string in the URL parameters
_Requests with Pre-Request Scripts are indicated in History entries_
📄 **API Documentation**: Create and share dynamic API documentation easily, quickly.
**Usage:**
1. Add your requests to Collections and Folders
2. Export Collections and easily share your APIs with the rest of your team
3. Import Collections and Generate Documentation on-the-go
⌨️ **Keyboard Shortcuts**: Optimized for efficiency.
**Shortcuts:**
- Send Request <kbd>Ctrl</kbd> + <kbd>G</kbd>
- Save to Collections <kbd>Ctrl</kbd> + <kbd>S</kbd>
- Copy Request Link <kbd>Ctrl</kbd> + <kbd>K</kbd>
- Reset Request <kbd>Ctrl</kbd> + <kbd>L</kbd>
🌎 **i18n β**: Experience the app in your own language.
1. Scroll down to the footer
2. Click "Choose Language" button
3. Select your language from the menu
_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.
- **[Postwoman Proxy β](https://github.com/postwoman-io/postwoman-proxy)** - A simple proxy server created for Postwoman
- **[Postwoman CLI β](https://github.com/postwoman-io/postwoman-cli)** - A CLI solution for Postwoman
_Add-ons are developed and maintained under **[Official Postwoman Organization](https://github.com/postwoman-io)**_
**To find out more, please check out [Postwoman Wiki](https://github.com/liyasthomas/postwoman/wiki).**
## Demo 🚀 [![Website](https://img.shields.io/website?url=https%3A%2F%2Fpostwoman.io)](https://postwoman.io)
## Demo 🚀 [![Website](https://img.shields.io/website?url=https%3A%2F%2Fpostwoman.io&logo=Postwoman)](https://postwoman.io)
[https://postwoman.io](https://postwoman.io)
[postwoman.io](https://postwoman.io)
<a href="https://www.netlify.com">
<img src="https://www.netlify.com/img/global/badges/netlify-light.svg"/>
</a>
## Usage 💡
1. Specify your request method
2. Type in your API URL
3. Add API path
4. Send request
5. Get response!
1. Specify your request `method`
2. Type in your API `URL` and `path`
3. Send request
4. Get response
You're done!
@@ -188,6 +252,12 @@ You're done!
## Developing 👷
#### Use a browser based development environment:
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/liyasthomas/postwoman)
#### Or, with local development environment:
1. [Clone this repo](https://help.github.com/en/articles/cloning-a-repository) with git.
2. Install dependencies by running `npm install` within the directory that you cloned (probably `postwoman`).
3. Start the development server with `npm run dev`.
@@ -258,11 +328,10 @@ See the [CHANGELOG](CHANGELOG.md) file for details.
<td align="center"><a href="https://nicholaslaroux.com"><img src="https://avatars0.githubusercontent.com/u/1557529?v=4" width="100px;" alt="Nicholas La Roux"/><br /><sub><b>Nicholas La Roux</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=larouxn" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/yubathom"><img src="https://avatars3.githubusercontent.com/u/4117768?v=4" width="100px;" alt="Thomas Yuba"/><br /><sub><b>Thomas Yuba</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=yubathom" title="Code">💻</a></td>
<td align="center"><a href="http://www.linkedin.com/in/nickpalenchar"><img src="https://avatars1.githubusercontent.com/u/7539781?v=4" width="100px;" alt="Nick Palenchar"/><br /><sub><b>Nick Palenchar</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=nickpalenchar" title="Code">💻</a></td>
<td align="center"><a href="https://www.lumahealth.io/"><img src="https://avatars3.githubusercontent.com/u/8795767?v=4" width="100px;" alt="Terran Blake"/><br /><sub><b>Terran Blake</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=terranblake" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/AndrewBastin"><img src="https://avatars2.githubusercontent.com/u/9131943?v=4" width="100px;" alt="Andrew Bastin"/><br /><sub><b>Andrew Bastin</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=AndrewBastin" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/vlad0337187"><img src="https://avatars1.githubusercontent.com/u/12682937?v=4" width="100px;" alt="Vladislav"/><br /><sub><b>Vladislav</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=vlad0337187" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/vlad0337187"><img src="https://avatars1.githubusercontent.com/u/12682937?v=4" width="100px;" alt="Vladislav"/><br /><sub><b>Vladislav</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=vlad0337187" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/izerozlu"><img src="https://avatars3.githubusercontent.com/u/17386157?v=4" width="100px;" alt="izerozlu"/><br /><sub><b>izerozlu</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=izerozlu" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/JacobAnavisca"><img src="https://avatars2.githubusercontent.com/u/21232366?v=4" width="100px;" alt="Jacob Anavisca"/><br /><sub><b>Jacob Anavisca</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=JacobAnavisca" title="Code">💻</a></td>
<td align="center"><a href="http://nityanandagohain.github.io"><img src="https://avatars3.githubusercontent.com/u/26831659?v=4" width="100px;" alt="Nityananda Gohain"/><br /><sub><b>Nityananda Gohain</b></sub></a><br /><a href="https://github.com/liyasthomas/postwoman/commits?author=nityanandagohain" title="Code">💻</a></td>
@@ -320,13 +389,34 @@ This project is licensed under the [MIT License](https://opensource.org/licenses
## Badges
| Status | Preview | Markdown Code (copy & paste into `readme.md`) |
| ----------- | ----------- | ----------- |
| **Default** | [![Postwoman](https://img.shields.io/badge/Tested_on-Postwoman-50fa7b)](https://postwoman.io) | `[![Postwoman](https://img.shields.io/badge/Tested_on-Postwoman-50fa7b)](https://postwoman.io)` |
| **Success** | [![Postwoman](https://img.shields.io/badge/Tested_on-Postwoman-success)](https://postwoman.io) | `[![Postwoman](https://img.shields.io/badge/Tested_on-Postwoman-success)](https://postwoman.io)` |
| **Critical** | [![Postwoman](https://img.shields.io/badge/Tested_on-Postwoman-critical)](https://postwoman.io) | `[![Postwoman](https://img.shields.io/badge/Tested_on-Postwoman-critical)](https://postwoman.io)` |
| **Custom** | [![Postwoman](https://img.shields.io/badge/Tested_on-Postwoman-blueviolet)](https://postwoman.io) | `[![Postwoman](https://img.shields.io/badge/Tested_on-Postwoman-blueviolet)](https://postwoman.io)` |
| Make your own badge! | [![Postwoman](https://img.shields.io/badge/your_text-Postwoman-hex_color_code)](https://postwoman.io) | `[![Postwoman](https://img.shields.io/badge/your_text-Postwoman-hex_color_code)](https://postwoman.io)` |
<table>
<tr>
<th>Preview</th>
<th>Markdown code</th>
</tr>
<tbody>
<tr>
<td align="center" width="200px"><a href="https://postwoman.io"><br/><img src="https://img.shields.io/badge/Tested_on-Postwoman-202124?logo=Postwoman"/></a><br/><sub>Default<sub></td>
<td><code>[![Postwoman](https://img.shields.io/badge/Tested_on-Postwoman-202124?logo=Postwoman)](https://postwoman.io)</code></td>
</tr>
<tr>
<td align="center" width="200px"><a href="https://postwoman.io"><br/><img src="https://img.shields.io/badge/Tested_on-Postwoman-success?logo=Postwoman"/></a><br/><sub>Success<sub></td>
<td><code>[![Postwoman](https://img.shields.io/badge/Tested_on-Postwoman-success?logo=Postwoman)](https://postwoman.io)</code></td>
</tr>
<tr>
<td align="center" width="200px"><a href="https://postwoman.io"><br/><img src="https://img.shields.io/badge/Tested_on-Postwoman-critical?logo=Postwoman"/></a><br/><sub>Critical<sub></td>
<td><code>[![Postwoman](https://img.shields.io/badge/Tested_on-Postwoman-critical?logo=Postwoman)](https://postwoman.io)</code></td>
</tr>
<tr>
<td align="center" width="200px"><a href="https://postwoman.io"><br/><img src="https://img.shields.io/badge/Tested_on-Postwoman-blueviolet?logo=Postwoman"/></a><br/><sub>Custom<sub></td>
<td><code>[![Postwoman](https://img.shields.io/badge/Tested_on-Postwoman-blueviolet?logo=Postwoman)](https://postwoman.io)</code></td>
</tr>
<tr>
<td align="center" width="200px"><a href="https://postwoman.io"><br/><img src="https://img.shields.io/badge/your_text-Postwoman-hex_color_code?logo=Postwoman"/></a><br/><sub>Customize<sub></td>
<td><code>[![Postwoman](https://img.shields.io/badge/your_text-Postwoman-hex_color_code?logo=Postwoman)](https://postwoman.io)</code></td>
</tr>
</tbody>
</table>
<div align="center">
<br>

View File

@@ -1,16 +1,21 @@
// @import url("https://fonts.googleapis.com/css?family=Poppins:500,700|Roboto+Mono:400&display=swap");
// @import url("https://fonts.googleapis.com/icon?family=Material+Icons&display=swap");
/* Material Design Icons */
@font-face {
font-family: "Material Icons";
font-display: swap;
font-style: normal;
font-weight: 400;
src: url(~@/assets/fonts/material-icons-v48.woff2) format("woff2");
font-display: swap;
src: url("~static/fonts/material-icons-v48.woff2") format("woff2");
}
.material-icons {
font-family: "Material Icons";
font-weight: normal;
font-style: normal;
height: 24px;
width: 24px;
font-size: 24px;
line-height: 1;
letter-spacing: normal;
@@ -21,43 +26,44 @@
direction: ltr;
-webkit-font-feature-settings: "liga";
-webkit-font-smoothing: antialiased;
font-feature-settings: "liga";
}
/* Roboto Mono 400 */
@font-face {
font-family: "Roboto Mono";
font-display: swap;
font-style: normal;
font-weight: 400;
src: local("Roboto Mono"), local("RobotoMono-Regular"),
url("~@/assets/fonts/roboto-mono-v7-latin-regular.woff2") format("woff2"),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url("~@/assets/fonts/roboto-mono-v7-latin-regular.woff") format("woff");
/* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* Poppins 500 */
/* poppins-500 - latin */
@font-face {
font-family: "Poppins";
font-display: swap;
font-style: normal;
font-weight: 500;
font-display: swap;
src: local("Poppins Medium"), local("Poppins-Medium"),
url("~@/assets/fonts/poppins-v9-latin-500.woff2") format("woff2"),
url("~static/fonts/poppins-v9-latin-500.woff2") format("woff2"),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url("~@/assets/fonts/poppins-v9-latin-500.woff") format("woff");
url("~static/fonts/poppins-v9-latin-500.woff") format("woff");
/* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* poppins-700 - latin */
@font-face {
font-family: "Poppins";
font-display: swap;
font-style: normal;
font-weight: 700;
font-display: swap;
src: local("Poppins Bold"), local("Poppins-Bold"),
url("~@/assets/fonts/poppins-v9-latin-700.woff2") format("woff2"),
url("~static/fonts/poppins-v9-latin-700.woff2") format("woff2"),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url("~@/assets/fonts/poppins-v9-latin-700.woff") format("woff");
url("~static/fonts/poppins-v9-latin-700.woff") format("woff");
/* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* roboto-mono-regular - latin */
@font-face {
font-family: "Roboto Mono";
font-style: normal;
font-weight: 400;
font-display: swap;
src: local("Roboto Mono"), local("RobotoMono-Regular"),
url("~static/fonts/roboto-mono-v7-latin-regular.woff2") format("woff2"),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url("~static/fonts/roboto-mono-v7-latin-regular.woff") format("woff");
/* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}

View File

@@ -1,27 +1,38 @@
$responsiveWidth: 720px;
html {
scroll-behavior: smooth;
.page-enter-active,
.page-leave-active,
.layout-enter-active,
.layout-leave-active {
transition: opacity 0.2s;
}
.page-enter,
.page-leave-active,
.layout-enter,
.layout-leave-active {
opacity: 0;
}
$responsiveWidth: 768px;
::selection {
background-color: var(--ac-sel-color);
background-color: var(--ac-color);
color: var(--act-color);
}
::-webkit-scrollbar {
width: 8px;
height: 8px;
width: 4px;
height: 4px;
border-radius: 4px;
background-color: var(--bg-light-color);
}
::-webkit-scrollbar-thumb {
background-color: var(--fg-light-color);
border-radius: 8px;
border: 2px solid var(--bg-color);
}
::-webkit-scrollbar-thumb:hover {
background-color: var(--fg-color);
&:hover {
background-color: var(--fg-color);
}
}
::placeholder {
@@ -35,11 +46,12 @@ html {
border: 0;
}
html,
body {
background-color: var(--bg-color);
color: var(--fg-color);
font-weight: 500;
font-size: 16px;
font-size: 14px;
font-family: "Poppins", "Roboto", "Noto", sans-serif;
line-height: 1.5;
-webkit-tap-highlight-color: transparent;
@@ -47,15 +59,12 @@ body {
user-select: none;
padding: 0;
margin: 0;
scroll-behavior: smooth;
}
// Make theme transition smoother.
body.afterLoad {
&,
& * {
transition: background-color 0.2s ease-in-out, border 0.2s ease-in-out;
}
transition: background-color 0.2s ease-in-out;
}
body.sticky-footer footer {
@@ -66,14 +75,14 @@ a {
display: inline-flex;
color: inherit;
text-decoration: none;
font-weight: 700;
transition: all 0.2s ease-in-out;
}
header,
footer {
& > div {
display: flex;
padding: 16px;
padding: 16px 8px;
width: 100%;
align-items: center;
justify-content: space-between;
@@ -86,8 +95,8 @@ footer {
flex-direction: column;
}
.wrapper .content {
min-height: 100vh;
.wrapper .page {
min-height: calc(100vh - 153px);
}
.header,
@@ -117,42 +126,50 @@ footer {
.logo {
font-size: 22px;
color: var(--ac-color);
&:hover {
color: var(--ac-color);
}
}
.tagline {
font-size: 18px;
}
.nav-first {
.nav-first,
.sticky-inner {
display: flex;
order: 1;
flex-flow: column;
position: sticky;
top: 0;
align-self: flex-start;
}
.nav-first {
z-index: 1;
height: 100vh;
padding: 0 8px;
background-color: var(--bg-light-color);
}
.main {
display: flex;
flex-flow: column;
flex: 1;
order: 2;
position: relative;
padding: 0 16px;
height: 100%;
}
.nav-second {
display: flex;
width: 10%;
order: 3;
// comment this to display
// comment below this to display
display: none;
}
nav.primary-nav {
display: flex;
flex-flow: column nowrap;
border-bottom: 1px solid var(--brd-color);
svg {
fill: var(--fg-light-color);
@@ -163,15 +180,17 @@ nav.primary-nav {
align-items: center;
justify-content: center;
flex-shrink: 0;
padding: 16px;
padding: 14px;
border-radius: 50%;
background-color: var(--brd-color);
background-color: var(--bg-light-color);
color: var(--fg-light-color);
margin: 8px;
fill: var(--fg-light-color);
margin: 8px 0;
transition: all 0.2s ease-in-out;
&:hover {
color: var(--fg-color);
fill: var(--fg-color);
svg {
fill: var(--fg-color);
@@ -181,6 +200,7 @@ nav.primary-nav {
&.nuxt-link-exact-active {
background-color: var(--ac-color);
color: var(--act-color);
fill: var(--act-color);
border-radius: 16px;
svg {
@@ -192,6 +212,7 @@ nav.primary-nav {
nav.secondary-nav {
display: flex;
border-top: 1px dashed var(--brd-color);
ul {
display: flex;
@@ -205,11 +226,11 @@ nav.secondary-nav {
align-items: center;
justify-content: center;
flex-shrink: 0;
padding: 16px;
padding: 14px;
border-radius: 50%;
background-color: var(--bg-dark-color);
color: var(--fg-light-color);
margin: 8px;
margin: 8px 0;
&:hover {
color: var(--fg-color);
@@ -228,48 +249,30 @@ nav.secondary-nav {
flex-direction: column;
}
$responsiveWidth: 720px;
@media (max-width: $responsiveWidth) {
.columns {
flex-flow: column;
}
.nav-first {
width: 100%;
background-color: var(--bg-color);
}
nav.primary-nav {
flex-flow: row;
}
nav.secondary-nav {
display: none;
}
.main {
padding: 0 8px;
}
}
h1,
h2,
h3 {
h3,
h4 {
display: flex;
align-items: center;
margin: 0;
font-weight: 700;
}
.tooltip {
$bgcolor: var(--tt-color);
$fgcolor: var(--fg-color);
display: block !important;
z-index: 10000;
.tooltip-inner {
background: black;
color: white;
background: $bgcolor;
color: $fgcolor;
border-radius: 8px;
padding: 8px 16px;
font-size: 14px;
font-size: 12px;
font-weight: 500;
box-shadow: 0 4px 24px rgba(black, 0.1);
}
.tooltip-arrow {
@@ -278,7 +281,7 @@ h3 {
border-style: solid;
position: absolute;
margin: 5px;
border-color: black;
border-color: $bgcolor;
z-index: 1;
}
@@ -343,18 +346,22 @@ h3 {
}
&.popover {
$color: #f9f9f9;
.wrapper {
min-height: auto;
}
.popover-inner {
background: $color;
color: black;
padding: 24px;
border-radius: 5px;
background: $bgcolor;
color: $fgcolor;
padding: 4px;
border-radius: 8px;
box-shadow: 0 5px 30px rgba(black, 0.1);
max-height: 256px;
overflow: auto;
}
.popover-arrow {
border-color: $color;
border-color: $bgcolor;
}
}
@@ -375,21 +382,25 @@ h3.title {
margin: 4px;
}
.info {
margin-left: 4px;
color: var(--fg-light-color);
}
button {
display: inline-flex;
align-items: center;
justify-content: center;
margin: 4px;
padding: 0 16px;
padding: 6px 16px;
border-radius: 20px;
background-color: var(--ac-color);
color: var(--act-color);
font-weight: 700;
font-size: 16px;
font-family: "Poppins", "Roboto", "Noto", sans-serif;
font-weight: 700;
transition: all 0.2s ease-in-out;
fill: var(--act-color);
height: 40px;
cursor: pointer;
span {
@@ -397,28 +408,64 @@ button {
margin-left: 8px;
}
&:not([disabled]):hover,
&:not([disabled]):active,
&:not([disabled]):focus {
color: var(--act-color);
fill: var(--act-color);
box-shadow: inset 0 0 0 2px var(--fg-color);
transition: all 0.2s ease-in-out;
}
&.icon {
background-color: var(--bg-color);
background-color: transparent;
color: var(--fg-light-color);
fill: var(--fg-light-color);
border-radius: 8px;
&:not([disabled]):hover {
&:not([disabled]):hover,
&:not([disabled]):active,
&:not([disabled]):focus {
color: var(--fg-color);
fill: var(--fg-color);
box-shadow: none;
transition: all 0.2s ease-in-out;
}
}
&:not([disabled]):hover {
color: var(--act-color);
fill: var(--act-color);
&.primary {
color: var(--ac-color);
&:not([disabled]):hover,
&:not([disabled]):active,
&:not([disabled]):focus {
background-color: var(--ac-color);
color: var(--act-color);
}
}
}
@keyframes beat {
30% {
transform: scale(1.1);
}
50% {
transform: scale(0.9);
}
100% {
transform: scale(1);
}
}
.material-icons:active {
animation: beat 0.5s forwards 1;
}
fieldset {
margin: 16px 0;
border: 1px solid var(--brd-color);
border-radius: 8px;
background-color: var(--bg-color);
border-radius: 16px;
transition: all 0.2s ease-in-out;
background-color: var(--bg-dark-color);
}
legend {
@@ -474,31 +521,42 @@ fieldset.yellow legend {
color: #f1fa8c;
}
input[type="file"],
input[type="radio"],
.tab,
.hide-on-large-screen,
#installPWA,
.hidden {
display: none;
}
kbd,
select,
input,
option,
textarea,
pre {
pre,
code {
display: inline-flex;
margin: 4px;
padding: 8px;
border-radius: 8px;
background-color: var(--bg-dark-color);
color: var(--fg-color);
font-size: 16px;
font-family: 'Roboto Mono', monospace;
font-family: "Roboto Mono", monospace;
font-weight: 400;
line-height: 1;
transition: all 0.2s ease-in-out;
user-select: text;
width: calc(100% - 8px);
min-height: 40px;
resize: vertical;
text-overflow: ellipsis;
&:not([readonly]):hover {
background-color: var(--bg-dark-color);
&:not([readonly]):not(.ace_editor):hover,
&:not([readonly]):not(.ace_editor):active,
&:not([readonly]):not(.ace_editor):focus {
box-shadow: inset 0 0 0 2px var(--fg-light-color);
transition: all 0.2s ease-in-out;
}
}
@@ -506,22 +564,47 @@ pre {
display: grid;
}
code {
height: 336px;
border-radius: 8px;
pre.ace_editor {
font-family: "Roboto Mono", monospace;
font-weight: 400;
z-index: 0;
}
.hljs,
.hljs-subst {
background-color: var(--bg-dark-color) !important;
color: var(--fg-color) !important;
font-family: 'Roboto Mono', monospace;
kbd,
code,
pre {
width: auto;
}
.select-wrapper {
position: relative;
&:after {
display: inline-block;
position: absolute;
pointer-events: none;
content: "\e313";
font-family: "Material Icons";
top: 14px;
right: 14px;
}
}
select {
height: 37px;
background-color: var(--bg-dark-color);
cursor: pointer;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
&::-ms-expand {
display: none;
}
}
select,
input,
option {
height: 40px;
background-color: var(--bg-color);
}
input[type="checkbox"] {
@@ -554,17 +637,17 @@ input[type="checkbox"] {
}
}
.error,
.disabled,
.error:not(input),
.disabled:not(input),
[disabled] {
background-color: var(--err-color);
color: var(--fg-light-color);
fill: var(--fg-light-color);
cursor: default;
cursor: not-allowed;
&.icon {
color: var(--bg-color);
fill: var(--bg-color);
color: var(--err-color);
fill: var(--err-color);
}
}
@@ -579,6 +662,11 @@ ol {
margin: 4px 0 4px;
padding: 0;
list-style-type: none;
ul,
ol {
margin: 0;
}
}
ul li,
@@ -586,41 +674,30 @@ ol li {
display: inline-flex;
flex-direction: column;
flex-grow: 1;
justify-content: center;
}
.flex-wrap {
display: flex;
align-items: center;
justify-content: space-between;
flex-grow: 1;
flex-direction: row;
* {
display: inline-flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
}
}
.show-on-small-screen {
display: flex;
}
@media (max-width: $responsiveWidth) {
ul,
ol {
flex-direction: column;
}
ul li,
ol li {
display: flex;
}
.hide-on-small-screen {
display: none;
}
.show-on-small-screen {
display: inline-flex;
}
}
#installPWA {
display: none;
.show-on-large-screen {
display: inline-flex;
}
.info-response {
@@ -647,23 +724,6 @@ ol li {
background-color: var(--err-color);
}
.virtual-list::-webkit-scrollbar {
width: 0;
}
fieldset#history {
.method-list-item {
position: relative;
span {
position: absolute;
top: 12px;
right: 12px;
font-family: 'Roboto Mono', monospace;
}
}
}
.align-left {
text-align: left;
}
@@ -676,6 +736,11 @@ fieldset#history {
text-align: right;
}
.mono {
font-family: "Roboto Mono", monospace;
font-weight: 400;
}
#response-details-wrapper {
position: relative;
overflow: hidden;
@@ -684,6 +749,7 @@ fieldset#history {
textarea {
margin: 0;
width: 100%;
line-height: 1;
}
.covers-response {
@@ -699,21 +765,21 @@ fieldset#history {
}
#send {
#hidden-message {
display: none;
}
// #hidden-message {
// display: none;
// }
&.show {
display: flex;
position: fixed;
top: 12px;
right: 12px;
z-index: 1;
z-index: 2;
#hidden-message {
display: block;
margin-left: 4px;
}
// #hidden-message {
// display: block;
// margin-left: 4px;
// }
}
}
@@ -722,44 +788,152 @@ section {
flex-wrap: wrap;
}
div.tab {
.tab {
width: 100%;
order: 1;
}
input[type="radio"],
div.tab {
display: none;
}
input[type="radio"] + label {
padding: 8px 16px;
border-bottom: 2px solid transparent;
cursor: pointer;
transition: all 0.2s ease-in-out;
&:hover {
&:hover,
&:active,
&:focus {
border-color: var(--brd-color);
}
}
input[type="radio"]:checked + label {
border-color: var(--fg-color);
color: var(--fg-color);
}
input[type="radio"]:checked + label + div.tab {
input[type="radio"]:checked + label + .tab {
display: block;
}
.toasted-container .toasted {
justify-content: start !important;
justify-content: flex-start !important;
}
.toasted.info {
background-color: var(--ac-color) !important;
color: var(--act-color) !important;
font-weight: 700 !important;
}
.toasted.bubble .action {
color: inherit !important;
}
.toasted .action {
margin-left: auto !important;
}
.page-columns {
display: flex;
flex: 1;
flex-flow: column;
}
.inner-left {
display: flex;
order: 1;
}
.inner-right {
display: flex;
width: 30%;
order: 2;
margin-left: 16px;
}
@media (max-width: $responsiveWidth) {
.content {
flex-flow: column;
}
.columns {
flex-flow: column;
}
.nav-first {
position: fixed;
top: auto;
bottom: 0;
height: auto;
padding: 0;
width: 100%;
background-color: var(--bg-color);
transition: all 0.2s ease-in-out;
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.45);
}
nav.primary-nav {
flex-flow: row nowrap;
overflow: auto;
justify-content: space-around;
a {
background-color: transparent;
margin: 8px;
&.nuxt-link-exact-active {
background-color: transparent;
color: var(--ac-color);
fill: var(--ac-color);
svg {
fill: var(--ac-color);
}
}
}
}
nav.secondary-nav {
display: none;
}
.main {
padding: 0 8px 68px;
}
ul,
ol {
flex-direction: column;
}
ul li,
ol li {
display: flex;
}
.hide-on-small-screen {
display: none;
}
.hide-on-large-screen,
.show-on-small-screen {
display: inline-flex;
}
.sticky-inner {
position: relative;
width: 100%;
}
.inner-left {
order: 0;
}
.inner-right {
margin-left: 0;
}
.toasted-container {
margin-bottom: 68px;
}
}

View File

@@ -8,91 +8,100 @@
// Dark is the default theme variant.
@mixin darkTheme {
// Dark Background color
--bg-dark-color: rgb(41, 42, 45);
// Background color
--bg-color: rgb(37, 38, 40);
// Auto-complete color
--atc-color: rgb(49, 49, 55);
--bg-color: rgba(32, 33, 36, 1);
// Light Background color
--bg-light-color: rgba(255, 255, 255, 0.02);
// Dark Background color
--bg-dark-color: rgba(0, 0, 0, 0.1);
// Text color
--fg-color: rgb(247, 248, 248);
--fg-color: rgba(255, 255, 255, 0.9);
// Light Text color
--fg-light-color: rgb(150, 155, 160);
--fg-light-color: rgba(255, 255, 255, 0.5);
// Border color
--brd-color: rgb(48, 47, 55);
--brd-color: rgba(255, 255, 255, 0.05);
// Error color
--err-color: rgb(41, 42, 45);
--err-color: rgba(255, 255, 255, 0.05);
// Acent color
--ac-color: #50fa7b;
--ac-sel-color: rgb(80, 250, 123, 0.8);
--ac-color: rgba(80, 250, 123, 1);
// Active text color
--act-color: rgb(37, 38, 40);
--act-color: rgba(32, 33, 36, 1);
// Auto-complete color
--atc-color: rgba(32, 33, 36, 1);
// Tooltip color
--tt-color: rgba(53, 53, 53, 1);
}
@mixin lightTheme {
// Background color
--bg-color: rgba(255, 255, 255, 1);
// Light Background color
--bg-light-color: rgba(0, 0, 0, 0.02);
// Dark Background color
--bg-dark-color: rgba(0, 0, 0, 0.02);
// Text color
--fg-color: rgba(0, 0, 0, 0.9);
// Light Text color
--fg-light-color: rgba(0, 0, 0, 0.6);
// Border color
--brd-color: rgba(0, 0, 0, 0.1);
// Error color
--err-color: rgba(0, 0, 0, 0.1);
// Acent color
--ac-color: rgba(80, 250, 123, 1);
// Active text color
--act-color: rgba(255, 255, 255, 1);
// Auto-complete color
--atc-color: rgba(255, 255, 255, 1);
// Tooltip color
--tt-color: rgba(220, 220, 220, 1);
}
@mixin blackTheme {
// Background color
--bg-color: rgba(0, 0, 0, 1);
// Light Background color
--bg-light-color: rgba(255, 255, 255, 0.02);
// Dark Background color
--bg-dark-color: rgba(255, 255, 255, 0.02);
// Text color
--fg-color: rgba(255, 255, 255, 0.9);
// Light Text color
--fg-light-color: rgba(255, 255, 255, 0.5);
// Border color
--brd-color: rgba(255, 255, 255, 0.05);
// Error color
--err-color: rgba(255, 255, 255, 0.05);
// Acent color
--ac-color: rgba(80, 250, 123, 1);
// Active text color
--act-color: rgba(0, 0, 0, 1);
// Auto-complete color
--atc-color: rgba(0, 0, 0, 1);
// Tooltip color
--tt-color: rgba(18, 18, 18, 1);
}
:root {
@include darkTheme;
}
@media(prefers-color-scheme: dark) {
:root.auto {
@include darkTheme;
}
}
@mixin lightTheme {
// Dark Background color
--bg-dark-color: #f6f6f6;
// Background color
--bg-color: #ffffff;
// Auto-complete color
--atc-color: #ebebeb;
// Text color
--fg-color: #525252;
// Light Text color
--fg-light-color: rgb(150, 155, 160);
// Border color
--brd-color: #eeeeed;
// Error color
--err-color: #f6f6f6;
// Acent color
--ac-color: #57b5f9;
--ac-sel-color: #57b5f9;
// Active text color
--act-color: #ffffff;
}
:root.light {
@include lightTheme;
}
@media(prefers-color-scheme: light) {
:root.auto {
@include lightTheme;
}
}
@mixin blackTheme {
// Dark Background color
--bg-dark-color: rgb(8, 8, 8);
// Background color
--bg-color: #000000;
// Auto-complete color
--atc-color: rgb(18, 18, 18);
// Text color
--fg-color: rgb(250, 250, 250);
// Light Text color
--fg-light-color: rgb(100, 100, 100);
// Border color
--brd-color: rgb(16, 16, 16);
// Error color
--err-color: rgb(8, 8, 8);
// Acent color
--ac-color: #50fa7b;
--ac-sel-color: rgb(80, 250, 123, 0.8);
// Active text color
--act-color: #000000;
}
:root.black {
@include blackTheme;
}
@media (prefers-color-scheme: dark) {
:root.auto {
@include darkTheme;
}
}
@media (prefers-color-scheme: light) {
:root.auto {
@include lightTheme;
}
}

View File

@@ -7,19 +7,19 @@ import * as querystring from "querystring";
* output this: 'msg1=value1&msg2=value2'
* @param dataArguments
*/
function joinDataArguments(dataArguments) {
const joinDataArguments = dataArguments => {
let data = "";
dataArguments.forEach(function (argument, i) {
dataArguments.forEach((argument, i) => {
if (i === 0) {
data += argument;
} else {
data += "&" + argument;
data += `&${argument}`;
}
});
return data;
}
};
function parseCurlCommand(curlCommand) {
const parseCurlCommand = curlCommand => {
let newlineFound = /\r|\n/.exec(curlCommand);
if (newlineFound) {
// remove newlines
@@ -47,7 +47,7 @@ function parseCurlCommand(curlCommand) {
}
let headers;
let parseHeaders = function (headerFieldName) {
const parseHeaders = headerFieldName => {
if (parsedArguments[headerFieldName]) {
if (!headers) {
headers = {};
@@ -55,7 +55,7 @@ function parseCurlCommand(curlCommand) {
if (!Array.isArray(parsedArguments[headerFieldName])) {
parsedArguments[headerFieldName] = [parsedArguments[headerFieldName]];
}
parsedArguments[headerFieldName].forEach(function (header) {
parsedArguments[headerFieldName].forEach(header => {
if (header.includes("Cookie")) {
// stupid javascript tricks: closure
cookieString = header;
@@ -95,17 +95,15 @@ function parseCurlCommand(curlCommand) {
if (!Array.isArray(parsedArguments.F)) {
parsedArguments.F = [parsedArguments.F];
}
parsedArguments.F.forEach(function (multipartArgument) {
parsedArguments.F.forEach(multipartArgument => {
// input looks like key=value. value could be json or a file path prepended with an @
const [key, value] = multipartArgument.split("=", 2);
multipartUploads[key] = value;
});
}
if (cookieString) {
let cookieParseOptions = {
decode: function (s) {
return s;
}
const cookieParseOptions = {
decode: s => s
};
// separate out cookie headers into separate data structure
// note: cookie is case insensitive
@@ -174,8 +172,8 @@ function parseCurlCommand(curlCommand) {
});
urlObject.search = null; // Clean out the search/query portion.
let request = {
url: url,
const request = {
url,
urlWithoutQuery: URL.format(urlObject)
};
if (compressed) {
@@ -223,6 +221,6 @@ function parseCurlCommand(curlCommand) {
request.insecure = true;
}
return request;
}
};
export default parseCurlCommand;

View File

@@ -2,36 +2,39 @@ export default () => {
//*** Determine whether or not the PWA has been installed. ***//
// Step 1: Check local storage
let pwaInstalled = localStorage.getItem('pwaInstalled') === 'yes';
let pwaInstalled = localStorage.getItem("pwaInstalled") === "yes";
// Step 2: Check if the display-mode is standalone. (Only permitted for PWAs.)
if (!pwaInstalled && window.matchMedia('(display-mode: standalone)').matches) {
localStorage.setItem('pwaInstalled', 'yes');
if (
!pwaInstalled &&
window.matchMedia("(display-mode: standalone)").matches
) {
localStorage.setItem("pwaInstalled", "yes");
pwaInstalled = true;
}
// Step 3: Check if the navigator is in standalone mode. (Again, only permitted for PWAs.)
if (!pwaInstalled && window.navigator.standalone === true) {
localStorage.setItem('pwaInstalled', 'yes');
localStorage.setItem("pwaInstalled", "yes");
pwaInstalled = true;
}
//*** If the PWA has not been installed, show the install PWA prompt.. ***//
let deferredPrompt = null;
window.addEventListener('beforeinstallprompt', (event) => {
window.addEventListener("beforeinstallprompt", event => {
deferredPrompt = event;
// Show the install button if the prompt appeared.
if (!pwaInstalled) {
document.querySelector('#installPWA').style.display = 'inline-flex';
document.querySelector("#installPWA").style.display = "inline-flex";
}
});
// When the app is installed, remove install prompts.
window.addEventListener('appinstalled', (event) => {
localStorage.setItem('pwaInstalled', 'yes');
window.addEventListener("appinstalled", event => {
localStorage.setItem("pwaInstalled", "yes");
pwaInstalled = true;
document.getElementById('installPWA').style.display = 'none';
document.getElementById("installPWA").style.display = "none";
});
// When the app is uninstalled, add the prompts back
@@ -40,13 +43,14 @@ export default () => {
deferredPrompt.prompt();
let outcome = await deferredPrompt.userChoice;
if (outcome === 'accepted') {
console.log('Postwoman was installed successfully.')
if (outcome === "accepted") {
console.log("Postwoman was installed successfully.");
} else {
console.log('Postwoman could not be installed. (Installation rejected by user.)')
console.log(
"Postwoman could not be installed. (Installation rejected by user.)"
);
}
deferredPrompt = null;
}
};
};

View File

@@ -1,12 +1,10 @@
const axios = require("axios");
const fs = require("fs");
const {
spawnSync
} = require("child_process");
const { spawnSync } = require("child_process");
const runCommand = (command, args) =>
spawnSync(command, args)
.stdout.toString()
.replace(/\n/g, "");
.stdout.toString()
.replace(/\n/g, "");
const FAIL_ON_ERROR = false;
const PW_BUILD_DATA_DIR = "./.postwoman";
@@ -21,18 +19,24 @@ try {
let version = {};
// Get the current version name as the tag from Git.
version.name = process.env.TRAVIS_TAG || runCommand("git", ["tag"]);
version.name =
process.env.TRAVIS_TAG ||
runCommand("git", ["tag --sort=committerdate | tail -1"]);
// FALLBACK: If version.name was unset, let's grab it from GitHub.
if (!version.name) {
version.name = (await axios
.get("https://api.github.com/repos/liyasthomas/postwoman/releases")
// If we can't get it from GitHub, we'll resort to getting it from package.json
.catch(ex => ({
data: [{
tag_name: require("./package.json").version
}]
}))).data[0]["tag_name"];
version.name = (
await axios
.get("https://api.github.com/repos/liyasthomas/postwoman/releases")
// If we can't get it from GitHub, we'll resort to getting it from package.json
.catch(ex => ({
data: [
{
tag_name: require("./package.json").version
}
]
}))
).data[0]["tag_name"];
}
// Get the current version hash as the short hash from Git.
@@ -41,10 +45,11 @@ try {
version.variant =
process.env.TRAVIS_BRANCH ||
runCommand("git", ["branch"])
.split("* ")[1]
.split(" ")[0] + (IS_DEV_MODE ? " - DEV MODE" : "");
if (["", "master"].includes(version.variant))
.split("* ")[1]
.split(" ")[0] + (IS_DEV_MODE ? " - DEV MODE" : "");
if (["", "master"].includes(version.variant)) {
delete version.variant;
}
// Write version data into a file
fs.writeFileSync(

92
components/ace-editor.vue Normal file
View File

@@ -0,0 +1,92 @@
<template>
<pre ref="editor"></pre>
</template>
<script>
const DEFAULT_THEME = "twilight";
import ace from "ace-builds";
import "ace-builds/webpack-resolver";
export default {
props: {
value: {
type: String,
default: ""
},
theme: {
type: String,
required: false
},
lang: {
type: String,
default: "json"
},
options: {
type: Object,
default: {}
}
},
data() {
return {
editor: null,
cacheValue: ""
};
},
watch: {
value(value) {
if (value !== this.cacheValue) {
this.editor.session.setValue(value, 1);
this.cacheValue = value;
}
},
theme() {
this.editor.setTheme("ace/theme/" + this.defineTheme());
},
lang(value) {
this.editor.getSession().setMode("ace/mode/" + value);
},
options(value) {
this.editor.setOptions(value);
}
},
mounted() {
const editor = ace.edit(this.$refs.editor, {
theme: "ace/theme/" + this.defineTheme(),
mode: "ace/mode/" + this.lang,
...this.options
});
if (this.value) editor.setValue(this.value, 1);
this.editor = editor;
this.cacheValue = this.value;
editor.on("change", () => {
const content = editor.getValue();
this.$emit("input", content);
this.cacheValue = content;
});
},
methods: {
defineTheme() {
if (this.theme) {
return this.theme;
} else {
return (
this.$store.state.postwoman.settings.THEME_ACE_EDITOR || DEFAULT_THEME
);
}
}
},
beforeDestroy() {
this.editor.destroy();
this.editor.container.remove();
}
};
</script>

View File

@@ -3,7 +3,7 @@
<input
type="text"
:placeholder="placeholder"
v-model="value"
v-model="text"
@input="updateSuggestions"
@keyup="updateSuggestions"
@click="updateSuggestions"
@@ -23,12 +23,14 @@
@click.prevent="forceSuggestion(suggestion)"
:class="{ active: currentSuggestionIndex === index }"
:key="index"
>{{ suggestion }}</li>
>
{{ suggestion }}
</li>
</ul>
</div>
</template>
<style lang="scss" scoped>
<style scoped lang="scss">
.autocomplete-wrapper {
position: relative;
@@ -45,20 +47,20 @@
margin: 0 4px;
left: 0;
padding: 0;
border-radius: 0 0 4px 4px;
border-radius: 0 0 8px 8px;
z-index: 9999;
transition: transform 200ms ease-out;
transition: transform 0.2s ease-out;
box-shadow: 0 5px 30px rgba(black, 0.1);
li {
width: 100%;
display: block;
padding: 8px 16px;
font-size: 18px;
font-size: 16px;
font-family: "Roboto Mono", monospace;
white-space: pre-wrap;
&:last-child {
border-radius: 0 0 4px 4px;
border-radius: 0 0 8px 8px;
}
&:hover,
@@ -89,25 +91,31 @@ export default {
placeholder: {
type: String,
default: "Start typing...",
default: "",
required: false
},
source: {
type: Array,
required: true
},
value: {
type: String,
default: "",
required: false
}
},
watch: {
value() {
this.$emit("input", this.value);
text() {
this.$emit("input", this.text);
}
},
data() {
return {
value: "application/json",
text: this.value,
selectionStart: 0,
suggestionsOffsetLeft: 0,
currentSuggestionIndex: -1,
@@ -133,10 +141,10 @@ export default {
},
forceSuggestion(text) {
let input = this.value.substring(0, this.selectionStart);
this.value = input + text;
let input = this.text.substring(0, this.selectionStart);
this.text = input + text;
this.selectionStart = this.value.length;
this.selectionStart = this.text.length;
this.suggestionsVisible = true;
this.currentSuggestionIndex = -1;
},
@@ -165,8 +173,8 @@ export default {
this.currentSuggestionIndex >= 0 ? this.currentSuggestionIndex : 0
];
if (activeSuggestion) {
let input = this.value.substring(0, this.selectionStart);
this.value = input + activeSuggestion;
let input = this.text.substring(0, this.selectionStart);
this.text = input + activeSuggestion;
}
break;
@@ -183,7 +191,7 @@ export default {
* @returns {default.props.source|{type, required}}
*/
suggestions() {
let input = this.value.substring(0, this.selectionStart);
let input = this.text.substring(0, this.selectionStart);
return (
this.source
@@ -195,8 +203,8 @@ export default {
})
// Cut off the part that's already been typed.
.map(entry => entry.substring(this.selectionStart))
// We only want the top 3 suggestions.
.slice(0, 3)
// We only want the top 6 suggestions.
.slice(0, 6)
);
}
},

View File

@@ -22,27 +22,28 @@
</ul>
</div>
<div slot="footer">
<ul>
<li>
<button class="icon" @click="addNewCollection">
<i class="material-icons">add</i>
<span>Create</span>
<div class="flex-wrap">
<span></span>
<span>
<button class="icon" @click="hideModal">
Cancel
</button>
</li>
</ul>
<button class="icon primary" @click="addNewCollection">
Save
</button>
</span>
</div>
</div>
</modal>
</template>
<script>
import modal from "../../components/modal";
export default {
props: {
show: Boolean
},
components: {
modal
modal: () => import("../../components/modal")
},
data() {
return {

View File

@@ -22,21 +22,22 @@
</ul>
</div>
<div slot="footer">
<ul>
<li>
<button class="icon" @click="addNewFolder">
<i class="material-icons">add</i>
<span>Create</span>
<div class="flex-wrap">
<span></span>
<span>
<button class="icon" @click="hideModal">
Cancel
</button>
</li>
</ul>
<button class="icon primary" @click="addNewFolder">
Save
</button>
</span>
</div>
</div>
</modal>
</template>
<script>
import modal from "../../components/modal";
export default {
props: {
show: Boolean,
@@ -44,7 +45,7 @@ export default {
collectionIndex: Number
},
components: {
modal
modal: () => import("../../components/modal")
},
data() {
return {

View File

@@ -6,53 +6,82 @@
<i class="material-icons" v-show="!showChildren">arrow_right</i>
<i class="material-icons" v-show="showChildren">arrow_drop_down</i>
<i class="material-icons">folder</i>
<span>{{collection.name}}</span>
<span>{{ collection.name }}</span>
</button>
</div>
<div>
<button class="icon" @click="removeCollection" v-tooltip="'Delete collection'">
<i class="material-icons">delete</i>
<v-popover>
<button class="tooltip-target icon" v-tooltip="'More'">
<i class="material-icons">more_vert</i>
</button>
<button class="icon" @click="$emit('edit-collection')" v-tooltip="'Edit collection'">
<i class="material-icons">create</i>
</button>
<button class="icon" @click="$emit('add-folder')" v-tooltip="'New Folder'">
<i class="material-icons">create_new_folder</i>
</button>
</div>
<template slot="popover">
<div>
<button class="icon" @click="$emit('add-folder')" v-close-popover>
<i class="material-icons">create_new_folder</i>
<span>New folder</span>
</button>
</div>
<div>
<button
class="icon"
@click="$emit('edit-collection')"
v-close-popover
>
<i class="material-icons">create</i>
<span>Edit</span>
</button>
</div>
<div>
<button class="icon" @click="removeCollection" v-close-popover>
<i class="material-icons">delete</i>
<span>Delete</span>
</button>
</div>
</template>
</v-popover>
</div>
<div v-show="showChildren">
<ul>
<li v-for="(folder, index) in collection.folders" :key="folder.name">
<folder
v-bind:folder="folder"
v-bind:folderIndex="index"
v-bind:collection-index="collectionIndex"
v-on:edit-folder="editFolder(collectionIndex, folder, index)"
v-on:edit-request="$emit('edit-request', $event)"
:folder="folder"
:folderIndex="index"
:collection-index="collectionIndex"
@edit-folder="editFolder(collectionIndex, folder, index)"
@edit-request="$emit('edit-request', $event)"
/>
</li>
<li v-if="(collection.folders.length === 0) && (collection.requests.length === 0)">
<li
v-if="
collection.folders.length === 0 && collection.requests.length === 0
"
>
<label>Collection is empty</label>
</li>
</ul>
<ul>
<li v-for="(request, index) in collection.requests" :key="index">
<request
v-bind:request="request"
v-bind:collection-index="collectionIndex"
v-bind:folder-index="-1"
v-bind:request-index="index"
v-on:edit-request="$emit('edit-request', { request, collectionIndex, folderIndex: undefined, requestIndex: index })"
></request>
:request="request"
:collection-index="collectionIndex"
:folder-index="-1"
:request-index="index"
@edit-request="
$emit('edit-request', {
request,
collectionIndex,
folderIndex: undefined,
requestIndex: index
})
"
/>
</li>
</ul>
</div>
</div>
</template>
<style scoped>
<style scoped lang="scss">
ul {
display: flex;
flex-direction: column;
@@ -66,13 +95,10 @@ ul li {
</style>
<script>
import folder from "./folder";
import request from "./request";
export default {
components: {
folder,
request
folder: () => import("./folder"),
request: () => import("./request")
},
props: {
collectionIndex: Number,
@@ -89,7 +115,7 @@ export default {
this.showChildren = !this.showChildren;
},
removeCollection() {
if (!confirm("Are you sure you want to remove this collection?")) return;
if (!confirm("Are you sure you want to remove this Collection?")) return;
this.$store.commit("postwoman/removeCollection", {
collectionIndex: this.collectionIndex
});

View File

@@ -1,12 +1,12 @@
<template>
<modal v-if="show" @close="hideModel">
<modal v-if="show" @close="hideModal">
<div slot="header">
<ul>
<li>
<div class="flex-wrap">
<h3 class="title">Edit Collection</h3>
<div>
<button class="icon" @click="hideModel">
<button class="icon" @click="hideModal">
<i class="material-icons">close</i>
</button>
</div>
@@ -17,26 +17,32 @@
<div slot="body">
<ul>
<li>
<input type="text" v-model="name" v-bind:placeholder="editingCollection.name" />
<input
type="text"
v-model="name"
:placeholder="editingCollection.name"
@keyup.enter="saveCollection"
/>
</li>
</ul>
</div>
<div slot="footer">
<ul>
<li>
<button class="icon" @click="saveCollection">
<i class="material-icons">save</i>
<span>Save</span>
<div class="flex-wrap">
<span></span>
<span>
<button class="icon" @click="hideModal">
Cancel
</button>
</li>
</ul>
<button class="icon primary" @click="saveCollection">
Save
</button>
</span>
</div>
</div>
</modal>
</template>
<script>
import modal from "../../components/modal";
export default {
props: {
show: Boolean,
@@ -44,7 +50,7 @@ export default {
editingCollectionIndex: Number
},
components: {
modal
modal: () => import("../../components/modal")
},
data() {
return {
@@ -63,7 +69,7 @@ export default {
});
this.$emit("hide-modal");
},
hideModel() {
hideModal() {
this.$emit("hide-modal");
}
}

View File

@@ -17,26 +17,32 @@
<div slot="body">
<ul>
<li>
<input type="text" v-model="name" v-bind:placeholder="folder.name" />
<input
type="text"
v-model="name"
:placeholder="folder.name"
@keyup.enter="editFolder"
/>
</li>
</ul>
</div>
<div slot="footer">
<ul>
<li>
<button class="icon" @click="editFolder">
<i class="material-icons">add</i>
<span>Save</span>
<div class="flex-wrap">
<span></span>
<span>
<button class="icon" @click="hideModal">
Cancel
</button>
</li>
</ul>
<button class="icon primary" @click="editFolder">
Save
</button>
</span>
</div>
</div>
</modal>
</template>
<script>
import modal from "../../components/modal";
export default {
props: {
show: Boolean,
@@ -46,7 +52,7 @@ export default {
folderIndex: Number
},
components: {
modal
modal: () => import("../../components/modal")
},
data() {
return {

View File

@@ -18,40 +18,75 @@
<ul>
<li>
<label for="selectLabel">Label</label>
<input type="text" id="selectLabel" v-model="requestUpdateData.name" :placeholder="request.name" />
<input
type="text"
id="selectLabel"
v-model="requestUpdateData.name"
@keyup.enter="saveRequest"
:placeholder="request.name"
/>
<label for="selectCollection">Collection</label>
<select type="text" id="selectCollection" v-model="requestUpdateData.collectionIndex">
<option :key="undefined" :value="undefined" hidden disabled selected>Current Collection</option>
<option
v-for="(collection, index) in $store.state.postwoman.collections"
:key="index"
:value="index"
>{{ collection.name }}</option>
</select>
<span class="select-wrapper">
<select
type="text"
id="selectCollection"
v-model="requestUpdateData.collectionIndex"
>
<option
:key="undefined"
:value="undefined"
hidden
disabled
selected
>Current Collection</option
>
<option
v-for="(collection, index) in $store.state.postwoman
.collections"
:key="index"
:value="index"
>
{{ collection.name }}
</option>
</select>
</span>
<label for="selectFolder">Folder</label>
<select type="text" id="selectFolder" v-model="requestUpdateData.folderIndex">
<option :key="undefined" :value="undefined">/</option>
<option v-for="(folder, index) in folders" :key="index" :value="index">{{ folder.name }}</option>
</select>
<span class="select-wrapper">
<select
type="text"
id="selectFolder"
v-model="requestUpdateData.folderIndex"
>
<option :key="undefined" :value="undefined">/</option>
<option
v-for="(folder, index) in folders"
:key="index"
:value="index"
>
{{ folder.name }}
</option>
</select>
</span>
</li>
</ul>
</div>
<div slot="footer">
<ul>
<li>
<button class="icon" @click="saveRequest">
<i class="material-icons">save</i>
<span>Save</span>
<div class="flex-wrap">
<span></span>
<span>
<button class="icon" @click="hideModal">
Cancel
</button>
</li>
</ul>
<button class="icon primary" @click="saveRequest">
Save
</button>
</span>
</div>
</div>
</modal>
</template>
<script>
import modal from "../../components/modal";
export default {
props: {
show: Boolean,
@@ -61,7 +96,7 @@ export default {
requestIndex: Number
},
components: {
modal
modal: () => import("../../components/modal")
},
data() {
return {
@@ -107,7 +142,6 @@ export default {
// pass data separately to don't depend on request's collection, folder fields
// probably, they should be deprecated because they don't describe request itself
this.$store.commit("postwoman/editRequest", {
requestOld: this.$props.request,
requestOldCollectionIndex: this.$props.collectionIndex,
requestOldFolderIndex: this.$props.folderIndex,
requestOldIndex: this.$props.requestIndex,

View File

@@ -6,29 +6,47 @@
<i class="material-icons" v-show="!showChildren">arrow_right</i>
<i class="material-icons" v-show="showChildren">arrow_drop_down</i>
<i class="material-icons">folder_open</i>
<span>{{folder.name}}</span>
<span>{{ folder.name }}</span>
</button>
</div>
<div>
<button class="icon" @click="removeFolder" v-tooltip="'Delete folder'">
<i class="material-icons">delete</i>
<v-popover>
<button class="tooltip-target icon" v-tooltip="'More'">
<i class="material-icons">more_vert</i>
</button>
<button class="icon" @click="editFolder" v-tooltip="'Edit folder'">
<i class="material-icons">edit</i>
</button>
</div>
<template slot="popover">
<div>
<button class="icon" @click="editFolder" v-close-popover>
<i class="material-icons">edit</i>
<span>Edit</span>
</button>
</div>
<div>
<button class="icon" @click="removeFolder" v-close-popover>
<i class="material-icons">delete</i>
<span>Delete</span>
</button>
</div>
</template>
</v-popover>
</div>
<div v-show="showChildren">
<ul>
<li v-for="(request, index) in folder.requests" :key="index">
<request
v-bind:request="request"
v-bind:collection-index="collectionIndex"
v-bind:folder-index="folderIndex"
v-bind:request-index="index"
v-on:edit-request="$emit('edit-request', { request, collectionIndex, folderIndex, requestIndex: index })"
></request>
:request="request"
:collection-index="collectionIndex"
:folder-index="folderIndex"
:request-index="index"
@edit-request="
$emit('edit-request', {
request,
collectionIndex,
folderIndex,
requestIndex: index
})
"
/>
</li>
<li v-if="folder.requests.length === 0">
<label>Folder is empty</label>
@@ -38,7 +56,7 @@
</div>
</template>
<style scoped>
<style scoped lang="scss">
ul {
display: flex;
flex-direction: column;
@@ -52,8 +70,6 @@ ul li {
</style>
<script>
import request from "./request";
export default {
props: {
folder: Object,
@@ -61,7 +77,7 @@ export default {
folderIndex: Number
},
components: {
request
request: () => import("./request")
},
data() {
return {

View File

@@ -1,12 +1,12 @@
<template>
<modal v-if="show" @close="hideModel">
<modal v-if="show" @close="hideModal">
<div slot="header">
<ul>
<li>
<div class="flex-wrap">
<h3 class="title">Import / Export Collections</h3>
<div>
<button class="icon" @click="hideModel">
<button class="icon" @click="hideModal">
<i class="material-icons">close</i>
</button>
</div>
@@ -18,8 +18,8 @@
<textarea v-model="collectionJson" rows="8"></textarea>
</div>
<div slot="footer">
<ul>
<li>
<div class="flex-wrap">
<span>
<button
class="icon"
@click="openDialogChooseFileToReplaceWith"
@@ -34,8 +34,6 @@
ref="inputChooseFileToReplaceWith"
/>
</button>
</li>
<li>
<button
class="icon"
@click="openDialogChooseFileToImportFrom"
@@ -50,27 +48,35 @@
ref="inputChooseFileToImportFrom"
/>
</button>
</li>
<li>
<button class="icon" @click="exportJSON" v-tooltip="'Download file'">
<i class="material-icons">get_app</i>
<span>Export to JSON</span>
</span>
<span></span>
</div>
<div class="flex-wrap">
<span></span>
<span>
<button class="icon" @click="hideModal">
Cancel
</button>
</li>
</ul>
<button
class="icon primary"
@click="exportJSON"
v-tooltip="'Download file'"
>
Export
</button>
</span>
</div>
</div>
</modal>
</template>
<script>
import modal from "../../components/modal";
export default {
props: {
show: Boolean
},
components: {
modal
modal: () => import("../../components/modal")
},
computed: {
collectionJson() {
@@ -78,7 +84,7 @@ export default {
}
},
methods: {
hideModel() {
hideModal() {
this.$emit("hide-modal");
},
openDialogChooseFileToReplaceWith() {

View File

@@ -5,39 +5,39 @@ TODO:
<template>
<div class="collections-wrapper">
<addCollection v-bind:show="showModalAdd" v-on:hide-modal="displayModalAdd(false)"></addCollection>
<addCollection :show="showModalAdd" @hide-modal="displayModalAdd(false)" />
<editCollection
v-bind:show="showModalEdit"
v-bind:editingCollection="editingCollection"
v-bind:editingCollectionIndex="editingCollectionIndex"
v-on:hide-modal="displayModalEdit(false)"
></editCollection>
:show="showModalEdit"
:editingCollection="editingCollection"
:editingCollectionIndex="editingCollectionIndex"
@hide-modal="displayModalEdit(false)"
/>
<addFolder
v-bind:show="showModalAddFolder"
v-bind:collection="editingCollection"
v-bind:collectionIndex="editingCollectionIndex"
v-on:hide-modal="displayModalAddFolder(false)"
></addFolder>
:show="showModalAddFolder"
:collection="editingCollection"
:collectionIndex="editingCollectionIndex"
@hide-modal="displayModalAddFolder(false)"
/>
<editFolder
v-bind:show="showModalEditFolder"
v-bind:collection="editingCollection"
v-bind:collectionIndex="editingCollectionIndex"
v-bind:folder="editingFolder"
v-bind:folderIndex="editingFolderIndex"
v-on:hide-modal="displayModalEditFolder(false)"
></editFolder>
:show="showModalEditFolder"
:collection="editingCollection"
:collectionIndex="editingCollectionIndex"
:folder="editingFolder"
:folderIndex="editingFolderIndex"
@hide-modal="displayModalEditFolder(false)"
/>
<editRequest
v-bind:show="showModalEditRequest"
v-bind:collectionIndex="editingCollectionIndex"
v-bind:folderIndex="editingFolderIndex"
v-bind:request="editingRequest"
v-bind:requestIndex="editingRequestIndex"
v-on:hide-modal="displayModalEditRequest(false)"
></editRequest>
:show="showModalEditRequest"
:collectionIndex="editingCollectionIndex"
:folderIndex="editingFolderIndex"
:request="editingRequest"
:requestIndex="editingRequestIndex"
@hide-modal="displayModalEditRequest(false)"
/>
<importExportCollections
v-bind:show="showModalImportExport"
v-on:hide-modal="displayModalImportExport(false)"
></importExportCollections>
:show="showModalImportExport"
@hide-modal="displayModalImportExport(false)"
/>
<div class="flex-wrap">
<div>
@@ -47,32 +47,57 @@ TODO:
</button>
</div>
<div>
<button class="icon" @click="displayModalImportExport(true)">
<button
class="icon"
@click="displayModalImportExport(true)"
v-tooltip="'Import / Export'"
>
<i class="material-icons">import_export</i>
<span>Import / Export</span>
</button>
<!-- <a
href="https://github.com/liyasthomas/postwoman/wiki/Collections"
target="_blank"
rel="noopener"
>
<button class="icon" v-tooltip="'Wiki'">
<i class="material-icons">help</i>
</button>
</a> -->
</div>
</div>
<ul>
<li v-for="(collection, index) in collections" :key="collection.name">
<collection
v-bind:collection-index="index"
v-bind:collection="collection"
v-on:edit-collection="editCollection(collection, index)"
v-on:add-folder="addFolder(collection, index)"
v-on:edit-folder="editFolder($event)"
v-on:edit-request="editRequest($event)"
></collection>
</li>
<li v-if="collections.length === 0">
<label>Collections are empty</label>
</li>
</ul>
<p v-if="collections.length === 0" class="info">
Create new collection
</p>
<virtual-list
class="virtual-list"
:class="{ filled: collections.length }"
:size="152"
:remain="Math.min(5, collections.length)"
>
<ul>
<li v-for="(collection, index) in collections" :key="collection.name">
<collection
:collection-index="index"
:collection="collection"
@edit-collection="editCollection(collection, index)"
@add-folder="addFolder(collection, index)"
@edit-folder="editFolder($event)"
@edit-request="editRequest($event)"
/>
</li>
<li v-if="collections.length === 0">
<label>Collections are empty</label>
</li>
</ul>
</virtual-list>
</div>
</template>
<style lang="scss" scoped>
<style scoped lang="scss">
.virtual-list {
max-height: calc(100vh - 232px);
}
ul {
display: flex;
flex-direction: column;
@@ -80,23 +105,18 @@ ul {
</style>
<script>
import addCollection from "./addCollection";
import addFolder from "./addFolder";
import collection from "./collection";
import editCollection from "./editCollection";
import editFolder from "./editFolder";
import editRequest from "./editRequest";
import importExportCollections from "./importExportCollections";
export default {
components: {
addCollection,
addFolder,
collection,
editCollection,
editFolder,
editRequest,
importExportCollections
addCollection: () => import("./addCollection"),
addFolder: () => import("./addFolder"),
editCollection: () => import("./editCollection"),
editFolder: () => import("./editFolder"),
editRequest: () => import("./editRequest"),
importExportCollections: () => import("./importExportCollections"),
VirtualList: () => import("vue-virtual-scroll-list")
},
data() {
return {

View File

@@ -3,21 +3,32 @@
<div>
<button class="icon" @click="selectRequest()" v-tooltip="'Use request'">
<i class="material-icons">insert_drive_file</i>
<span>{{request.name}}</span>
<span>{{ request.name }}</span>
</button>
</div>
<div>
<button class="icon" @click="removeRequest" v-tooltip="'Delete request'">
<i class="material-icons">delete</i>
<v-popover>
<button class="tooltip-target icon" v-tooltip="'More'">
<i class="material-icons">more_vert</i>
</button>
<button class="icon" @click="$emit('edit-request')" v-tooltip="'Edit request'">
<i class="material-icons">edit</i>
</button>
</div>
<template slot="popover">
<div>
<button class="icon" @click="$emit('edit-request')" v-close-popover>
<i class="material-icons">edit</i>
<span>Edit</span>
</button>
</div>
<div>
<button class="icon" @click="removeRequest" v-close-popover>
<i class="material-icons">delete</i>
<span>Delete</span>
</button>
</div>
</template>
</v-popover>
</div>
</template>
<style scoped>
<style scoped lang="scss">
ul {
display: flex;
flex-direction: column;

View File

@@ -22,61 +22,99 @@
type="text"
id="selectLabel"
v-model="requestData.name"
v-bind:placeholder="defaultRequestName"
:placeholder="defaultRequestName"
@keyup.enter="saveRequestAs"
/>
<label for="selectCollection">Collection</label>
<select type="text" id="selectCollection" v-model="requestData.collectionIndex">
<option :key="undefined" :value="undefined" hidden disabled selected>Select a Collection</option>
<option
v-for="(collection, index) in $store.state.postwoman.collections"
:key="index"
:value="index"
>{{ collection.name }}</option>
</select>
<span class="select-wrapper">
<select
type="text"
id="selectCollection"
v-model="requestData.collectionIndex"
>
<option
:key="undefined"
:value="undefined"
hidden
disabled
selected
>Select a Collection</option
>
<option
v-for="(collection, index) in $store.state.postwoman
.collections"
:key="index"
:value="index"
>
{{ collection.name }}
</option>
</select>
</span>
<label for="selectFolder">Folder</label>
<select type="text" id="selectFolder" v-model="requestData.folderIndex">
<option :key="undefined" :value="undefined">/</option>
<option v-for="(folder, index) in folders" :key="index" :value="index">{{ folder.name }}</option>
</select>
<span class="select-wrapper">
<select
type="text"
id="selectFolder"
v-model="requestData.folderIndex"
>
<option :key="undefined" :value="undefined">/</option>
<option
v-for="(folder, index) in folders"
:key="index"
:value="index"
>
{{ folder.name }}
</option>
</select>
</span>
<label for="selectRequest">Request</label>
<select type="text" id="selectRequest" v-model="requestData.requestIndex">
<option :key="undefined" :value="undefined">/</option>
<option
v-for="(folder, index) in requests"
:key="index"
:value="index"
>{{ folder.name }}</option>
</select>
<span class="select-wrapper">
<select
type="text"
id="selectRequest"
v-model="requestData.requestIndex"
>
<option :key="undefined" :value="undefined">/</option>
<option
v-for="(folder, index) in requests"
:key="index"
:value="index"
>
{{ folder.name }}
</option>
</select>
</span>
</li>
</ul>
</div>
<div slot="footer">
<ul>
<li>
<button class="icon" @click="saveRequestAs">
<i class="material-icons">save</i>
<span>Save</span>
<div class="flex-wrap">
<span></span>
<span>
<button class="icon" @click="hideModal">
Cancel
</button>
</li>
</ul>
<button class="icon primary" @click="saveRequestAs">
Save
</button>
</span>
</div>
</div>
</modal>
</template>
<script>
import modal from "../../components/modal";
export default {
props: {
show: Boolean,
editingRequest: Object
},
components: {
modal
modal: () => import("../../components/modal")
},
data() {
return {
defaultRequestName: "My New Request",
defaultRequestName: "My Request",
requestData: {
name: undefined,
collectionIndex: undefined,
@@ -102,6 +140,12 @@ export default {
this.$data.requestData.collectionIndex !== undefined;
if (!userSelectedAnyCollection) return [];
const noCollectionAvailable =
this.$store.state.postwoman.collections[
this.$data.requestData.collectionIndex
] !== undefined;
if (!noCollectionAvailable) return [];
return this.$store.state.postwoman.collections[
this.$data.requestData.collectionIndex
].folders;
@@ -124,6 +168,12 @@ export default {
const collection = this.$store.state.postwoman.collections[
this.$data.requestData.collectionIndex
];
const noCollectionAvailable =
this.$store.state.postwoman.collections[
this.$data.requestData.collectionIndex
] !== undefined;
if (!noCollectionAvailable) return [];
const requests = collection.requests;
return requests;
}

View File

@@ -0,0 +1,62 @@
<template>
<div class="field-box">
<div class="field-title">{{ fieldString }}</div>
<div class="field-desc" v-if="gqlField.description">
{{ gqlField.description }}
</div>
<div class="field-deprecated" v-if="gqlField.isDeprecated">
DEPRECATED
</div>
</div>
</template>
<style>
.field-box {
padding: 16px;
margin: 4px;
border-bottom: 1px dashed var(--brd-color);
}
.field-deprecated {
background-color: yellow;
color: black;
display: inline-block;
padding: 4px 8px;
margin: 4px 0;
border-radius: 4px;
font-size: 14px;
font-weight: 700;
}
.field-desc {
color: var(--fg-light-color);
margin-top: 4px;
}
</style>
<script>
export default {
props: {
gqlField: Object
},
computed: {
fieldString() {
const args = (this.gqlField.args || []).reduce((acc, arg, index) => {
return (
acc +
`${arg.name}: ${arg.type.toString()}${
index !== this.gqlField.args.length - 1 ? ", " : ""
}`
);
}, "");
const argsString = args.length > 0 ? `(${args})` : "";
return `${
this.gqlField.name
}${argsString}: ${this.gqlField.type.toString()}`;
}
}
};
</script>

View File

@@ -0,0 +1,42 @@
<template>
<div class="type-box">
<div class="type-title">{{ gqlType.name }}</div>
<div class="type-desc" v-if="gqlType.description">
{{ gqlType.description }}
</div>
<div v-if="gqlType.getFields">
<h5>FIELDS</h5>
<div v-for="field in gqlType.getFields()" :key="field.name">
<gql-field :gqlField="field" />
</div>
</div>
</div>
</template>
<style>
.type-box {
padding: 16px;
margin: 4px 0;
}
.type-desc {
color: var(--fg-light-color);
margin-top: 4px;
}
.type-title {
font-weight: 700;
}
</style>
<script>
export default {
components: {
"gql-field": () => import("./field")
},
props: {
gqlType: {}
}
};
</script>

View File

@@ -6,132 +6,167 @@
aria-label="Search"
type="text"
placeholder="search history"
:readonly="history.length === 0"
v-model="filterText"
/>
</li>
</ul>
<ul>
<li></li>
<li @click="sort_by_label()">
<label>
Label
</label>
</li>
<li @click="sort_by_time()">
<label>
Time
</label>
</li>
<li @click="sort_by_status_code()">
<label>
Status
</label>
</li>
<li @click="sort_by_url()">
<label>
URL
</label>
</li>
<li @click="sort_by_path()">
<label>
Path
</label>
</li>
<li></li>
</ul>
<virtual-list
class="virtual-list"
:class="{filled: filteredHistory.length}"
:size="54"
:class="{ filled: filteredHistory.length }"
:size="185"
:remain="Math.min(5, filteredHistory.length)"
>
<ul v-for="(entry, index) in filteredHistory" :key="index" class="entry">
<li>
<button v-if="entry.usesScripts"
v-tooltip="'This entry used pre-request scripts'"
<div class="show-on-large-screen">
<button
class="icon"
:class="{ stared: entry.star }"
@click="toggleStar(index)"
v-tooltip="{ content: !entry.star ? 'Add star' : 'Remove star' }"
>
<i class="material-icons">code</i>
<i class="material-icons">
{{ entry.star ? "star" : "star_border" }}
</i>
</button>
<button v-else
v-tooltip="'No pre-request scripts'"
class="icon"
>
<i class="material-icons">http</i>
</button>
</li>
<li>
<input
aria-label="Label"
type="text"
readonly
:value="entry.label"
placeholder="No label"
/>
</li>
<li>
<input aria-label="Time" type="text" readonly :value="entry.time" v-tooltip="entry.date" />
</li>
<li class="method-list-item">
<input
aria-label="Method"
type="text"
readonly
:value="entry.method"
:class="findEntryStatus(entry).className"
:style="{'--status-code': entry.status}"
/>
<span
class="entry-status-code"
:class="findEntryStatus(entry).className"
:style="{'--status-code': entry.status}"
>{{entry.status}}</span>
</li>
<li>
<input aria-label="URL" type="text" readonly :value="entry.url" />
</li>
<li>
<input aria-label="Path" type="text" readonly :value="entry.path" placeholder="No path" />
</li>
<div class="show-on-small-screen">
<li>
<button
v-tooltip="'Delete entry'"
class="icon"
:id="'delete-button#'+index"
@click="deleteHistory(entry)"
aria-label="Delete"
>
<i class="material-icons">delete</i>
</button>
<input
aria-label="Label"
type="text"
readonly
:value="entry.label"
placeholder="No label"
class="bg-color"
/>
</li>
<li>
<!-- <li>
<button
v-tooltip="'Edit entry'"
class="icon"
:id="'use-button#'+index"
@click="useHistory(entry)"
aria-label="Edit"
v-tooltip="{
content: !entry.usesScripts
? 'No pre-request script'
: 'Used pre-request script'
}"
>
<i class="material-icons">edit</i>
<i class="material-icons">
{{ !entry.usesScripts ? "http" : "code" }}
</i>
</button>
</li> -->
<v-popover>
<button class="tooltip-target icon" v-tooltip="'Options'">
<i class="material-icons">more_vert</i>
</button>
<template slot="popover">
<div>
<button
class="icon"
:id="'use-button#' + index"
@click="useHistory(entry)"
aria-label="Edit"
v-close-popover
>
<i class="material-icons">restore</i>
<span>Restore</span>
</button>
</div>
<div>
<button
class="icon"
:id="'delete-button#' + index"
@click="deleteHistory(entry)"
aria-label="Delete"
v-close-popover
>
<i class="material-icons">delete</i>
<span>Delete</span>
</button>
</div>
</template>
</v-popover>
</div>
<div class="show-on-large-screen">
<li class="method-list-item">
<input
aria-label="Method"
type="text"
readonly
:value="entry.method"
:class="findEntryStatus(entry).className"
:style="{ '--status-code': entry.status }"
/>
<span
class="entry-status-code"
:class="findEntryStatus(entry).className"
:style="{ '--status-code': entry.status }"
>{{ entry.status }}</span
>
</li>
</div>
<div class="show-on-large-screen">
<li>
<input
aria-label="URL"
type="text"
readonly
:value="entry.url"
placeholder="No URL"
/>
</li>
<li>
<input
aria-label="Path"
type="text"
readonly
:value="entry.path"
placeholder="No path"
/>
</li>
</div>
<transition name="fade">
<div v-if="showMore" class="show-on-large-screen">
<li>
<input
aria-label="Time"
type="text"
readonly
:value="entry.time"
v-tooltip="entry.date"
/>
</li>
<li>
<input
aria-label="Duration"
type="text"
readonly
:value="entry.duration"
placeholder="No duration"
/>
</li>
<li>
<input
aria-label="Pre Request Script"
type="text"
readonly
:value="entry.preRequestScript"
placeholder="No pre request script"
/>
</li>
</div>
</transition>
</ul>
</virtual-list>
<ul :class="{hidden: filteredHistory.length != 0 || history.length === 0 }">
<ul
:class="{ hidden: filteredHistory.length != 0 || history.length === 0 }"
>
<li>
<label>Nothing found "{{filterText}}"</label>
<label>Nothing found "{{ filterText }}"</label>
</li>
</ul>
<ul v-if="history.length === 0">
<li>
<label>History is empty</label>
</li>
</ul>
<ul v-if="history.length !== 0">
<li v-if="!isClearingHistory">
<p v-if="history.length === 0" class="info">
History is empty
</p>
<div v-if="history.length !== 0">
<div class="flex-wrap" v-if="!isClearingHistory">
<button
class="icon"
id="clear-history-button"
@@ -141,192 +176,326 @@
<i class="material-icons">clear_all</i>
<span>Clear All</span>
</button>
</li>
<li v-else>
<div class="flex-wrap">
<label for="clear-history-button">Are you sure?</label>
<div>
<button class="icon" id="confirm-clear-history-button" @click="clearHistory">Yes</button>
<button class="icon" id="reject-clear-history-button" @click="disableHistoryClearing">No</button>
</div>
<v-popover>
<button class="tooltip-target icon" v-tooltip="'Sort'">
<i class="material-icons">sort</i>
</button>
<template slot="popover">
<div>
<button class="icon" @click="sort_by_label()" v-close-popover>
<i class="material-icons">sort_by_alpha</i>
<span>Label</span>
</button>
</div>
<div>
<button class="icon" @click="sort_by_time()" v-close-popover>
<i class="material-icons">access_time</i>
<span>Time</span>
</button>
</div>
<div>
<button
class="icon"
@click="sort_by_status_code()"
v-close-popover
>
<i class="material-icons">assistant</i>
<span>Status</span>
</button>
</div>
<div>
<button class="icon" @click="sort_by_url()" v-close-popover>
<i class="material-icons">language</i>
<span>URL</span>
</button>
</div>
<div>
<button class="icon" @click="sort_by_path()" v-close-popover>
<i class="material-icons">timeline</i>
<span>Path</span>
</button>
</div>
<div v-if="showMore">
<button class="icon" @click="sort_by_duration()" v-close-popover>
<i class="material-icons">timer</i>
<span>Duration</span>
</button>
</div>
<div>
<button class="icon" @click="toggleCollapse()">
<i class="material-icons">
{{ !showMore ? "first_page" : "last_page" }}
</i>
<span>{{ !showMore ? "Show more" : "Hide more" }}</span>
</button>
</div>
</template>
</v-popover>
</div>
<div class="flex-wrap" v-else>
<label for="clear-history-button" class="info">Are you sure?</label>
<div>
<button
class="icon"
id="confirm-clear-history-button"
@click="clearHistory"
v-tooltip="'Yes'"
>
<i class="material-icons">done</i>
</button>
<button
class="icon"
id="reject-clear-history-button"
@click="disableHistoryClearing"
v-tooltip="'No'"
>
<i class="material-icons">close</i>
</button>
</div>
</li>
</ul>
</div>
</div>
</pw-section>
</template>
<style scoped lang="scss">
.virtual-list {
[readonly] {
cursor: default;
}
.virtual-list {
max-height: calc(100vh - 284px);
[readonly] {
cursor: default;
}
}
.fade-enter-active,
.fade-leave-active {
transition: all 0.2s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.stared {
color: #f8e81c !important;
}
ul,
ol {
flex-direction: column;
}
ul li,
ol li {
display: flex;
}
.method-list-item {
position: relative;
span {
position: absolute;
top: 10px;
right: 10px;
font-family: "Roboto Mono", monospace;
background-color: transparent;
padding: 2px 6px;
border-radius: 8px;
}
}
.entry {
border-bottom: 1px dashed var(--brd-color);
padding: 0 0 8px;
}
.bg-color {
background-color: transparent;
}
@media (max-width: 720px) {
.virtual-list.filled {
min-height: 320px;
}
label {
&:hover {
cursor: pointer;
color: var(--fg-color);
}
}
@media (max-width: 720px) {
.virtual-list.filled {
min-height: 200px;
}
.labels {
display: none;
}
}
</style>
<script>
import VirtualList from "vue-virtual-scroll-list";
import section from "./section";
import { findStatusGroup } from "../pages/index";
import { findStatusGroup } from "../pages/index";
const updateOnLocalStorage = (propertyName, property) =>
window.localStorage.setItem(propertyName, JSON.stringify(property));
export default {
components: {
"pw-section": section,
VirtualList
},
data() {
const localStorageHistory = JSON.parse(
window.localStorage.getItem("history")
);
return {
history: localStorageHistory || [],
filterText: "",
showFilter: false,
isClearingHistory: false,
reverse_sort_label: false,
reverse_sort_time: false,
reverse_sort_status_code: false,
reverse_sort_url: false,
reverse_sort_path: false
};
},
computed: {
filteredHistory() {
return this.history.filter(entry => {
const filterText = this.filterText.toLowerCase();
return Object.keys(entry).some(key => {
let value = entry[key];
value = typeof value !== "string" ? value.toString() : value;
return value.toLowerCase().includes(filterText);
});
const updateOnLocalStorage = (propertyName, property) =>
window.localStorage.setItem(propertyName, JSON.stringify(property));
export default {
components: {
"pw-section": () => import("./section"),
VirtualList: () => import("vue-virtual-scroll-list")
},
data() {
const localStorageHistory = JSON.parse(
window.localStorage.getItem("history")
);
return {
history: localStorageHistory || [],
filterText: "",
showFilter: false,
isClearingHistory: false,
reverse_sort_label: false,
reverse_sort_time: false,
reverse_sort_status_code: false,
reverse_sort_url: false,
reverse_sort_path: false,
showMore: false
};
},
computed: {
filteredHistory() {
return this.history.filter(entry => {
const filterText = this.filterText.toLowerCase();
return Object.keys(entry).some(key => {
let value = entry[key];
value = typeof value !== "string" ? value.toString() : value;
return value.toLowerCase().includes(filterText);
});
}
},
methods: {
clearHistory() {
this.history = [];
this.filterText = "";
this.disableHistoryClearing();
updateOnLocalStorage("history", this.history);
this.$toast.error("History Deleted", {
icon: "delete"
});
},
useHistory(entry) {
this.$emit("useHistory", entry);
},
findEntryStatus(entry) {
const foundStatusGroup = findStatusGroup(entry.status);
return (
foundStatusGroup || {
className: ""
}
);
},
deleteHistory(entry) {
this.history.splice(this.history.indexOf(entry), 1);
if (this.history.length === 0) {
this.filterText = "";
}
updateOnLocalStorage("history", this.history);
this.$toast.error("Deleted", {
icon: "delete"
});
},
addEntry(entry) {
this.history.push(entry);
updateOnLocalStorage("history", this.history);
},
enableHistoryClearing() {
if (!this.history || !this.history.length) return;
this.isClearingHistory = true;
},
disableHistoryClearing() {
this.isClearingHistory = false;
},
sort_by_time() {
let byDate = this.history.slice(0);
byDate.sort((a, b) => {
let date_a = a.date.split("/");
let date_b = b.date.split("/");
let time_a = a.time.split(":");
let time_b = b.time.split(":");
let final_a = new Date(
date_a[2],
date_a[1],
date_a[0],
time_a[0],
time_a[1],
time_a[2]
);
let final_b = new Date(
date_b[2],
date_b[1],
date_b[0],
time_b[0],
time_b[1],
time_b[2]
);
if (this.reverse_sort_time) return final_b - final_a;
else return final_a - final_b;
});
this.history = byDate;
this.reverse_sort_time = !this.reverse_sort_time;
},
sort_by_status_code() {
let byCode = this.history.slice(0);
byCode.sort((a, b) => {
if (this.reverse_sort_status_code) return b.status - a.status;
else return a.status - b.status;
});
this.history = byCode;
this.reverse_sort_status_code = !this.reverse_sort_status_code;
},
sort_by_url() {
let byUrl = this.history.slice(0);
byUrl.sort((a, b) => {
if (this.reverse_sort_url)
return a.url == b.url ? 0 : +(a.url < b.url) || -1;
else return a.url == b.url ? 0 : +(a.url > b.url) || -1;
});
this.history = byUrl;
this.reverse_sort_url = !this.reverse_sort_url;
},
sort_by_label() {
let byLabel = this.history.slice(0);
byLabel.sort((a, b) => {
if (this.reverse_sort_label)
return a.label == b.label ? 0 : +(a.label < b.label) || -1;
else return a.label == b.label ? 0 : +(a.label > b.label) || -1;
});
this.history = byLabel;
this.reverse_sort_label = !this.reverse_sort_label;
},
sort_by_path() {
let byPath = this.history.slice(0);
byPath.sort((a, b) => {
if (this.reverse_sort_path)
return a.path == b.path ? 0 : +(a.path < b.path) || -1;
else return a.path == b.path ? 0 : +(a.path > b.path) || -1;
});
this.history = byPath;
this.reverse_sort_path = !this.reverse_sort_path;
}
});
}
};
},
methods: {
clearHistory() {
this.history = [];
this.filterText = "";
this.disableHistoryClearing();
updateOnLocalStorage("history", this.history);
this.$toast.error("History Deleted", {
icon: "delete"
});
},
useHistory(entry) {
this.$emit("useHistory", entry);
},
findEntryStatus(entry) {
const foundStatusGroup = findStatusGroup(entry.status);
return (
foundStatusGroup || {
className: ""
}
);
},
deleteHistory(entry) {
this.history.splice(this.history.indexOf(entry), 1);
if (this.history.length === 0) {
this.filterText = "";
}
updateOnLocalStorage("history", this.history);
this.$toast.error("Deleted", {
icon: "delete"
});
},
addEntry(entry) {
this.history.push(entry);
updateOnLocalStorage("history", this.history);
},
enableHistoryClearing() {
if (!this.history || !this.history.length) return;
this.isClearingHistory = true;
},
disableHistoryClearing() {
this.isClearingHistory = false;
},
sort_by_time() {
let byDate = this.history.slice(0);
byDate.sort((a, b) => {
let date_a = a.date.split("/");
let date_b = b.date.split("/");
let time_a = a.time.split(":");
let time_b = b.time.split(":");
let final_a = new Date(
date_a[2],
date_a[1],
date_a[0],
time_a[0],
time_a[1],
time_a[2]
);
let final_b = new Date(
date_b[2],
date_b[1],
date_b[0],
time_b[0],
time_b[1],
time_b[2]
);
if (this.reverse_sort_time) return final_b - final_a;
else return final_a - final_b;
});
this.history = byDate;
this.reverse_sort_time = !this.reverse_sort_time;
},
sort_by_status_code() {
let byCode = this.history.slice(0);
byCode.sort((a, b) => {
if (this.reverse_sort_status_code) return b.status - a.status;
else return a.status - b.status;
});
this.history = byCode;
this.reverse_sort_status_code = !this.reverse_sort_status_code;
},
sort_by_url() {
let byUrl = this.history.slice(0);
byUrl.sort((a, b) => {
if (this.reverse_sort_url)
return a.url === b.url ? 0 : +(a.url < b.url) || -1;
else return a.url === b.url ? 0 : +(a.url > b.url) || -1;
});
this.history = byUrl;
this.reverse_sort_url = !this.reverse_sort_url;
},
sort_by_label() {
let byLabel = this.history.slice(0);
byLabel.sort((a, b) => {
if (this.reverse_sort_label)
return a.label === b.label ? 0 : +(a.label < b.label) || -1;
else return a.label === b.label ? 0 : +(a.label > b.label) || -1;
});
this.history = byLabel;
this.reverse_sort_label = !this.reverse_sort_label;
},
sort_by_path() {
let byPath = this.history.slice(0);
byPath.sort((a, b) => {
if (this.reverse_sort_path)
return a.path === b.path ? 0 : +(a.path < b.path) || -1;
else return a.path === b.path ? 0 : +(a.path > b.path) || -1;
});
this.history = byPath;
this.reverse_sort_path = !this.reverse_sort_path;
},
sort_by_duration() {
let byDuration = this.history.slice(0);
byDuration.sort((a, b) => {
if (this.reverse_sort_duration)
return a.duration === b.duration
? 0
: +(a.duration < b.duration) || -1;
else
return a.duration === b.duration
? 0
: +(a.duration > b.duration) || -1;
});
this.history = byDuration;
this.reverse_sort_duration = !this.reverse_sort_duration;
},
toggleCollapse() {
this.showMore = !this.showMore;
},
toggleStar(index) {
this.history[index]["star"] = !this.history[index]["star"];
updateOnLocalStorage("history", this.history);
}
}
};
</script>

View File

@@ -24,9 +24,9 @@
<path
:fill="color"
id="path3816"
data-old_color="#121212"
data-old_color="#202124"
class="active-path"
data-original="#121212"
data-original="#202124"
d="M 64.601,236.822 C 64.601,394.256 192.786,612 306.001,612 412.582,612 547.4,394.256 547.4,236.822 547.4,79.388 439.322,0 306,0 172.678,0 64.601,79.388 64.601,236.822 Z m 304.12,116.415 c 29.475,-29.475 70.598,-40.195 108.552,-32.173 8.021,37.954 -2.698,79.077 -32.173,108.552 -29.475,29.475 -70.598,40.195 -108.552,32.173 -8.022,-37.955 2.698,-79.078 32.173,-108.552 z M 134.727,321.063 c 37.954,-8.021 79.077,2.698 108.552,32.173 29.475,29.475 40.195,70.598 32.173,108.552 -37.954,8.021 -79.077,-2.698 -108.552,-32.173 -29.475,-29.476 -40.194,-70.598 -32.173,-108.552 z"
/>
</g>
@@ -35,7 +35,7 @@
</svg>
</template>
<style>
<style scoped lang="scss">
#circle3814 {
/* fill: var(--fg-color); */
fill: transparent;

View File

@@ -1,5 +1,5 @@
<template>
<transition name="modal-fade">
<transition name="modal" appear>
<div class="modal-backdrop">
<div class="modal-wrapper">
<div class="modal-container">
@@ -17,7 +17,7 @@
</div>
</transition>
</template>
<style scoped>
<style scoped lang="scss">
.modal-backdrop {
position: fixed;
z-index: 998;
@@ -25,7 +25,7 @@
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
background-color: rgba(0, 0, 0, 0.87);
display: flex;
align-items: center;
justify-content: center;
@@ -37,7 +37,7 @@
align-items: center;
justify-content: center;
flex-grow: 1;
max-width: 800px;
max-width: 720px;
}
.modal-container {
@@ -45,11 +45,11 @@
flex-grow: 1;
flex-direction: column;
margin: 8px;
padding: 12px;
padding: 16px;
transition: all 0.2s ease;
background-color: var(--bg-color);
border-radius: 8px;
box-shadow: rgba(0, 0, 0, 0.5) 0px 16px 70px;
border-radius: 16px;
box-shadow: 0px 16px 70px rgba(0, 0, 0, 0.5);
}
/*
@@ -61,13 +61,13 @@
* these styles.
*/
.modal-fade-enter,
.modal-fade-leave-active {
.modal-enter,
.modal-leave-active {
opacity: 0;
}
.modal-fade-enter .modal-container,
.modal-fade-leave-active .modal-container {
.modal-enter .modal-container,
.modal-leave-active .modal-container {
transform: scale(0.8);
transition: all 0.2s ease-in-out;
}

View File

@@ -1,9 +1,13 @@
<template>
<fieldset :id="label.toLowerCase()" :class="{ 'no-colored-frames': !frameColorsEnabled }">
<fieldset
:id="label.toLowerCase()"
:class="{ 'no-colored-frames': !frameColorsEnabled }"
>
<legend @click.prevent="collapse">
<span>{{ label }}</span>
<i class="material-icons" v-if="isCollapsed">expand_more</i>
<i class="material-icons" v-if="!isCollapsed">expand_less</i>
<i class="material-icons">
{{ isCollapsed ? "expand_more" : "expand_less" }}
</i>
</legend>
<div class="collapsible" :class="{ hidden: collapsed }">
<slot />

View File

@@ -1,34 +1,42 @@
<template>
<div class="color" :data-color="color">
<span :style="{backgroundColor: color}" class="preview">
<div
class="color"
:data-color="color"
:class="{ active: active }"
v-tooltip="{ content: name || color }"
>
<span :style="{ backgroundColor: color }" class="preview">
<i v-if="active" class="material-icons activeTick">done</i>
</span>
{{ name || color }}
</div>
</template>
<style lang="scss">
<style scoped lang="scss">
.color {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0 16px 0 4px;
margin: 4px;
background-color: var(--bg-dark-color);
color: var(--fg-color);
border-radius: 20px;
margin: 8px;
border-radius: 100%;
border: 3px solid var(--bg-dark-color);
cursor: pointer;
height: 40px;
&.fg {
color: var(--act-color);
}
&.active {
background-color: var(--bg-dark-color);
border: 3px solid var(--ac-color);
}
&.fg.active {
border: 3px solid var(--fg-color);
}
.preview {
vertical-align: middle;
display: inline-block;
border-radius: 100%;
margin-right: 8px;
padding: 16px;
position: relative;
@@ -37,16 +45,9 @@
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #ffffff;
}
}
}
.color.vibrant {
.preview .activeTick {
color: var(--act-color);
}
}
</style>
<script>

View File

@@ -1,6 +1,6 @@
<template>
<div @click="toggle()">
<label class="toggle" :class="{on: on}" ref="toggle">
<label class="toggle" :class="{ on: on }" ref="toggle">
<span class="handle"></span>
</label>
<label class="caption">
@@ -9,7 +9,7 @@
</div>
</template>
<style lang="scss" scoped>
<style scoped lang="scss">
$useBorder: false;
$borderColor: var(--fg-light-color);
$activeColor: var(--ac-color);

View File

@@ -1,9 +1,9 @@
{
"baseUrl": "http://localhost:3000",
"integrationFolder": "tests/e2e/integration",
"screenshotsFolder": "tests/e2e/screenshots",
"fixturesFolder": "tests/e2e/fixtures",
"supportFile": "tests/e2e/support",
"pluginsFile": false,
"video": false
"baseUrl": "http://localhost:3000",
"integrationFolder": "tests/e2e/integration",
"screenshotsFolder": "tests/e2e/screenshots",
"fixturesFolder": "tests/e2e/fixtures",
"supportFile": "tests/e2e/support",
"pluginsFile": false,
"video": false
}

View File

@@ -1,7 +1,6 @@
{
/* Visit https://firebase.google.com/docs/database/security to learn more about security rules. */
"rules": {
".read": false,
".write": false
}
}
}

View File

@@ -1,8 +1,8 @@
export default {
name: "textareaAutoHeight",
update(element) {
if (element.scrollHeight !== element.clientHeight) {
element.style.minHeight = `${element.scrollHeight}px`;
update({ scrollHeight, clientHeight, style }) {
if (scrollHeight !== clientHeight) {
style.minHeight = `${scrollHeight}px`;
}
}
}
};

View File

@@ -14,6 +14,7 @@ services:
- "./plugins:/app/plugins"
- "./static:/app/static"
- "./store:/app/store"
- "./components:/app/components"
ports:
- "3000:3000"
command: "npm run dev"

15
docs/index.html Normal file
View File

@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Postwoman</title>
<meta http-equiv="refresh" content="0; url=https://postwoman.io" />
<link rel="canonical" href="https://postwoman.io" />
</head>
<body>
Redirecting to postwoman.io
</body>
</html>

View File

@@ -1,4 +1,4 @@
const functions = require('firebase-functions');
// const functions = require('firebase-functions');
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions

View File

@@ -5,13 +5,16 @@ export default function getEnvironmentVariablesFromScript(script) {
// for security and control purposes, this is the only way a pre-request script should modify variables.
let pw = {
environment: {
set: (key, value) => _variables[key] = value,
set: (key, value) => (_variables[key] = value)
},
env: {
set: (key, value) => (_variables[key] = value)
}
// globals that the script is allowed to have access to.
};
// run pre-request script within this function so that it has access to the pw object.
(new Function('pw', script))(pw);
new Function("pw", script)(pw);
return _variables;
}

View File

@@ -1,7 +1,7 @@
export default function parseTemplateString(string, variables) {
if(!variables || !string) {
return string;
}
const searchTerm = /<<([^>]*)>>/g; // "<<myVariable>>"
return string.replace(searchTerm, (match, p1) => variables[p1] || '');
if (!variables || !string) {
return string;
}
const searchTerm = /<<([^>]*)>>/g; // "<<myVariable>>"
return string.replace(searchTerm, (match, p1) => variables[p1] || "");
}

90
lang/de-DE.js Normal file
View File

@@ -0,0 +1,90 @@
export default {
home: "Startseite",
realtime: "Echtzeit",
graphql: "GraphQL",
settings: "Einstellungen",
request: "Anfrage",
install_pwa: "PWA installieren",
support_us: "Unterstütze uns",
tweet: "Twittern",
options: "Optionen",
communication: "Kommunikation",
endpoint: "Endpunkt",
schema: "Schema",
theme: "Design",
subscribe: "Abonnieren",
choose_language: "Sprache auswählen",
shortcuts: "Tastenkombinationen",
send_request: "Anfrage senden",
save_to_collections: "In Sammlungen speichern",
copy_request_link: "Anfragelink kopieren",
reset_request: "Anfrage zurücksetzen",
support_us_on: "Unterstütze uns auf",
open_collective: "Open Collective",
paypal: "PayPal",
patreon: "Patreon",
javascript_code: "JavaScript-Code",
method: "Methode",
path: "Pfad",
label: "Beschriftung",
again: "Wiederholen",
content_type: "Content-Typ",
raw_input: "Rohdaten-Eingabe",
parameter_list: "Parameterliste",
raw_request_body: "Rohdaten der Anfrage",
show_code: "Code zeigen",
hide_code: "Code ausblenden",
show_prerequest_script: "Preanfrageskript anzeigen",
hide_prerequest_script: "Preanfrageskript ausblenden",
authentication: "Authentifizierung",
authentication_type: "Authentifizierungs-Typ",
include_in_url: "In URL einfügen",
parameters: "Parameter",
expand_response: "Antwort ausklappen",
collapse_response: "Antwort einklappen",
hide_preview: "Vorschau verstecken",
preview_html: "HTML-Vorschau",
history: "Verlauf",
collections: "Kollektionen",
import_curl: "cURL importieren",
import: "Importieren",
generate_code: "Code generieren",
request_type: "Anfrage-Typ",
generated_code: "Generierter Code",
status: "Status",
headers: "Headers",
websocket: "WebSocket",
waiting_for_connection: "(warte auf Verbindung)",
message: "Nachricht",
sse: "SSE",
server: "Server",
events: "Ereignisse",
url: "URL",
get_schema: "Schema abrufen",
header_list: "Headerliste",
add_new: "Neu hinzufügen",
response: "Antwort",
query: "Abfrage",
queries: "Abfragen",
query_variables: "Variablen",
mutations: "Mutationen",
subscriptions: "Abonnements",
types: "Typen",
send: "Senden",
background: "Hintergrund",
color: "Farbe",
labels: "Bezeichner",
multi_color: "Mehrfarbig",
enabled: "Aktiviert",
disabled: "Deaktiviert",
proxy: "Proxy",
postwoman_official_proxy_hosting:
"Postwomans offizieller Proxy wird durch ApolloTV bereitgestellt.",
read_the: "Lies die",
apollotv_privacy_policy: "ApolloTV Datenschutzerklärung",
contact_us: "Kontaktiere uns",
connect: "Verbinden",
disconnect: "Trennen",
start: "Start",
stop: "Stopp"
};

90
lang/en-US.js Normal file
View File

@@ -0,0 +1,90 @@
export default {
home: "Home",
realtime: "Realtime",
graphql: "GraphQL",
settings: "Settings",
request: "Request",
install_pwa: "Install PWA",
support_us: "Support us",
tweet: "Tweet",
options: "Options",
communication: "Communication",
endpoint: "Endpoint",
schema: "Schema",
theme: "Theme",
subscribe: "Subscribe",
choose_language: "Choose Language",
shortcuts: "Shortcuts",
send_request: "Send Request",
save_to_collections: "Save to Collections",
copy_request_link: "Copy Request Link",
reset_request: "Reset Request",
support_us_on: "Support us on",
open_collective: "Open Collective",
paypal: "PayPal",
patreon: "Patreon",
javascript_code: "JavaScript Code",
method: "Method",
path: "Path",
label: "Label",
again: "Again",
content_type: "Content Type",
raw_input: "Raw input",
parameter_list: "Parameter List",
raw_request_body: "Raw Request Body",
show_code: "Show Code",
hide_code: "Hide Code",
show_prerequest_script: "Show Pre-Request Script",
hide_prerequest_script: "Hide Pre-Request Script",
authentication: "Authentication",
authentication_type: "Authentication type",
include_in_url: "Include in URL",
parameters: "Parameters",
expand_response: "Expand response",
collapse_response: "Collapse response",
hide_preview: "Hide Preview",
preview_html: "Preview HTML",
history: "History",
collections: "Collections",
import_curl: "Import cURL",
import: "Import",
generate_code: "Generate code",
request_type: "Request type",
generated_code: "Generated code",
status: "Status",
headers: "Headers",
websocket: "WebSocket",
waiting_for_connection: "(waiting for connection)",
message: "Message",
sse: "SSE",
server: "Server",
events: "Events",
url: "URL",
get_schema: "Get schema",
header_list: "Header list",
add_new: "Add new",
response: "Response",
query: "Query",
queries: "Queries",
query_variables: "Variables",
mutations: "Mutations",
subscriptions: "Subscriptions",
types: "Types",
send: "Send",
background: "Background",
color: "Color",
labels: "Labels",
multi_color: "Multi-color",
enabled: "Enabled",
disabled: "Disabled",
proxy: "Proxy",
postwoman_official_proxy_hosting:
"Postwoman's Official Proxy is hosted by ApolloTV.",
read_the: "Read the",
apollotv_privacy_policy: "ApolloTV privacy policy",
contact_us: "Contact us",
connect: "Connect",
disconnect: "Disconnect",
start: "Start",
stop: "Stop"
};

90
lang/es-ES.js Normal file
View File

@@ -0,0 +1,90 @@
export default {
home: "Inicio",
realtime: "Tiempo real",
graphql: "GraphQL",
settings: "Ajustes",
request: "Petición",
install_pwa: "Instalar PWA",
support_us: "Ayúdanos",
tweet: "Tweet",
options: "Opciones",
communication: "Comunicación",
endpoint: "Endpoint",
schema: "Esquema",
theme: "Tema",
subscribe: "Subscribirse",
choose_language: "Seleccione un idioma",
shortcuts: "Atajos",
send_request: "Enviar petición",
save_to_collections: "Guardar en las Colecciones",
copy_request_link: "Copiar enlace de la petición",
reset_request: "Reiniciar Petición",
support_us_on: "Ayúdanos en",
open_collective: "Open Collective",
paypal: "PayPal",
patreon: "Patreon",
javascript_code: "Código JavaScript",
method: "Método",
path: "Ruta",
label: "Etiqueta",
again: "De nuevo",
content_type: "Tipo de Contenido",
raw_input: "Datos sin Procesar",
parameter_list: "Lista de Parámetros",
raw_request_body: "Cuerpo de la Solicitud sin Procesar",
show_code: "Mostrar el código",
hide_code: "Ocultar el código",
show_prerequest_script: "Mostrar Script pre solicitud",
hide_prerequest_script: "Ocultar Script pre solicitud",
authentication: "Autenticación",
authentication_type: "Tipo de autenticación",
include_in_url: "Incluir en el URL",
parameters: "Parámetros",
expand_response: "Ampliar Respuesta",
collapse_response: "Contraer Respuesta",
hide_preview: "Ocultar la vista previa",
preview_html: "Vista Previa del HTML",
history: "Historial",
collections: "Colecciones",
import_curl: "Importar cURL",
import: "Importar",
generate_code: "Generar código",
request_type: "Tipo de Petición",
generated_code: "Código Generado",
status: "Estado",
headers: "Cabeceras",
websocket: "WebSocket",
waiting_for_connection: "(esperando por conexión)",
message: "Mensaje",
sse: "SSE",
server: "Servidor",
events: "Eventos",
url: "URL",
get_schema: "Obtener esquema",
header_list: "Lista de Cabeceras",
add_new: "Agregar nuevo",
response: "Respuesta",
query: "Consulta",
queries: "Consultas",
query_variables: "Variables",
mutations: "Mutaciones",
subscriptions: "Subscripciones",
types: "Tipos",
send: "Enviar",
background: "Fondo",
color: "Color",
labels: "Etiquetas",
multi_color: "Multicolor",
enabled: "Habilitado",
disabled: "Deshabilitado",
proxy: "Proxy",
postwoman_official_proxy_hosting:
"Proxy Oficial de Postwoman está hospedado en ApolloTV.",
read_the: "Leer la",
apollotv_privacy_policy: "Política de Privacidad de ApolloTV",
contact_us: "Contáctenos",
connect: "Conectar",
disconnect: "Desconectar",
start: "Comienzo",
stop: "Detener"
};

90
lang/fa-IR.js Normal file
View File

@@ -0,0 +1,90 @@
export default {
home: "خانه",
realtime: "بلادرنگ",
graphql: "GraphQL",
settings: "تنظیمات",
request: "درخواست",
install_pwa: "نصب PWA",
support_us: "از ما حمایت کنید",
tweet: "Tweet",
options: "گزینه‌ها",
communication: "ارتباط",
endpoint: "Endpoint",
schema: "Schema",
theme: "پوسته",
subscribe: "اشتراک",
choose_language: "تغییر زبان",
shortcuts: "میانبرها",
send_request: "ارسال درخواست",
save_to_collections: "ذخیره در کلکسیون",
copy_request_link: "کپی لینک درخواست",
reset_request: "بازنشانی درخواست",
support_us_on: "حمایت از ما از طریق",
open_collective: "Open Collective",
paypal: "PayPal",
patreon: "Patreon",
javascript_code: "کد JavaScript",
method: "متد",
path: "مسیر",
label: "برچسب",
again: "دوباره",
content_type: "Content Type",
raw_input: "ورودی raw",
parameter_list: "لیست پارامترها",
raw_request_body: "Raw Request Body",
show_code: "نمایش کد",
hide_code: "عدم نمایش کد",
show_prerequest_script: "Show Pre-Request Script",
hide_prerequest_script: "Hide Pre-Request Script",
authentication: "Authentication",
authentication_type: "Authentication type",
include_in_url: "در URL گنجانده شود",
parameters: "پارامترها",
expand_response: "نمایش کامل پاسخ",
collapse_response: "نمایش مختصر پاسخ",
hide_preview: "مخفی کردن نمایش",
preview_html: "نمایش HTML",
history: "تاریخچه",
collections: "کلکسیون",
import_curl: "وارد کردن cURL",
import: "وارد کردن",
generate_code: "تولید کد",
request_type: "Request type",
generated_code: "کد تولید شده",
status: "Status",
headers: "Headers",
websocket: "WebSocket",
waiting_for_connection: "(منتظر برقراری اتصال)",
message: "پیام",
sse: "SSE",
server: "سرور",
events: "رویداد",
url: "URL",
get_schema: "دریافت Schema",
header_list: "لیست Header",
add_new: "افزودن",
response: "Response",
query: "Query",
queries: "Queries",
query_variables: "Variables",
mutations: "Mutations",
subscriptions: "Subscriptions",
types: "Types",
send: "ارسال",
background: "پس زمینه",
color: "رنگ",
labels: "برچسب‌ها",
multi_color: "چند رنگی",
enabled: "فعال",
disabled: "غیر فعال",
proxy: "پراکسی",
postwoman_official_proxy_hosting:
"پراکسی Postwoman برروی هاست ApolloTV قرار دارد.",
read_the: "بخوانید",
apollotv_privacy_policy: "خط مشی رازداری ApolloTV",
contact_us: "Contact us",
connect: "Connect",
disconnect: "Disconnect",
start: "Start",
stop: "Stop"
};

90
lang/fr-FR.js Normal file
View File

@@ -0,0 +1,90 @@
export default {
home: "Accueil",
realtime: "Temps réel",
graphql: "GraphQL",
settings: "Paramètres",
request: "Request",
install_pwa: "Installer la PWA",
support_us: "Nous supporter",
tweet: "Tweeter",
options: "Options",
communication: "Communication",
endpoint: "Endpoint",
schema: "Schéma",
theme: "Thème",
subscribe: "S'inscrire",
choose_language: "Sélectionner une langue",
shortcuts: "Raccourcis",
send_request: "Envoyer la requête",
save_to_collections: "Sauvegarder dans les collections",
copy_request_link: "Copier le lien de la requête",
reset_request: "Réinitialiser la requête",
support_us_on: "Supportez-nous sur",
open_collective: "Ouvrir Collective",
paypal: "PayPal",
patreon: "Patreon",
javascript_code: "Code JavaScript",
method: "Méthode",
path: "Chemin d'accès",
label: "Libellé",
again: "Réessayer",
content_type: "Type de contenu",
raw_input: "Texte brut",
parameter_list: "Liste des paramètres",
raw_request_body: "Corps de la requête en texte brut",
show_code: "Afficher le code",
hide_code: "Masquer le code",
show_prerequest_script: "Afficher le script de pré-requête",
hide_prerequest_script: "Masquer le script de pré-requête",
authentication: "Authentification",
authentication_type: "Type d'authentification",
include_in_url: "Inclure dans l'URL",
parameters: "Paramètres",
expand_response: "Agrandir la réponse",
collapse_response: "Réduire la réponse",
hide_preview: "Masquer la prévisualisation",
preview_html: "Prévisualiser le HTML",
history: "Historique",
collections: "Collections",
import_curl: "Importer en cURL",
importer: "Importer",
generate_code: "Générer le code",
request_type: "Type de requête",
generated_code: "Code généré",
status: "Statut",
headers: "En-têtes",
websocket: "WebSocket",
waiting_for_connection: "(en attente de connexion)",
message: "Message",
sse: "SSE",
server: "Serveur",
events: "Évènements",
url: "URL",
get_schema: "Récuperer le schéma",
header_list: "Liste d'en-têtes",
add_new: "Ajouter",
response: "Réponse",
query: "Requête",
queries: "Requêtes",
query_variables: "Variables",
mutations: "Mutations",
subscriptions: "Abonnements",
types: "Types",
send: "Envoyer",
background: "Arrière-plan",
color: "Couleur",
labels: "Libellés",
multi_color: "Multi-couleurs",
enabled: "Activé",
disabled: "Désactivé",
proxy: "Proxy",
postwoman_official_proxy_hosting:
"Le proxy officiel de Postwoman est hébergé par ApolloTV.",
read_the: "Lire la",
apollotv_privacy_policy: "politique de confidentialité ApolloTV",
contact_us: "Contactez nous",
connect: "Relier",
disconnect: "Déconnecter",
start: "Début",
stop: "Arrêtez"
};

90
lang/id-ID.js Normal file
View File

@@ -0,0 +1,90 @@
export default {
home: "Beranda",
realtime: "Waktu Nyata",
graphql: "GraphQL",
settings: "Pengaturan",
request: "Permintaan",
install_pwa: "Pasang PWA",
support_us: "Dukung kami",
tweet: "Cuitkan",
options: "Opsi",
communication: "Komunikasi",
endpoint: "Titik Akhir",
schema: "Skema",
theme: "Tema",
subscribe: "Berlangganan",
choose_language: "Pilih Bahasa",
shortcuts: "Pintasan",
send_request: "Kirim Permintaan",
save_to_collections: "Simpan ke Koleksi",
copy_request_link: "Salin Tautan Permintaan",
reset_request: "Atur Ulang Permintaan",
support_us_on: "Dukung kami di",
open_collective: "Open Collective",
paypal: "Paypal",
patreon: "Patreon",
javascript_code: "Kode Javascript",
method: "Metode",
path: "Lintasan",
label: "Label",
again: "Lagi",
content_type: "Jenis Konten",
raw_input: "Masukan mentah",
parameter_list: "Daftar parameter",
raw_request_body: "Badan Permintaan Mentah",
show_code: "Tampilkan Kode",
hide_code: "Sembunyikan Kode",
show_prerequest_script: "Tampilkan Skrip Pra-Permintaan",
hide_prerequest_script: "Sembunyikan Skrip Pra-Permintaan",
authentication: "Autentikasi",
authentication_type: "Jenis Autentikasi",
include_in_url: "Sertakan di URL",
parameters: "Parameter",
expand_response: "Bentangkan Balasan",
collapse_response: "Ciutkan Balasan",
hide_preview: "Sembunyikan Pratinjau",
preview_html: "Pratinjau HTML",
history: "Riwayat",
collections: "Koleksi",
import_curl: "Impor cURL",
import: "Impor",
generate_code: "Hasilkan kode",
request_type: "Jenis permintaan",
generated_code: "Kode yang dihasilkan",
status: "Status",
headers: "Header",
websocket: "WebSocket",
waiting_for_connection: "(Menunggu sambungan)",
message: "Pesan",
sse: "SSE",
server: "Peladen",
events: "Kejadian",
url: "URL",
get_schema: "Ambil skema",
header_list: "Daftar header",
add_new: "Tambah baru",
response: "Balasan",
query: "Kueri",
queries: "Kueri",
query_variables: "Variables",
mutations: "Mutasi",
subscriptions: "Langganan",
types: "Jenis",
send: "Kirim",
background: "Latar belakang",
color: "Warna",
labels: "Label",
multi_color: "Warna beragam",
enabled: "diaktifkan",
disabled: "dinonaktifkan",
proxy: "Proksi",
postwoman_official_proxy_hosting:
"Proksi Resmi Postwoman dalam penginangan ApolloTV.",
read_the: "Bacalah",
apollotv_privacy_policy: "kebijakan privasi ApolloTV",
contact_us: "Hubungi kami",
connect: "Menghubungkan",
disconnect: "Memutuskan",
start: "Mulai",
stop: "Berhenti"
};

90
lang/ja-JP.js Normal file
View File

@@ -0,0 +1,90 @@
export default {
home: "ホーム",
realtime: "リアルタイム",
graphql: "GraphQL",
settings: "設定",
request: "リクエスト",
install_pwa: "PWAをインストール",
support_us: "寄付",
tweet: "ツイート",
options: "オプション",
communication: "通信",
endpoint: "エンドポイント",
schema: "スキーマ",
theme: "テーマ",
subscribe: "登録",
choose_language: "言語の選択",
shortcuts: "ショートカット",
send_request: "リクエストを送信",
save_to_collections: "コレクションに保存",
copy_request_link: "リクエストURLをコピー",
reset_request: "リクエストをリセット",
support_us_on: "以下より寄付",
open_collective: "Open Collective",
paypal: "PayPal",
patreon: "Patreon",
javascript_code: "JavaScriptコード",
method: "メソッド",
path: "パス",
label: "ラベル",
again: "",
content_type: "Content Type",
raw_input: "Raw入力",
parameter_list: "パラメータリスト",
raw_request_body: "Rawリクエストボディー",
show_code: "コードを表示",
hide_code: "コードを非表示",
show_prerequest_script: "プレリクエストスクリプトを表示",
hide_prerequest_script: "プレリクエストスクリプトを非表示",
authentication: "認証",
authentication_type: "認証タイプ",
include_in_url: "URLに含む",
parameters: "パラメータ",
expand_response: "レスポンスを広げる",
collapse_response: "レスポンスを狭める",
hide_preview: "プレビューしない",
preview_html: "HTMLプレビュー表示",
history: "履歴",
collections: "コレクション",
import_curl: "cURLをインポート",
import: "インポート",
generate_code: "コード生成",
request_type: "リクエストタイプ",
generated_code: "生成されたコード",
status: "ステータス",
headers: "ヘッダー",
websocket: "ウェブソケット",
waiting_for_connection: "(接続待ち)",
message: "メッセージ",
sse: "SSE",
server: "サーバ",
events: "イベント",
url: "URL",
get_schema: "スキーマを取得",
header_list: "ヘッダーリスト",
add_new: "追加",
response: "レスポンス",
query: "クエリ",
queries: "クエリ",
query_variables: "変数 (へんすう)",
mutations: "ミューテーション",
subscriptions: "サブスクリプション",
types: "タイプ",
send: "送信",
background: "背景",
color: "色",
labels: "ラベル",
multi_color: "マルチカラー",
enabled: "有効",
disabled: "無効",
proxy: "プロキシ",
postwoman_official_proxy_hosting:
"Postwomanの公式プロキシは、Apollo TVがホストしています。",
read_the: "プライバシーポリシー",
apollotv_privacy_policy: "を読む",
contact_us: "お問い合わせ",
connect: "つなぐ",
disconnect: "切断する",
start: "開始",
stop: "やめる"
};

89
lang/pt-BR.js Normal file
View File

@@ -0,0 +1,89 @@
export default {
home: "Home",
realtime: "Tempo real",
graphql: "GraphQL",
settings: "Configurações",
request: "Request",
install_pwa: "Instalar PWA",
support_us: "Nos ajude",
tweet: "Tweet",
options: "Opções",
communication: "Comunicação",
endpoint: "Endpoint",
schema: "Schema",
theme: "Tema",
subscribe: "Subscribe",
choose_language: "Escolher idioma",
shortcuts: "Atalhos",
send_request: "Enviar request",
save_to_collections: "Salvar nas coleções",
copy_request_link: "Copiar link da request",
reset_request: "Reiniciar request",
support_us_on: "Nos ajude no",
open_collective: "Abrir coletivamente",
paypal: "Paypal",
patreon: "Patreon",
javascript_code: "Codigo JavaScript",
method: "Método",
path: "Caminho",
label: "Label",
again: "Novamente",
content_type: "Content Type",
raw_input: "Raw input",
parameter_list: "Lista de parâmetros",
raw_request_body: "Raw request body",
show_code: "Mostrar código",
hide_code: "Esconder código",
show_prerequest_script: "Mostrar script de pré-request",
hide_prerequest_script: "Esconder script de pré-request",
authentication: "Autenticação",
authentication_type: "Tipo de autenticação",
include_in_url: "Incluir na url",
parameters: "Parâmetros",
expand_response: "Expandir response",
collapse_response: "Esconder response",
hide_preview: "Esconder preview",
preview_html: "Preview html",
history: "Histórico",
collections: "Coleções",
import_curl: "Importar curl",
import: "Importar",
generate_code: "Gerar código",
request_type: "Tipo de request",
generated_code: "Código gerado",
status: "Status",
headers: "Headers",
websocket: "Websocket",
waiting_for_connection: "(aguardando conexão)",
message: "Mensagem",
sse: "SSE",
server: "Servidor",
events: "Eventos",
url: "URL",
get_schema: "Get schema",
header_list: "Lista de headers",
add_new: "Adicionar novo",
response: "Response",
query: "Query",
queries: "Queries",
query_variables: "Variáveis",
mutations: "Mutações",
subscriptions: "Assinaturas",
types: "Tipos",
send: "Enviar",
background: "Fundo",
color: "Cor",
labels: "Labels",
multi_color: "Multi cor",
enabled: "Ativado",
disabled: "Desativado",
proxy: "Proxy",
postwoman_official_proxy_hosting: "Postwoman's alojamento proxy oficial",
read_the: "Leia o",
apollotv_privacy_policy: "ApolloTV Política de Privacidade",
contact_us: "Contate-Nos",
connect: "Conectar",
disconnect: "Desconectar",
start: "Começar",
stop: "Pare"
};

90
lang/tr-TR.js Normal file
View File

@@ -0,0 +1,90 @@
export default {
home: "Ana Sayfa",
realtime: "Realtime",
graphql: "GraphQL",
settings: "Ayarlar",
request: "İstek",
install_pwa: "PWA yükle",
support_us: "Bize destek ol",
tweet: "Tweet",
options: "Options",
communication: "İletişim",
endpoint: "Endpoint",
schema: "Taslak",
theme: "Tema",
subscribe: "Abonelik",
choose_language: "Dil seç",
shortcuts: "Kısayollar",
send_request: "İstek gönder",
save_to_collections: "Koleksiyonları kaydet",
copy_request_link: "İstek adresini kopyala",
reset_request: "İstekleri resetle",
support_us_on: "Bizi destekle",
open_collective: "Open Collective",
paypal: "PayPal",
patreon: "Patreon",
javascript_code: "JavaScript code",
method: "Metot",
path: "Yol",
label: "Etiket",
again: "Yeniden",
content_type: "İçerik tipi",
raw_input: "Raw giriş",
parameter_list: "Parametre listesi",
raw_request_body: "Raw istek içeriği",
show_code: "Kodu göster",
hide_code: "Kodu gizle",
show_prerequest_script: "Pre-Request scriptini göster",
hide_prerequest_script: "Pre-Request scriptini gizle",
authentication: "Authentication",
authentication_type: "Authentication tipi",
include_in_url: "URL'den içeri aktar",
parameters: "Parametre",
expand_response: "Cevabı genişlet",
collapse_response: "Cevap daralt",
hide_preview: "Görüntülemeyi gizle",
preview_html: "HTML formatında görüntüle",
history: "Geçmiş",
collections: "Koleksiyonlar",
import_curl: "cURL içeri aktar",
import: "İçeri Aktar",
generate_code: "Kod Üret",
request_type: "Request tipi",
generated_code: "Üretilen Kod",
status: "Durum",
headers: "Headers",
websocket: "WebSocket",
waiting_for_connection: "(esperando por conexión)",
message: "Mesaj",
sse: "SSE",
server: "Server",
events: "Events",
url: "URL",
get_schema: "Taslak",
header_list: "Header listesi",
add_new: "Yeni Ekle",
response: "Cevap",
query: "Sorgu",
queries: "Sorgular",
query_variables: "Değişkenler",
mutations: "Değişimler",
subscriptions: "Aboneler",
types: "Tipler",
send: "Gönder",
background: "Arka Plan",
color: "Renk",
labels: "Etiketler",
multi_color: "Çoklu renk",
enabled: "Aktif",
disabled: "Aktif değil",
proxy: "Proxy",
postwoman_official_proxy_hosting:
"Proxy Oficial de Postwoman está hospedado en ApolloTV.",
read_the: "Leer la",
apollotv_privacy_policy: "ApolloTV gizlilik politikaları",
contact_us: "Bizimle iletişime geçin",
connect: "Bağlan",
disconnect: "Kesmek",
start: "Başla",
stop: "Durdurmak"
};

89
lang/zh-CN.js Normal file
View File

@@ -0,0 +1,89 @@
export default {
home: "主页",
realtime: "长连接",
graphql: "GraphQL",
settings: "设置",
request: "请求",
install_pwa: "安装PWA应用",
support_us: "支持我们",
tweet: "推特",
options: "选项",
communication: "联系我们",
endpoint: "服务端点",
schema: "模式",
theme: "主题",
subscribe: "订阅",
choose_language: "选择语言",
shortcuts: "快捷键",
send_request: "发送请求",
save_to_collections: "保存到收藏夹",
copy_request_link: "复制请求链接",
reset_request: "重置请求",
support_us_on: "支持我们",
open_collective: "Open Collective",
paypal: "Paypal",
patreon: "Patreon",
javascript_code: "JavaScript代码",
method: "方法",
path: "路径",
label: "标签",
again: "重试",
content_type: "内容类型",
raw_input: "raw数据",
parameter_list: "参数列表",
raw_request_body: "raw请求主体",
show_code: "显示代码",
hide_code: "隐藏代码",
show_prerequest_script: "显示预请求脚本",
hide_prerequest_script: "隐藏预请求脚本",
authentication: "认证方式",
authentication_type: "认证类型",
include_in_url: "包含在URL中",
parameters: "参数",
expand_response: "展开显示响应内容",
collapse_response: "折叠显示响应内容",
hide_preview: "隐藏预览",
preview_html: "预览HTML",
history: "历史记录",
collections: "收藏夹",
import_curl: "批量导入",
import: "导入",
generate_code: "生成代码",
request_type: "请求类型",
generated_code: "生成的代码",
status: "状态码",
headers: "请求头",
websocket: "Websocket",
waiting_for_connection: "(等待连接)",
message: "消息内容",
sse: "SSE",
server: "Server",
events: "事件",
url: "地址",
get_schema: "获取模式",
header_list: "请求头列表",
add_new: "添加",
response: "响应",
query: "查询",
queries: "查询",
query_variables: "变数",
mutations: "Mutations",
subscriptions: "订阅",
types: "种类",
send: "发送",
background: "背景",
color: "颜色",
labels: "标签",
multi_color: "彩色",
enabled: "已启用",
disabled: "已禁用",
proxy: "代理",
postwoman_official_proxy_hosting: "Postwoman的官方代理由ApolloTV托管",
read_the: "阅读",
apollotv_privacy_policy: "ApolloTV隐私政策",
contact_us: "联系我们",
connect: "连接",
disconnect: "断开",
start: "开始",
stop: "停止"
};

View File

@@ -1,21 +1,5 @@
<template>
<div class="wrapper">
<header class="header">
<div>
<div class="slide-in">
<nuxt-link to="/">
<h1 class="logo">Postwoman</h1>
</nuxt-link>
<h3 class="tagline">API request builder</h3>
</div>
<a href="https://github.com/liyasthomas/postwoman" target="_blank" rel="noopener">
<button class="icon">
<img id="imgGitHub" src="~static/icons/github.svg" alt="GitHub" :style="logoStyle()" />
<span>GitHub</span>
</button>
</a>
</div>
</header>
<div class="content">
<div class="columns">
<aside class="nav-first">
@@ -24,82 +8,242 @@
We're using manual checks for linkActive because the query string
seems to mess up the nuxt-link active class.
-->
<nuxt-link to="/" :class="linkActive('/')" v-tooltip.right="'Home'" aria-label="Home">
<logo alt style="height: 24px;"></logo>
</nuxt-link>
<nuxt-link
to="/websocket"
:class="linkActive('/websocket')"
v-tooltip.right="'WebSocket'"
:to="localePath('index')"
:class="linkActive('/')"
v-tooltip.right="$t('home')"
aria-label="Home"
>
<i class="material-icons">cloud</i>
<logo alt class="material-icons" style="height: 24px;"></logo>
</nuxt-link>
<nuxt-link
to="/settings"
:to="localePath('realtime')"
:class="linkActive('/realtime')"
v-tooltip.right="$t('realtime')"
>
<i class="material-icons">settings_input_hdmi</i>
</nuxt-link>
<nuxt-link
:to="localePath('graphql')"
:class="linkActive('/graphql')"
v-tooltip.right="$t('graphql')"
aria-label="GraphQL"
>
<svg
class="material-icons"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
x="0px"
y="0px"
viewBox="0 0 400 400"
>
<g>
<g>
<g>
<rect
x="122"
y="-0.4"
transform="matrix(-0.866 -0.5 0.5 -0.866 163.3196 363.3136)"
width="16.6"
height="320.3"
/>
</g>
</g>
<g>
<g>
<rect x="39.8" y="272.2" width="320.3" height="16.6" />
</g>
</g>
<g>
<g>
<rect
x="37.9"
y="312.2"
transform="matrix(-0.866 -0.5 0.5 -0.866 83.0693 663.3409)"
width="185"
height="16.6"
/>
</g>
</g>
<g>
<g>
<rect
x="177.1"
y="71.1"
transform="matrix(-0.866 -0.5 0.5 -0.866 463.3409 283.0693)"
width="185"
height="16.6"
/>
</g>
</g>
<g>
<g>
<rect
x="122.1"
y="-13"
transform="matrix(-0.5 -0.866 0.866 -0.5 126.7903 232.1221)"
width="16.6"
height="185"
/>
</g>
</g>
<g>
<g>
<rect
x="109.6"
y="151.6"
transform="matrix(-0.5 -0.866 0.866 -0.5 266.0828 473.3766)"
width="320.3"
height="16.6"
/>
</g>
</g>
<g>
<g><rect x="52.5" y="107.5" width="16.6" height="185" /></g>
</g>
<g>
<g>
<rect x="330.9" y="107.5" width="16.6" height="185" />
</g>
</g>
<g>
<g>
<rect
x="262.4"
y="240.1"
transform="matrix(-0.5 -0.866 0.866 -0.5 126.7953 714.2875)"
width="14.5"
height="160.9"
/>
</g>
</g>
<path
d="M369.5,297.9c-9.6,16.7-31,22.4-47.7,12.8c-16.7-9.6-22.4-31-12.8-47.7c9.6-16.7,31-22.4,47.7-12.8C373.5,259.9,379.2,281.2,369.5,297.9"
/>
<path
d="M90.9,137c-9.6,16.7-31,22.4-47.7,12.8c-16.7-9.6-22.4-31-12.8-47.7c9.6-16.7,31-22.4,47.7-12.8C94.8,99,100.5,120.3,90.9,137"
/>
<path
d="M30.5,297.9c-9.6-16.7-3.9-38,12.8-47.7c16.7-9.6,38-3.9,47.7,12.8c9.6,16.7,3.9,38-12.8,47.7C61.4,320.3,40.1,314.6,30.5,297.9"
/>
<path
d="M309.1,137c-9.6-16.7-3.9-38,12.8-47.7c16.7-9.6,38-3.9,47.7,12.8c9.6,16.7,3.9,38-12.8,47.7C340.1,159.4,318.7,153.7,309.1,137"
/>
<path
d="M200,395.8c-19.3,0-34.9-15.6-34.9-34.9c0-19.3,15.6-34.9,34.9-34.9c19.3,0,34.9,15.6,34.9,34.9C234.9,380.1,219.3,395.8,200,395.8"
/>
<path
d="M200,74c-19.3,0-34.9-15.6-34.9-34.9c0-19.3,15.6-34.9,34.9-34.9c19.3,0,34.9,15.6,34.9,34.9C234.9,58.4,219.3,74,200,74"
/>
</g>
</svg>
</nuxt-link>
<nuxt-link
:to="localePath('doc')"
:class="linkActive('/doc')"
v-tooltip.right="'Documentation'"
aria-label="Documentation"
>
<i class="material-icons">books</i>
</nuxt-link>
<nuxt-link
:to="localePath('settings')"
:class="linkActive('/settings')"
v-tooltip.right="'Settings'"
v-tooltip.right="$t('settings')"
aria-label="Settings"
>
<i class="material-icons">settings</i>
</nuxt-link>
</nav>
<div v-if="['/'].includes($route.path)">
<div v-if="$route.path === '/'">
<nav class="secondary-nav">
<ul>
<li>
<a href="#request" v-tooltip.right="'Request'">
<a href="#request" v-tooltip.right="$t('request')">
<i class="material-icons">cloud_upload</i>
</a>
</li>
<li>
<a href="#options" v-tooltip.right="'Options'">
<a href="#options" v-tooltip.right="$t('options')">
<i class="material-icons">toc</i>
</a>
</li>
<li>
<a href="#response" v-tooltip.right="'Response'">
<a href="#response" v-tooltip.right="$t('response')">
<i class="material-icons">cloud_download</i>
</a>
</li>
<li>
<a href="#collections" v-tooltip.right="'Collections'">
<i class="material-icons">folder_special</i>
</a>
</li>
<li>
<a href="#history" v-tooltip.right="'History'">
<i class="material-icons">watch_later</i>
</a>
</li>
</ul>
</nav>
</div>
<div v-else-if="['/websocket'].includes($route.path)">
<div v-else-if="$route.path === '/realtime'">
<nav class="secondary-nav">
<ul>
<li>
<a href="#request" v-tooltip.right="'Request'">
<a href="#request" v-tooltip.right="$t('request')">
<i class="material-icons">cloud_upload</i>
</a>
</li>
<li>
<a href="#response" v-tooltip.right="'Response'">
<a href="#response" v-tooltip.right="$t('communication')">
<i class="material-icons">cloud_download</i>
</a>
</li>
</ul>
</nav>
</div>
<div v-else-if="['/settings'].includes($route.path)">
<div v-else-if="$route.path === '/graphql'">
<nav class="secondary-nav">
<ul>
<li>
<a href="#theme" v-tooltip.right="'Theme'">
<a href="#endpoint" v-tooltip.right="$t('endpoint')">
<i class="material-icons">cloud</i>
</a>
</li>
<li>
<a href="#schema" v-tooltip.right="$t('schema')">
<i class="material-icons">assignment_returned</i>
</a>
</li>
<li>
<a href="#query" v-tooltip.right="$t('query')">
<i class="material-icons">cloud_upload</i>
</a>
</li>
<li>
<a href="#response" v-tooltip.right="$t('response')">
<i class="material-icons">cloud_download</i>
</a>
</li>
</ul>
</nav>
</div>
<div v-else-if="$route.path === '/doc'">
<nav class="secondary-nav">
<ul>
<li>
<a href="#collections" v-tooltip.right="$t('collections')">
<i class="material-icons">folder</i>
</a>
</li>
<li>
<a href="#documentation" v-tooltip.right="'Documentation'">
<i class="material-icons">insert_drive_file</i>
</a>
</li>
</ul>
</nav>
</div>
<div v-else-if="$route.path === '/settings'">
<nav class="secondary-nav">
<ul>
<li>
<a href="#theme" v-tooltip.right="$t('theme')">
<i class="material-icons">brush</i>
</a>
</li>
<li>
<a href="#proxy" v-tooltip.right="'Proxy'">
<a href="#proxy" v-tooltip.right="$t('proxy')">
<i class="material-icons">public</i>
</a>
</li>
@@ -107,173 +251,376 @@
</nav>
</div>
</aside>
<nuxt id="main" class="main" />
<div class="main" id="main">
<header class="header">
<div class="flex-wrap">
<span class="slide-in">
<nuxt-link :to="localePath('index')">
<h1 class="logo">Postwoman</h1>
</nuxt-link>
</span>
<span>
<a
href="https://github.com/liyasthomas/postwoman"
target="_blank"
aria-label="GitHub"
rel="noopener"
>
<button class="icon" aria-label="GitHub" v-tooltip="'GitHub'">
<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>
</button>
</a>
<button
class="icon"
id="installPWA"
@click.prevent="showInstallPrompt()"
v-tooltip="$t('install_pwa')"
>
<i class="material-icons">offline_bolt</i>
</button>
<v-popover>
<button class="icon" v-tooltip="'More'">
<i class="material-icons">more_vert</i>
</button>
<template slot="popover">
<div>
<button
class="icon"
@click="showShortcuts = true"
v-close-popover
>
<i class="material-icons">keyboard</i>
<span>{{ $t("shortcuts") }}</span>
</button>
</div>
<div>
<button
class="icon"
@click="showSupport = true"
v-close-popover
>
<i class="material-icons">favorite</i>
<span>{{ $t("support_us") }}</span>
</button>
</div>
<div>
<button
class="icon"
onClick="window.open('https://twitter.com/share?text=👽 Postwoman • API request builder - Helps you create your requests faster, saving you precious time on your development&url=https://postwoman.io&hashtags=postwoman&via=liyasthomas');"
v-close-popover
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
>
<path
d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"
/>
</svg>
<span>{{ $t("tweet") }}</span>
</button>
</div>
</template>
</v-popover>
</span>
</div>
</header>
<nuxt />
<footer class="footer">
<div class="flex-wrap">
<span v-if="version.name" class="mono">
<a
href="https://liyasthomas.web.app"
target="_blank"
rel="noopener"
>
<button class="icon" v-tooltip="'Liyas Thomas'">
🦄
</button>
</a>
<a
:href="
'https://github.com/liyasthomas/postwoman/releases/tag/' +
version.name
"
target="_blank"
rel="noopener"
v-tooltip="'GitHub'"
>
{{ version.name }}
</a>
<!-- <span v-if="version.hash">
-
<a
:href="'https://github.com/liyasthomas/postwoman/commit/' + version.hash"
target="_blank"
rel="noopener"
>{{version.hash}}</a>
</span> -->
<!-- <span v-if="version.variant">({{version.variant}})</span> -->
</span>
<span>
<a
href="mailto:liyascthomas@gmail.com"
target="_blank"
rel="noopener"
>
<button class="icon" v-tooltip="$t('contact_us')">
<i class="material-icons">email</i>
</button>
</a>
<v-popover>
<button class="icon" v-tooltip="$t('choose_language')">
<i class="material-icons">translate</i>
</button>
<template slot="popover">
<div v-for="locale in availableLocales" :key="locale.code">
<nuxt-link :to="switchLocalePath(locale.code)">
<button class="icon" v-close-popover>
{{ locale.name }}
</button>
</nuxt-link>
</div>
</template>
</v-popover>
</span>
</div>
</footer>
</div>
<aside class="nav-second"></aside>
</div>
</div>
<footer class="footer">
<!-- Top section of footer: GitHub/install links -->
<div class="flex-wrap">
<button class="icon" id="installPWA" @click.prevent="showInstallPrompt()">
<i class="material-icons">add_to_home_screen</i>
<span>Install PWA</span>
</button>
<button
class="icon"
onClick="window.open('https://twitter.com/share?text=👽 Postwoman • API request builder - Helps you create your requests faster, saving you precious time on your development&url=https://postwoman.io&hashtags=postwoman&via=liyasthomas');"
>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24">
<path
d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"
/>
</svg>
<span>Tweet</span>
</button>
<modal v-if="showShortcuts" @close="showShortcuts = false">
<div slot="header">
<ul>
<li>
<div class="flex-wrap">
<h3 class="title">{{ $t("shortcuts") }}</h3>
<div>
<button class="icon" @click="showShortcuts = false">
<i class="material-icons">close</i>
</button>
</div>
</div>
</li>
</ul>
</div>
<!-- Bottom section of footer: version/author information -->
<p class="align-center">
<span v-if="version.name">
<div slot="body">
<br />
<div>
<label>{{ $t("send_request") }}</label>
<kbd> G</kbd>
</div>
<br />
<div>
<label>{{ $t("save_to_collections") }}</label>
<kbd> S</kbd>
</div>
<br />
<div>
<label>{{ $t("copy_request_link") }}</label>
<kbd> K</kbd>
</div>
<br />
<div>
<label>{{ $t("reset_request") }}</label>
<kbd> L</kbd>
</div>
<br />
</div>
<div slot="footer"></div>
</modal>
<modal v-if="showSupport" @close="showSupport = false">
<div slot="header">
<ul>
<li>
<div class="flex-wrap">
<h3 class="title">{{ $t("support_us_on") }}</h3>
<div>
<button class="icon" @click="showSupport = false">
<i class="material-icons">close</i>
</button>
</div>
</div>
</li>
</ul>
</div>
<div slot="body">
<div>
<a
v-bind:href="'https://github.com/liyasthomas/postwoman/releases/tag/' + version.name"
href="https://opencollective.com/postwoman"
target="_blank"
rel="noopener"
>{{version.name}}</a>
<span v-if="version.hash">
-
<a
v-bind:href="'https://github.com/liyasthomas/postwoman/commit/' + version.hash"
target="_blank"
rel="noopener"
>{{version.hash}}</a>
</span>
<span v-if="version.variant">({{version.variant}})</span>
&#x2022;
</span> by
<a href="https://liyasthomas.web.app" target="_blank" rel="noopener">Liyas Thomas 🦄</a> &#x2022;
<a href="https://postwoman.launchaco.com" target="_blank" rel="noopener">Subscribe</a>
</p>
</footer>
>
<button class="icon">
<i class="material-icons">donut_large</i>
<span>{{ $t("open_collective") }}</span>
</button>
</a>
</div>
<div>
<a
href="https://www.paypal.me/liyascthomas"
target="_blank"
rel="noopener"
>
<button class="icon">
<i class="material-icons">payment</i>
<span>{{ $t("paypal") }}</span>
</button>
</a>
</div>
<div>
<a
href="https://www.patreon.com/liyasthomas"
target="_blank"
rel="noopener"
>
<button class="icon">
<i class="material-icons">local_parking</i>
<span>{{ $t("patreon") }}</span>
</button>
</a>
</div>
</div>
<div slot="footer"></div>
</modal>
</div>
</template>
<style lang="scss">
</style>
<style scoped lang="scss"></style>
<script>
import intializePwa from "../assets/js/pwa";
import logo from "../components/logo";
import * as version from "../.postwoman/version.json";
import intializePwa from "../assets/js/pwa";
import * as version from "../.postwoman/version.json";
export default {
components: {
logo
},
export default {
components: {
logo: () => import("../components/logo"),
modal: () => import("../components/modal")
},
methods: {
linkActive(path) {
return {
"nuxt-link-exact-active": this.$route.path === path,
"nuxt-link-active": this.$route.path === path
};
}
},
data() {
methods: {
linkActive(path) {
return {
// Once the PWA code is initialized, this holds a method
// that can be called to show the user the installation
// prompt.
showInstallPrompt: null,
logoStyle() {
return (
this.$store.state.postwoman.settings.THEME_CLASS || ""
).includes("light")
? " filter: invert(100%); -webkit-filter: invert(100%);"
: "";
},
version: {}
"nuxt-link-exact-active": this.$route.path === path,
"nuxt-link-active": this.$route.path === path
};
},
beforeMount() {
// Set version data
this.version = version.default;
// Load theme settings
(() => {
// Apply theme from settings.
document.documentElement.className =
this.$store.state.postwoman.settings.THEME_CLASS || "";
// Load theme color data from settings, or use default color.
let color = this.$store.state.postwoman.settings.THEME_COLOR || "#50fa7b";
let vibrant = this.$store.state.postwoman.settings.THEME_COLOR_VIBRANT;
if (vibrant == null) vibrant = true;
document.documentElement.style.setProperty("--ac-color", color);
document.documentElement.style.setProperty(
"--act-color",
vibrant ? "rgb(37, 38, 40)" : "#ffffff"
);
})();
},
mounted() {
if (process.client) {
document.body.classList.add("afterLoad");
}
document
.querySelector("meta[name=theme-color]")
.setAttribute(
"content",
this.$store.state.postwoman.settings.THEME_TAB_COLOR || "#252628"
);
// Initializes the PWA code - checks if the app is installed,
// etc.
(async () => {
this.showInstallPrompt = await intializePwa();
let cookiesAllowed = localStorage.getItem("cookiesAllowed") === "yes";
if (!cookiesAllowed) {
this.$toast.show("We use cookies", {
icon: "info",
duration: 5000,
theme: "toasted-primary",
action: [
{
text: "Dismiss",
onClick: (e, toastObject) => {
localStorage.setItem("cookiesAllowed", "yes");
toastObject.goAway(0);
}
}
]
});
}
})();
window.addEventListener("scroll", event => {
let mainNavLinks = document.querySelectorAll("nav ul li a");
let fromTop = window.scrollY;
mainNavLinks.forEach(link => {
let section = document.querySelector(link.hash);
if (
section.offsetTop <= fromTop &&
section.offsetTop + section.offsetHeight > fromTop
) {
link.classList.add("current");
} else {
link.classList.remove("current");
}
});
});
},
watch: {
$route() {
this.$toast.clear();
}
}
};
},
data() {
return {
// Once the PWA code is initialized, this holds a method
// that can be called to show the user the installation
// prompt.
showInstallPrompt: null,
version: {},
showShortcuts: false,
showSupport: false
};
},
beforeMount() {
// Set version data
this.version = version.default;
// Load theme settings
(() => {
// Apply theme from settings.
document.documentElement.className =
this.$store.state.postwoman.settings.THEME_CLASS || "";
// Load theme color data from settings, or use default color.
let color = this.$store.state.postwoman.settings.THEME_COLOR || "#50fa7b";
let vibrant = this.$store.state.postwoman.settings.THEME_COLOR_VIBRANT;
if (vibrant == null) vibrant = true;
document.documentElement.style.setProperty("--ac-color", color);
document.documentElement.style.setProperty(
"--act-color",
vibrant ? "rgba(32, 33, 36, 1)" : "rgba(255, 255, 255, 1)"
);
})();
},
mounted() {
if (process.client) {
document.body.classList.add("afterLoad");
}
document
.querySelector("meta[name=theme-color]")
.setAttribute(
"content",
this.$store.state.postwoman.settings.THEME_TAB_COLOR || "#202124"
);
// Initializes the PWA code - checks if the app is installed,
// etc.
(async () => {
this.showInstallPrompt = await intializePwa();
let cookiesAllowed = localStorage.getItem("cookiesAllowed") === "yes";
if (!cookiesAllowed) {
this.$toast.show("We use cookies", {
icon: "info",
duration: 5000,
theme: "toasted-primary",
action: [
{
text: "Dismiss",
onClick: (e, toastObject) => {
localStorage.setItem("cookiesAllowed", "yes");
toastObject.goAway(0);
}
}
]
});
}
})();
window.addEventListener("scroll", event => {
let mainNavLinks = document.querySelectorAll("nav ul li a");
let fromTop = window.scrollY;
mainNavLinks.forEach(link => {
let section = document.querySelector(link.hash);
if (
section &&
section.offsetTop <= fromTop &&
section.offsetTop + section.offsetHeight > fromTop
) {
link.classList.add("current");
} else {
link.classList.remove("current");
}
});
});
console.log("%cWe ❤︎ open source!", "background-color:white;padding:8px 16px;border-radius:8px;font-size:32px;color:red;")
console.log("%cContribute: https://github.com/liyasthomas/postwoman", "background-color:black;padding:4px 8px;border-radius:8px;font-size:16px;color:white;")
},
watch: {
$route() {
this.$toast.clear();
}
},
computed: {
availableLocales() {
return this.$i18n.locales.filter(i => i.code !== this.$i18n.locale);
}
}
};
</script>

View File

@@ -14,7 +14,7 @@
</div>
</template>
<style lang="scss">
<style scoped lang="scss">
// Center the error page in the viewport.
.page-error {
display: flex;

View File

@@ -1,8 +1,5 @@
export default function ({
route,
redirect
}) {
if (route.fullPath !== '/') {
return redirect('/');
export default function({ route, redirect }) {
if (route.fullPath !== "/") {
return redirect("/");
}
}

View File

@@ -3,50 +3,64 @@
export const meta = {
name: "Postwoman",
shortDescription: "API request builder",
description: "The Postwoman API request builder helps you create your requests faster, saving you precious time on your development."
description:
"The Postwoman API request builder helps you create your requests faster, saving you precious time on your development."
};
// Sets the base path for the router.
// Important for deploying to GitHub pages.
// -- Travis includes the author in the repo slug,
// so if there's a /, we need to get everything after it.
let repoName = (process.env.TRAVIS_REPO_SLUG || '').split('/').pop();
export const routerBase = process.env.DEPLOY_ENV === 'GH_PAGES' ? {
router: {
base: `/${repoName}/`
}
} : {
router: {
base: '/'
}
};
let repoName = (process.env.TRAVIS_REPO_SLUG || "").split("/").pop();
export const routerBase =
process.env.DEPLOY_ENV === "GH_PAGES"
? {
router: {
base: `/${repoName}/`
}
}
: {
router: {
base: "/"
}
};
export default {
mode: 'spa',
mode: "spa",
/*
** Headers of the page
*/
server: {
host: '0.0.0.0', // default: localhost
host: "0.0.0.0" // default: localhost
},
render: {
bundleRenderer: {
shouldPreload: (file, type) => {
return ["script", "style", "font"].includes(type);
}
}
},
head: {
title: `${meta.name} \u2022 ${meta.shortDescription}`,
meta: [{
charset: 'utf-8'
meta: [
{
charset: "utf-8"
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1, minimum-scale=1, shrink-to-fit=no, minimal-ui'
name: "viewport",
content:
"width=device-width, initial-scale=1, minimum-scale=1, viewport-fit=cover, minimal-ui"
},
{
hid: 'description',
name: 'description',
content: meta.description || ''
hid: "description",
name: "description",
content: meta.description || ""
},
{
name: 'keywords',
content: 'postwoman, postwoman chrome, postwoman online, postwoman for mac, postwoman app, postwoman for windows, postwoman google chrome, postwoman chrome app, get postwoman, postwoman web, postwoman android, postwoman app for chrome, postwoman mobile app, postwoman web app, api, request, testing, tool, rest, websocket'
name: "keywords",
content:
"postwoman, postwoman chrome, postwoman online, postwoman for mac, postwoman app, postwoman for windows, postwoman google chrome, postwoman chrome app, get postwoman, postwoman web, postwoman android, postwoman app for chrome, postwoman mobile app, postwoman web app, api, request, testing, tool, rest, websocket, sse, graphql"
},
{
name: 'X-UA-Compatible',
name: "X-UA-Compatible",
content: "IE=edge, chrome=1"
},
{
@@ -59,156 +73,158 @@ export default {
},
{
itemprop: "image",
content: `${routerBase.router.base}icons/icon-192x192.png`
content: `${routerBase.router.base}logo.jpg`
},
// Add to homescreen for Chrome on Android. Fallback for PWA (handled by nuxt)
{
name: 'application-name',
name: "application-name",
content: meta.name
},
// Add to homescreen for Safari on iOS
{
name: 'apple-mobile-web-app-capable',
content: 'yes'
name: "apple-mobile-web-app-capable",
content: "yes"
},
{
name: 'apple-mobile-web-app-status-bar-style',
content: 'black-translucent'
name: "apple-mobile-web-app-status-bar-style",
content: "black-translucent"
},
{
name: 'apple-mobile-web-app-title',
name: "apple-mobile-web-app-title",
content: meta.name
},
// Windows phone tile icon
{
name: 'msapplication-TileImage',
name: "msapplication-TileImage",
content: `${routerBase.router.base}icons/icon-144x144.png`
},
{
name: 'msapplication-TileColor',
content: '#252628'
name: "msapplication-TileColor",
content: "#202124"
},
{
name: 'msapplication-tap-highlight',
content: 'no'
name: "msapplication-tap-highlight",
content: "no"
},
// OpenGraph
{
property: 'og:site_name',
property: "og:site_name",
content: meta.name
},
{
property: 'og:url',
content: 'https://postwoman.io'
},
{
property: 'og:type',
content: 'website'
},
{
property: 'og:title',
content: `${meta.name} \u2022 ${meta.shortDescription}`
},
{
property: 'og:description',
content: meta.description
},
{
property: 'og:image',
content: `${routerBase.router.base}icons/icon-144x144.png`
},
// Twitter
{
name: 'twitter:card',
content: "summary"
},
{
name: 'twitter:site',
content: "@liyasthomas"
},
{
name: 'twitter:creator',
content: "@liyasthomas"
},
{
name: 'twitter:url',
property: "og:url",
content: "https://postwoman.io"
},
{
name: 'twitter:title',
content: meta.name
property: "og:type",
content: "website"
},
{
name: 'twitter:description',
content: meta.shortDescription
property: "og:title",
content: `${meta.name} \u2022 ${meta.shortDescription}`
},
{
name: 'twitter:image',
content: `${routerBase.router.base}icons/icon-144x144.png`
property: "og:description",
content: meta.description
},
{
property: "og:image",
content: `${routerBase.router.base}logo.jpg`
},
// Twitter
{
name: "twitter:card",
content: "summary_large_image"
},
{
name: "twitter:site",
content: "@liyasthomas"
},
{
name: "twitter:creator",
content: "@liyasthomas"
},
{
name: "twitter:url",
content: "https://postwoman.io"
},
{
name: "twitter:title",
content: `${meta.name} \u2022 ${meta.shortDescription}`
},
{
name: "twitter:description",
content: meta.description
},
{
name: "twitter:image",
content: "https://postwoman.io/logo.jpg"
}
],
link: [{
rel: 'icon',
type: 'image/x-icon',
link: [
{
rel: "icon",
type: "image/x-icon",
href: `${routerBase.router.base}favicon.ico`
},
// Home-screen icons (iOS)
{
rel: 'apple-touch-icon',
rel: "apple-touch-icon",
href: `${routerBase.router.base}icons/icon-48x48.png`
},
{
rel: 'apple-touch-icon',
sizes: '72x72',
rel: "apple-touch-icon",
sizes: "72x72",
href: `${routerBase.router.base}icons/icon-72x72.png`
},
{
rel: 'apple-touch-icon',
sizes: '96x96',
rel: "apple-touch-icon",
sizes: "96x96",
href: `${routerBase.router.base}icons/icon-96x96.png`
},
{
rel: 'apple-touch-icon',
sizes: '144x144',
rel: "apple-touch-icon",
sizes: "144x144",
href: `${routerBase.router.base}icons/icon-144x144.png`
},
{
rel: 'apple-touch-icon',
sizes: '192x192',
rel: "apple-touch-icon",
sizes: "192x192",
href: `${routerBase.router.base}icons/icon-192x192.png`
},
}
]
},
/*
** Customize the progress-bar color
*/
loading: {
color: 'var(--ac-color)'
color: "var(--ac-color)"
},
/*
** Customize the loading indicator
*/
loadingIndicator: {
name: 'pulse',
color: 'var(--ac-color)',
background: 'var(--bg-color)'
name: "pulse",
color: "var(--ac-color)",
background: "var(--bg-color)"
},
/*
** Global CSS
*/
css: [
'@/assets/css/themes.scss',
'@/assets/css/fonts.scss',
'@/assets/css/styles.scss'
"~/assets/css/styles.scss",
"~/assets/css/themes.scss",
"~/assets/css/fonts.scss"
],
/*
** Plugins to load before mounting the App
*/
plugins: [{
src: '~/plugins/vuex-persist'
plugins: [
{
src: "~/plugins/vuex-persist"
},
{
src: '~/plugins/v-tooltip'
src: "~/plugins/v-tooltip"
}
],
/*
@@ -220,15 +236,19 @@ export default {
*/
modules: [
// See https://goo.gl/OOhYW5
['@nuxtjs/pwa'],
['@nuxtjs/axios'],
['@nuxtjs/toast'],
['@nuxtjs/google-analytics'],
['@nuxtjs/sitemap'],
['@nuxtjs/google-tag-manager', {
id: process.env.GTM_ID || 'GTM-MXWD8NQ'
}],
['@nuxtjs/robots']
["@nuxtjs/pwa"],
["@nuxtjs/axios"],
["@nuxtjs/toast"],
["@nuxtjs/google-analytics"],
["@nuxtjs/sitemap"],
[
"@nuxtjs/google-tag-manager",
{
id: process.env.GTM_ID || "GTM-MXWD8NQ"
}
],
["@nuxtjs/robots"],
["nuxt-i18n"]
],
pwa: {
manifest: {
@@ -237,45 +257,112 @@ export default {
display: "standalone",
theme_color: "#252628",
background_color: "#252628",
theme_color: "#202124",
background_color: "#202124",
start_url: `${routerBase.router.base}`
},
meta: {
description: meta.shortDescription,
theme_color: "#252628",
theme_color: "#202124"
},
icons: ((sizes) => {
icons: (sizes => {
let icons = [];
for (let size of sizes) {
icons.push({
"src": `${routerBase.router.base}icons/icon-${size}x${size}.png`,
"type": "image/png",
"sizes": `${size}x${size}`
src: `${routerBase.router.base}icons/icon-${size}x${size}.png`,
type: "image/png",
sizes: `${size}x${size}`
});
}
return icons;
})([48, 72, 96, 144, 192, 512])
},
toast: {
position: 'bottom-center',
position: "bottom-center",
duration: 3000,
theme: 'bubble',
theme: "bubble",
keepOnHover: true
},
googleAnalytics: {
id: process.env.GA_ID || 'UA-61422507-2'
id: process.env.GA_ID || "UA-61422507-2"
},
sitemap: {
hostname: 'https://postwoman.io'
hostname: "https://postwoman.io"
},
robots: {
UserAgent: '*',
Disallow: '',
Allow: '/',
Sitemap: 'https://postwoman.io/sitemap.xml'
UserAgent: "*",
Disallow: "",
Allow: "/",
Sitemap: "https://postwoman.io/sitemap.xml"
},
i18n: {
locales: [
{
code: "en",
name: "English",
iso: "en-US",
file: "en-US.js"
},
{
code: "es",
name: "Español",
iso: "es-ES",
file: "es-ES.js"
},
{
code: "fr",
name: "Français",
iso: "fr-FR",
file: "fr-FR.js"
},
{
code: "fa",
name: "Farsi",
iso: "fa-IR",
file: "fa-IR.js"
},
{
code: "pt",
name: "Português Brasileiro",
iso: "pt-BR",
file: "pt-BR.js"
},
{
code: "cn",
name: "简体中文",
iso: "zh-CN",
file: "zh-CN.js"
},
{
code: "id",
name: "Bahasa Indonesia",
iso: "id-ID",
file: "id-ID.js"
},
{
code: "tr",
name: "Türkçe",
iso: "tr-TR",
file: "tr-TR.js"
},
{
code: "de",
name: "Deutsch",
iso: "de-DE",
file: "de-DE.js"
},
{
code: "ja",
name: "日本語",
iso: "ja-JP",
file: "ja-JP.js"
}
],
defaultLocale: "en",
lazy: true,
langDir: "lang/"
},
/*
** Build configuration
@@ -296,4 +383,4 @@ export default {
** Router configuration
*/
...routerBase
}
};

3212
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"name": "postwoman",
"version": "1.0.0",
"description": "A free, fast, and beautiful API request builder",
"version": "1.5.0",
"description": "A free, fast and beautiful API request builder",
"author": "liyasthomas",
"private": true,
"scripts": {
@@ -18,25 +18,27 @@
"test": "start-server-and-test dev http://localhost:3000 e2e"
},
"dependencies": {
"@nuxtjs/axios": "^5.8.0",
"@nuxtjs/google-analytics": "^2.2.1",
"@nuxtjs/axios": "^5.9.2",
"@nuxtjs/google-analytics": "^2.2.2",
"@nuxtjs/google-tag-manager": "^2.3.1",
"@nuxtjs/pwa": "^3.0.0-beta.19",
"@nuxtjs/robots": "^2.4.2",
"@nuxtjs/sitemap": "^2.0.0",
"@nuxtjs/sitemap": "^2.0.1",
"@nuxtjs/toast": "^3.3.0",
"highlight.js": "^9.16.2",
"nuxt": "^2.10.2",
"ace-builds": "^1.4.7",
"graphql": "^14.5.8",
"nuxt": "^2.11.0",
"nuxt-i18n": "^6.4.1",
"v-tooltip": "^2.0.2",
"vue-virtual-scroll-list": "^1.4.2",
"vue-virtual-scroll-list": "^1.4.4",
"vuejs-auto-complete": "^0.9.0",
"vuex-persist": "^2.1.1",
"vuex-persist": "^2.2.0",
"yargs-parser": "^16.1.0"
},
"devDependencies": {
"cypress": "^3.6.0",
"cypress": "^3.8.1",
"node-sass": "^4.13.0",
"sass-loader": "^7.3.1",
"sass-loader": "^8.0.0",
"start-server-and-test": "^1.10.6"
}
}

387
pages/doc.vue Normal file
View File

@@ -0,0 +1,387 @@
<template>
<div class="page">
<pw-section class="blue" label="Collections" ref="collections">
<ul>
<li>
<p class="info">
Import any Postwoman Collection to Generate Documentation on-the-go.
</p>
</li>
</ul>
<ul>
<li>
<label for="collectionUpload">
<button
class="icon"
@click="$refs.collectionUpload.click()"
v-tooltip="'JSON'"
>
<i class="material-icons">folder</i>
<span>Import collections</span>
</button>
</label>
<input
ref="collectionUpload"
name="collectionUpload"
type="file"
@change="uploadCollection"
/>
</li>
</ul>
<ul>
<li>
<Editor
v-model="collectionJSON"
:lang="'json'"
:options="{
maxLines: '16',
minLines: '8',
fontSize: '16px',
autoScrollEditorIntoView: true,
showPrintMargin: false,
useWorker: false
}"
/>
</li>
</ul>
<ul>
<li>
<button class="icon" @click="getDoc">
<i class="material-icons">book</i>
<span>Generate Documentation</span>
</button>
</li>
</ul>
</pw-section>
<pw-section class="green" label="Documentation" ref="documentation">
<p v-if="this.items.length === 0" class="info">
Generate documentation first
</p>
<div>
<span
class="collection"
v-for="(collection, index) in this.items"
:key="index"
>
<h2>
<i class="material-icons">folder</i>
{{ collection.name || "None" }}
</h2>
<span
class="folder"
v-for="(folder, index) in collection.folders"
:key="index"
>
<h3>
<i class="material-icons">folder_open</i>
{{ folder.name || "None" }}
</h3>
<span
class="request"
v-for="(request, index) in folder.requests"
:key="index"
>
<h4>
<i class="material-icons">insert_drive_file</i>
{{ request.name || "None" }}
</h4>
<p class="doc-desc" v-if="request.url">
<span>
URL: <code>{{ request.url || "None" }}</code>
</span>
</p>
<p class="doc-desc" v-if="request.path">
<span>
Path: <code>{{ request.path || "None" }}</code>
</span>
</p>
<p class="doc-desc" v-if="request.method">
<span>
Method: <code>{{ request.method || "None" }}</code>
</span>
</p>
<p class="doc-desc" v-if="request.auth">
<span>
Authentication:
<code>{{ request.auth || "None" }}</code>
</span>
</p>
<p class="doc-desc" v-if="request.httpUser">
<span>
Username: <code>{{ request.httpUser || "None" }}</code>
</span>
</p>
<p class="doc-desc" v-if="request.httpPassword">
<span>
Password:
<code>{{ request.httpPassword || "None" }}</code>
</span>
</p>
<p class="doc-desc" v-if="request.bearerToken">
<span>
Token: <code>{{ request.bearerToken || "None" }}</code>
</span>
</p>
<h4 v-if="request.headers.length > 0">Headers</h4>
<span
v-if="request.headers"
v-for="header in request.headers"
:key="header.key"
>
<p class="doc-desc">
<span>
{{ header.key || "None" }}:
<code>{{ header.value || "None" }}</code>
</span>
</p>
</span>
<h4 v-if="request.params.length > 0">Parameters</h4>
<span
v-if="request.params"
v-for="parameter in request.params"
:key="parameter.key"
>
<p class="doc-desc">
<span>
{{ parameter.key || "None" }}:
<code>{{ parameter.value || "None" }}</code>
</span>
</p>
</span>
<h4 v-if="request.bodyParam">Payload</h4>
<span
v-if="request.bodyParam"
v-for="payload in request.bodyParam"
:key="payload.key"
>
<p class="doc-desc">
<span>
{{ payload.key || "None" }}:
<code>{{ payload.value || "None" }}</code>
</span>
</p>
</span>
<p class="doc-desc" v-if="request.rawParams">
<span>
Parameters: <code>{{ request.rawParams || "None" }}</code>
</span>
</p>
<p class="doc-desc" v-if="request.contentType">
<span>
Content Type:
<code>{{ request.contentType || "None" }}</code>
</span>
</p>
<p class="doc-desc" v-if="request.requestType">
<span>
Request Type:
<code>{{ request.requestType || "None" }}</code>
</span>
</p>
</span>
</span>
<span
class="request"
v-for="(request, index) in collection.requests"
:key="`request-${index}`"
>
<h4>
<i class="material-icons">insert_drive_file</i>
{{ request.name || "None" }}
</h4>
<p class="doc-desc" v-if="request.url">
<span>
URL: <code>{{ request.url || "None" }}</code>
</span>
</p>
<p class="doc-desc" v-if="request.path">
<span>
Path: <code>{{ request.path || "None" }}</code>
</span>
</p>
<p class="doc-desc" v-if="request.method">
<span>
Method: <code>{{ request.method || "None" }}</code>
</span>
</p>
<p class="doc-desc" v-if="request.auth">
<span>
Authentication:
<code>{{ request.auth || "None" }}</code>
</span>
</p>
<p class="doc-desc" v-if="request.httpUser">
<span>
Username: <code>{{ request.httpUser || "None" }}</code>
</span>
</p>
<p class="doc-desc" v-if="request.httpPassword">
<span>
Password: <code>{{ request.httpPassword || "None" }}</code>
</span>
</p>
<p class="doc-desc" v-if="request.bearerToken">
<span>
Token: <code>{{ request.bearerToken || "None" }}</code>
</span>
</p>
<h4 v-if="request.headers.length > 0">Headers</h4>
<span
v-if="request.headers"
v-for="header in request.headers"
:key="header.key"
>
<p class="doc-desc">
<span>
{{ header.key || "None" }}:
<code>{{ header.value || "None" }}</code>
</span>
</p>
</span>
<h4 v-if="request.params.length > 0">Parameters</h4>
<span
v-if="request.params"
v-for="parameter in request.params"
:key="parameter.key"
>
<p class="doc-desc">
<span>
{{ parameter.key || "None" }}:
<code>{{ parameter.value || "None" }}</code>
</span>
</p>
</span>
<h4 v-if="request.bodyParam">Payload</h4>
<span
v-if="request.bodyParam"
v-for="payload in request.bodyParam"
:key="payload.key"
>
<p class="doc-desc">
<span>
{{ payload.key || "None" }}:
<code>{{ payload.value || "None" }}</code>
</span>
</p>
</span>
<p class="doc-desc" v-if="request.rawParams">
<span>
Parameters: <code>{{ request.rawParams || "None" }}</code>
</span>
</p>
<p class="doc-desc" v-if="request.contentType">
<span>
Content Type:
<code>{{ request.contentType || "None" }}</code>
</span>
</p>
<p class="doc-desc" v-if="request.requestType">
<span>
Request Type:
<code>{{ request.requestType || "None" }}</code>
</span>
</p>
</span>
</span>
</div>
</pw-section>
</div>
</template>
<style scoped lang="scss">
.collection,
.folder,
.request,
.doc-desc {
display: flex;
flex-flow: column;
justify-content: center;
flex: 1;
padding: 16px;
.material-icons {
margin-right: 16px;
}
}
.collection {
}
.folder {
border-left: 1px solid var(--brd-color);
margin: 16px 0 0;
}
.request {
border: 1px solid var(--brd-color);
border-radius: 8px;
margin: 16px 0 0;
h4 {
margin: 8px 0;
}
}
.doc-desc {
color: var(--fg-light-color);
border-bottom: 1px dashed var(--brd-color);
margin: 0;
&:last-child {
border-bottom: none;
}
}
</style>
<script>
import AceEditor from "../components/ace-editor";
export default {
components: {
"pw-section": () => import("../components/section"),
Editor: AceEditor
},
data() {
return {
collectionJSON: "[]",
items: []
};
},
methods: {
uploadCollection() {
this.rawInput = true;
let file = this.$refs.collectionUpload.files[0];
if (file !== undefined && file !== null) {
let reader = new FileReader();
reader.onload = e => {
this.collectionJSON = e.target.result;
};
reader.readAsText(file);
this.$toast.info("File imported", {
icon: "attach_file"
});
} else {
this.$toast.error("Choose a file", {
icon: "attach_file"
});
}
},
getDoc() {
try {
this.items = JSON.parse(this.collectionJSON);
this.$toast.info("Documentation generated", {
icon: "book"
});
} catch (e) {
this.$toast.error(e, {
icon: "code"
});
}
}
}
};
</script>

888
pages/graphql.vue Normal file
View File

@@ -0,0 +1,888 @@
<template>
<div class="page">
<div class="content">
<div class="page-columns inner-left">
<pw-section class="blue" label="Endpoint" ref="endpoint">
<ul>
<li>
<label for="url">{{ $t("url") }}</label>
<input
id="url"
type="url"
v-model="url"
@keyup.enter="getSchema()"
/>
</li>
<div>
<li>
<label for="get" class="hide-on-small-screen">&nbsp;</label>
<button id="get" name="get" @click="getSchema">
{{ $t("get_schema") }}
<span><i class="material-icons">send</i></span>
</button>
</li>
</div>
</ul>
</pw-section>
<pw-section class="orange" label="Headers" ref="headers">
<ul>
<li>
<div class="flex-wrap">
<label for="headerList">{{ $t("header_list") }}</label>
<div>
<button
class="icon"
@click="headers = []"
v-tooltip.bottom="'Clear'"
>
<i class="material-icons">clear_all</i>
</button>
</div>
</div>
<textarea
id="headerList"
readonly
v-textarea-auto-height="headerString"
v-model="headerString"
placeholder="(add at least one header)"
rows="1"
></textarea>
</li>
</ul>
<ul v-for="(header, index) in headers" :key="index">
<li>
<autocomplete
:placeholder="'header ' + (index + 1)"
:source="commonHeaders"
:spellcheck="false"
:value="header.key"
@input="
$store.commit('setGQLHeaderKey', {
index,
value: $event
})
"
autofocus
/>
</li>
<li>
<input
:placeholder="'value ' + (index + 1)"
:name="'value' + index"
:value="header.value"
@change="
$store.commit('setGQLHeaderValue', {
index,
value: $event.target.value
})
"
autofocus
/>
</li>
<div>
<li>
<button
class="icon"
@click="removeRequestHeader(index)"
id="header"
>
<i class="material-icons">delete</i>
</button>
</li>
</div>
</ul>
<ul>
<li>
<button class="icon" @click="addRequestHeader">
<i class="material-icons">add</i>
<span>{{ $t("add_new") }}</span>
</button>
</li>
</ul>
</pw-section>
<pw-section class="green" label="Schema" ref="schema">
<div class="flex-wrap">
<label>{{ $t("response") }}</label>
<div>
<button
class="icon"
@click="ToggleExpandResponse"
ref="ToggleExpandResponse"
v-tooltip="{
content: !expandResponse
? 'Expand response'
: 'Collapse response'
}"
>
<i class="material-icons">
{{ !expandResponse ? "unfold_more" : "unfold_less" }}
</i>
</button>
<button
class="icon"
@click="downloadResponse"
ref="downloadResponse"
v-tooltip="'Download file'"
>
<i class="material-icons">get_app</i>
</button>
<button
class="icon"
ref="copySchemaCode"
@click="copySchema"
v-tooltip="'Copy Schema'"
>
<i class="material-icons">file_copy</i>
</button>
</div>
</div>
<Editor
:value="schemaString"
:lang="'graphqlschema'"
:options="{
maxLines: responseBodyMaxLines,
minLines: '16',
fontSize: '16px',
autoScrollEditorIntoView: true,
readOnly: true,
showPrintMargin: false,
useWorker: false
}"
/>
</pw-section>
<pw-section class="cyan" label="Query" ref="query">
<div class="flex-wrap">
<label for="gqlQuery">{{ $t("query") }}</label>
<div>
<button
class="icon"
@click="runQuery()"
v-tooltip.bottom="'Run Query'"
>
<i class="material-icons">play_arrow</i>
</button>
<button
class="icon"
@click="copyQuery"
ref="copyQueryButton"
v-tooltip="'Copy Query'"
>
<i class="material-icons">file_copy</i>
</button>
</div>
</div>
<Editor
v-model="gqlQueryString"
:options="{
maxLines: responseBodyMaxLines,
minLines: '16',
fontSize: '16px',
autoScrollEditorIntoView: true,
showPrintMargin: false,
useWorker: false
}"
/>
<div class="flex-wrap">
<label>{{ $t("query_variables") }}</label>
<div>
<button
class="icon"
@click="variables = []"
v-tooltip.bottom="'Clear'"
>
<i class="material-icons">clear_all</i>
</button>
</div>
</div>
<ul v-for="(variable, index) in variables" :key="index">
<li>
<input
:placeholder="'variable ' + (index + 1)"
:name="'variable_key_' + index"
:value="variable.key"
@change="
$store.commit('setGQLVariableKey', {
index,
value: $event.target.value
})
"
autofocus
/>
</li>
<li>
<input
:placeholder="'value ' + (index + 1)"
:name="'variable_value_' + index"
:value="variable.value"
@change="
$store.commit('setGQLVariableValue', {
index,
value: $event.target.value
})
"
autofocus
/>
</li>
<div>
<li>
<button class="icon" @click="removeQueryVariable(index)">
<i class="material-icons">delete</i>
</button>
</li>
</div>
</ul>
<ul>
<li>
<button class="icon" @click="addQueryVariable">
<i class="material-icons">add</i>
<span>{{ $t("add_new") }}</span>
</button>
</li>
</ul>
</pw-section>
<pw-section class="purple" label="Response" ref="response">
<div class="flex-wrap">
<label for="responseField">{{ $t("response") }}</label>
<div>
<button
class="icon"
@click="copyResponse"
ref="copyResponseButton"
v-tooltip="'Copy Response'"
>
<i class="material-icons">file_copy</i>
</button>
</div>
</div>
<Editor
:value="responseString"
:lang="'json'"
:options="{
maxLines: responseBodyMaxLines,
minLines: '16',
fontSize: '16px',
autoScrollEditorIntoView: true,
readOnly: true,
showPrintMargin: false,
useWorker: false
}"
/>
</pw-section>
</div>
<aside class="sticky-inner inner-right">
<pw-section class="purple" label="Docs" ref="docs">
<section>
<input
v-if="queryFields.length > 0"
id="queries-tab"
type="radio"
name="side"
checked="checked"
/>
<label v-if="queryFields.length > 0" for="queries-tab">
{{ $t("queries") }}
</label>
<div v-if="queryFields.length > 0" class="tab">
<div v-for="field in queryFields" :key="field.name">
<gql-field :gqlField="field" />
</div>
</div>
<input
v-if="mutationFields.length > 0"
id="mutations-tab"
type="radio"
name="side"
checked="checked"
/>
<label v-if="mutationFields.length > 0" for="mutations-tab">
{{ $t("mutations") }}
</label>
<div v-if="mutationFields.length > 0" class="tab">
<div v-for="field in mutationFields" :key="field.name">
<gql-field :gqlField="field" />
</div>
</div>
<input
v-if="subscriptionFields.length > 0"
id="subscriptions-tab"
type="radio"
name="side"
checked="checked"
/>
<label v-if="subscriptionFields.length > 0" for="subscriptions-tab">
{{ $t("subscriptions") }}
</label>
<div v-if="subscriptionFields.length > 0" class="tab">
<div v-for="field in subscriptionFields" :key="field.name">
<gql-field :gqlField="field" />
</div>
</div>
<input
v-if="gqlTypes.length > 0"
id="gqltypes-tab"
type="radio"
name="side"
checked="checked"
/>
<label v-if="gqlTypes.length > 0" for="gqltypes-tab">
{{ $t("types") }}
</label>
<div v-if="gqlTypes.length > 0" class="tab">
<div v-for="type in gqlTypes" :key="type.name">
<gql-type :gqlType="type" />
</div>
</div>
</section>
<p
v-if="
queryFields.length === 0 &&
mutationFields.length === 0 &&
subscriptionFields.length === 0 &&
gqlTypes.length === 0
"
class="info"
>
Send a request first
</p>
</pw-section>
</aside>
</div>
</div>
</template>
<style scoped lang="scss">
.tab {
max-height: calc(100vh - 186px);
overflow: auto;
}
</style>
<script>
import axios from "axios";
import * as gql from "graphql";
import textareaAutoHeight from "../directives/textareaAutoHeight";
import AceEditor from "../components/ace-editor";
export default {
directives: {
textareaAutoHeight
},
components: {
"pw-section": () => import("../components/section"),
"gql-field": () => import("../components/graphql/field"),
"gql-type": () => import("../components/graphql/type"),
autocomplete: () => import("../components/autocomplete"),
Editor: AceEditor
},
data() {
return {
schemaString: "",
commonHeaders: [
"WWW-Authenticate",
"Authorization",
"Proxy-Authenticate",
"Proxy-Authorization",
"Age",
"Cache-Control",
"Clear-Site-Data",
"Expires",
"Pragma",
"Warning",
"Accept-CH",
"Accept-CH-Lifetime",
"Early-Data",
"Content-DPR",
"DPR",
"Device-Memory",
"Save-Data",
"Viewport-Width",
"Width",
"Last-Modified",
"ETag",
"If-Match",
"If-None-Match",
"If-Modified-Since",
"If-Unmodified-Since",
"Vary",
"Connection",
"Keep-Alive",
"Accept",
"Accept-Charset",
"Accept-Encoding",
"Accept-Language",
"Expect",
"Max-Forwards",
"Cookie",
"Set-Cookie",
"Cookie2",
"Set-Cookie2",
"Access-Control-Allow-Origin",
"Access-Control-Allow-Credentials",
"Access-Control-Allow-Headers",
"Access-Control-Allow-Methods",
"Access-Control-Expose-Headers",
"Access-Control-Max-Age",
"Access-Control-Request-Headers",
"Access-Control-Request-Method",
"Origin",
"Service-Worker-Allowed",
"Timing-Allow-Origin",
"X-Permitted-Cross-Domain-Policies",
"DNT",
"Tk",
"Content-Disposition",
"Content-Length",
"Content-Type",
"Content-Encoding",
"Content-Language",
"Content-Location",
"Forwarded",
"X-Forwarded-For",
"X-Forwarded-Host",
"X-Forwarded-Proto",
"Via",
"Location",
"From",
"Host",
"Referer",
"Referrer-Policy",
"User-Agent",
"Allow",
"Server",
"Accept-Ranges",
"Range",
"If-Range",
"Content-Range",
"Cross-Origin-Opener-Policy",
"Cross-Origin-Resource-Policy",
"Content-Security-Policy",
"Content-Security-Policy-Report-Only",
"Expect-CT",
"Feature-Policy",
"Public-Key-Pins",
"Public-Key-Pins-Report-Only",
"Strict-Transport-Security",
"Upgrade-Insecure-Requests",
"X-Content-Type-Options",
"X-Download-Options",
"X-Frame-Options",
"X-Powered-By",
"X-XSS-Protection",
"Last-Event-ID",
"NEL",
"Ping-From",
"Ping-To",
"Report-To",
"Transfer-Encoding",
"TE",
"Trailer",
"Sec-WebSocket-Key",
"Sec-WebSocket-Extensions",
"Sec-WebSocket-Accept",
"Sec-WebSocket-Protocol",
"Sec-WebSocket-Version",
"Accept-Push-Policy",
"Accept-Signature",
"Alt-Svc",
"Date",
"Large-Allocation",
"Link",
"Push-Policy",
"Retry-After",
"Signature",
"Signed-Headers",
"Server-Timing",
"SourceMap",
"Upgrade",
"X-DNS-Prefetch-Control",
"X-Firefox-Spdy",
"X-Pingback",
"X-Requested-With",
"X-Robots-Tag",
"X-UA-Compatible"
],
queryFields: [],
mutationFields: [],
subscriptionFields: [],
gqlTypes: [],
responseString: "",
copyButton: '<i class="material-icons">file_copy</i>',
downloadButton: '<i class="material-icons">get_app</i>',
doneButton: '<i class="material-icons">done</i>',
expandResponse: false,
responseBodyMaxLines: 16
};
},
computed: {
url: {
get() {
return this.$store.state.gql.url;
},
set(value) {
this.$store.commit("setGQLState", { value, attribute: "url" });
}
},
headers: {
get() {
return this.$store.state.gql.headers;
},
set(value) {
this.$store.commit("setGQLState", { value, attribute: "headers" });
}
},
variables: {
get() {
return this.$store.state.gql.variables;
},
set(value) {
this.$store.commit("setGQLState", { value, attribute: "variables" });
}
},
gqlQueryString: {
get() {
return this.$store.state.gql.query;
},
set(value) {
this.$store.commit("setGQLState", { value, attribute: "query" });
}
},
headerString() {
const result = this.headers
.filter(({ key }) => !!key)
.map(({ key, value }) => `${key}: ${value}`)
.join(",\n");
return result === "" ? "" : `${result}`;
}
},
methods: {
copySchema() {
this.$refs.copySchemaCode.innerHTML = this.doneButton;
const aux = document.createElement("textarea");
aux.innerText = this.schemaString;
document.body.appendChild(aux);
aux.select();
document.execCommand("copy");
document.body.removeChild(aux);
this.$toast.success("Copied to clipboard", {
icon: "done"
});
setTimeout(
() => (this.$refs.copySchemaCode.innerHTML = this.copyButton),
1000
);
},
copyQuery() {
this.$refs.copyQueryButton.innerHTML = this.doneButton;
const aux = document.createElement("textarea");
aux.innerText = this.gqlQueryString;
document.body.appendChild(aux);
aux.select();
document.execCommand("copy");
document.body.removeChild(aux);
this.$toast.success("Copied to clipboard", {
icon: "done"
});
setTimeout(
() => (this.$refs.copyQueryButton.innerHTML = this.copyButton),
1000
);
},
copyResponse() {
this.$refs.copyResponseButton.innerHTML = this.doneButton;
const aux = document.createElement("textarea");
aux.innerText = this.responseString;
document.body.appendChild(aux);
aux.select();
document.execCommand("copy");
document.body.removeChild(aux);
this.$toast.success("Copied to clipboard", {
icon: "done"
});
setTimeout(
() => (this.$refs.copyResponseButton.innerHTML = this.copyButton),
1000
);
},
async runQuery() {
const startTime = Date.now();
this.$nuxt.$loading.start();
this.scrollInto("response");
try {
let headers = {};
this.headers.forEach(header => {
headers[header.key] = header.value;
});
let variables = {};
const gqlQueryString = this.gqlQueryString;
this.variables.forEach(variable => {
// todo: better variable type validation
const intRex = new RegExp(`\$${variable.key}\: Int`);
intRex.compile();
const floatRex = new RegExp(`\$${variable.key}\: Float`);
floatRex.compile();
if (intRex.test(gqlQueryString)) {
variables[variable.key] = parseInt(variable.value);
} else if (floatRex.test(gqlQueryString)) {
variables[variable.key] = parseFloat(variable.value);
} else {
variables[variable.key] = variable.value;
}
});
const reqOptions = {
method: "post",
url: this.url,
headers: {
...headers,
"content-type": "application/json"
},
data: JSON.stringify({ query: gqlQueryString, variables })
};
const reqConfig = this.$store.state.postwoman.settings.PROXY_ENABLED
? {
method: "post",
url:
this.$store.state.postwoman.settings.PROXY_URL ||
`https://postwoman.apollotv.xyz/`,
data: reqOptions
}
: reqOptions;
const res = await axios(reqConfig);
const data = this.$store.state.postwoman.settings.PROXY_ENABLED
? res.data
: res;
this.responseString = JSON.stringify(data.data, null, 2);
this.$nuxt.$loading.finish();
const duration = Date.now() - startTime;
this.$toast.info(`Finished in ${duration}ms`, {
icon: "done"
});
} catch (error) {
this.$nuxt.$loading.finish();
this.$toast.error(error + " (F12 for details)", {
icon: "error"
});
console.log("Error", error);
}
},
async getSchema() {
const startTime = Date.now();
this.schemaString = "Loading...";
this.scrollInto("schema");
// Start showing the loading bar as soon as possible.
// The nuxt axios module will hide it when the request is made.
this.$nuxt.$loading.start();
try {
const query = JSON.stringify({
query: gql.getIntrospectionQuery()
});
let headers = {};
this.headers.forEach(header => {
headers[header.key] = header.value;
});
const reqOptions = {
method: "post",
url: this.url,
headers: {
...headers,
"content-type": "application/json"
},
data: query
};
// console.log(reqOptions);
const reqConfig = this.$store.state.postwoman.settings.PROXY_ENABLED
? {
method: "post",
url:
this.$store.state.postwoman.settings.PROXY_URL ||
`https://postwoman.apollotv.xyz/`,
data: reqOptions
}
: reqOptions;
const res = await axios(reqConfig);
const data = this.$store.state.postwoman.settings.PROXY_ENABLED
? res.data
: res;
const schema = gql.buildClientSchema(data.data.data);
this.schemaString = gql.printSchema(schema, {
commentDescriptions: true
});
if (schema.getQueryType()) {
const fields = schema.getQueryType().getFields();
const qFields = [];
for (const field in fields) {
qFields.push(fields[field]);
}
this.queryFields = qFields;
}
if (schema.getMutationType()) {
const fields = schema.getMutationType().getFields();
const mFields = [];
for (const field in fields) {
mFields.push(fields[field]);
}
this.mutationFields = mFields;
}
if (schema.getSubscriptionType()) {
const fields = schema.getSubscriptionType().getFields();
const sFields = [];
for (const field in fields) {
sFields.push(fields[field]);
}
this.subscriptionFields = sFields;
}
const typeMap = schema.getTypeMap();
const types = [];
const queryTypeName = schema.getQueryType()
? schema.getQueryType().name
: "";
const mutationTypeName = schema.getMutationType()
? schema.getMutationType().name
: "";
const subscriptionTypeName = schema.getSubscriptionType()
? schema.getSubscriptionType().name
: "";
for (const type in typeMap) {
if (
!typeMap[type].name.startsWith("__") &&
![queryTypeName, mutationTypeName, subscriptionTypeName].includes(
typeMap[type].name
) &&
typeMap[type] instanceof gql.GraphQLObjectType
) {
types.push(typeMap[type]);
}
}
this.gqlTypes = types;
this.$nuxt.$loading.finish();
const duration = Date.now() - startTime;
this.$toast.info(`Finished in ${duration}ms`, {
icon: "done"
});
} catch (error) {
this.$nuxt.$loading.finish();
this.schemaString = error + ". Check console for details.";
this.$toast.error(error + " (F12 for details)", {
icon: "error"
});
console.log("Error", error);
}
},
ToggleExpandResponse() {
this.expandResponse = !this.expandResponse;
this.responseBodyMaxLines =
this.responseBodyMaxLines == Infinity ? 16 : Infinity;
},
downloadResponse() {
const dataToWrite = JSON.stringify(this.schemaString, null, 2);
const file = new Blob([dataToWrite], { type: "application/json" });
const a = document.createElement("a"),
url = URL.createObjectURL(file);
a.href = url;
a.download = (this.url + " on " + Date() + ".graphql").replace(
/\./g,
"[dot]"
);
document.body.appendChild(a);
a.click();
this.$refs.downloadResponse.innerHTML = this.doneButton;
this.$toast.success("Download started", {
icon: "done"
});
setTimeout(() => {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
this.$refs.downloadResponse.innerHTML = this.downloadButton;
}, 1000);
},
addRequestHeader(index) {
this.$store.commit("addGQLHeader", {
key: "",
value: ""
});
return false;
},
removeRequestHeader(index) {
// .slice() is used so we get a separate array, rather than just a reference
const oldHeaders = this.headers.slice();
this.$store.commit("removeGQLHeader", index);
this.$toast.error("Deleted", {
icon: "delete",
action: {
text: "Undo",
duration: 4000,
onClick: (e, toastObject) => {
this.headers = oldHeaders;
toastObject.remove();
}
}
});
// console.log(oldHeaders);
},
addQueryVariable(index) {
this.$store.commit("addGQLVariable", {
key: "",
value: ""
});
return false;
},
removeQueryVariable(index) {
const oldVariables = this.variables.slice();
this.$store.commit("removeGQLVariable", index);
this.$toast.error("Deleted", {
icon: "delete",
action: {
text: "Undo",
duration: 4000,
onClick: (e, toastObject) => {
this.variables = oldVariables;
toastObject.remove();
}
}
});
// console.log(oldVariables);
},
scrollInto(view) {
this.$refs[view].$el.scrollIntoView({
behavior: "smooth"
});
}
}
};
</script>

File diff suppressed because it is too large Load Diff

442
pages/realtime.vue Normal file
View File

@@ -0,0 +1,442 @@
<template>
<div class="page">
<section id="options">
<input id="tab-one" type="radio" name="options" checked="checked" />
<label for="tab-one">{{ $t("websocket") }}</label>
<div class="tab">
<pw-section class="blue" label="Request" ref="request">
<ul>
<li>
<label for="url">{{ $t("url") }}</label>
<input
id="url"
type="url"
:class="{ error: !urlValid }"
v-model="url"
@keyup.enter="urlValid ? toggleConnection() : null"
/>
</li>
<div>
<li>
<label for="connect" class="hide-on-small-screen">&nbsp;</label>
<button
:disabled="!urlValid"
id="connect"
name="connect"
@click="toggleConnection"
>
{{ !connectionState ? $t("connect") : $t("disconnect") }}
<span>
<i class="material-icons">
{{ !connectionState ? "sync" : "sync_disabled" }}
</i>
</span>
</button>
</li>
</div>
</ul>
</pw-section>
<pw-section
class="purple"
label="Communication"
id="response"
ref="response"
>
<ul>
<li>
<label for="log">Log</label>
<div id="log" name="log" class="log">
<span v-if="communication.log">
<span
v-for="(logEntry, index) in communication.log"
:style="{ color: logEntry.color }"
:key="index"
>@ {{ logEntry.ts }}{{ getSourcePrefix(logEntry.source)
}}{{ logEntry.payload }}</span
>
</span>
<span v-else>{{ $t("waiting_for_connection") }}</span>
</div>
</li>
</ul>
<ul>
<li>
<label for="message">{{ $t("message") }}</label>
<input
id="message"
name="message"
type="text"
v-model="communication.input"
:readonly="!connectionState"
@keyup.enter="connectionState ? sendMessage() : null"
/>
</li>
<div>
<li>
<label for="send" class="hide-on-small-screen">&nbsp;</label>
<button
id="send"
name="send"
:disabled="!connectionState"
@click="sendMessage"
>
{{ $t("send") }}
<span>
<i class="material-icons">send</i>
</span>
</button>
</li>
</div>
</ul>
</pw-section>
</div>
<input id="tab-two" type="radio" name="options" />
<label for="tab-two">{{ $t("sse") }}</label>
<div class="tab">
<pw-section class="blue" label="Request" ref="request">
<ul>
<li>
<label for="server">{{ $t("server") }}</label>
<input
id="server"
type="url"
:class="{ error: !serverValid }"
v-model="server"
@keyup.enter="serverValid ? toggleSSEConnection() : null"
/>
</li>
<div>
<li>
<label for="start" class="hide-on-small-screen">&nbsp;</label>
<button
:disabled="!serverValid"
id="start"
name="start"
@click="toggleSSEConnection"
>
{{ !connectionSSEState ? $t("start") : $t("stop") }}
<span>
<i class="material-icons">
{{ !connectionSSEState ? "sync" : "sync_disabled" }}
</i>
</span>
</button>
</li>
</div>
</ul>
</pw-section>
<pw-section
class="purple"
label="Communication"
id="response"
ref="response"
>
<ul>
<li>
<label for="log">{{ $t("events") }}</label>
<div id="log" name="log" class="log">
<span v-if="events.log">
<span
v-for="(logEntry, index) in events.log"
:style="{ color: logEntry.color }"
:key="index"
>@ {{ logEntry.ts }}{{ getSourcePrefix(logEntry.source)
}}{{ logEntry.payload }}</span
>
</span>
<span v-else>{{ $t("waiting_for_connection") }}</span>
</div>
<div id="result"></div>
</li>
</ul>
</pw-section>
</div>
</section>
</div>
</template>
<style scoped lang="scss">
div.log {
margin: 4px;
padding: 8px 16px;
width: calc(100% - 8px);
border-radius: 8px;
background-color: var(--bg-dark-color);
color: var(--fg-color);
height: 256px;
overflow: auto;
&,
span {
font-size: 16px;
font-family: "Roboto Mono", monospace;
font-weight: 400;
}
span {
display: block;
white-space: pre-wrap;
word-wrap: break-word;
word-break: break-all;
}
}
</style>
<script>
export default {
components: {
"pw-section": () => import("../components/section")
},
data() {
return {
connectionState: false,
url: "wss://echo.websocket.org",
socket: null,
communication: {
log: null,
input: ""
},
connectionSSEState: false,
server: "https://express-eventsource.herokuapp.com/events",
sse: null,
events: {
log: null,
input: ""
}
};
},
computed: {
urlValid() {
const protocol = "^(wss?:\\/\\/)?";
const validIP = new RegExp(
protocol +
"(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"
);
const validHostname = new RegExp(
protocol +
"(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]).)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9/])$"
);
return validIP.test(this.url) || validHostname.test(this.url);
},
serverValid() {
const protocol = "^(https?:\\/\\/)?";
const validIP = new RegExp(
protocol +
"(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"
);
const validHostname = new RegExp(
protocol +
"(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]).)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9/])$"
);
return validIP.test(this.server) || validHostname.test(this.server);
}
},
methods: {
toggleConnection() {
// If it is connecting:
if (!this.connectionState) return this.connect();
// Otherwise, it's disconnecting.
else return this.disconnect();
},
connect() {
this.communication.log = [
{
payload: `Connecting to ${this.url}...`,
source: "info",
color: "var(--ac-color)"
}
];
try {
this.socket = new WebSocket(this.url);
this.socket.onopen = event => {
this.connectionState = true;
this.communication.log = [
{
payload: `Connected to ${this.url}.`,
source: "info",
color: "var(--ac-color)",
ts: new Date().toLocaleTimeString()
}
];
this.$toast.success("Connected", {
icon: "sync"
});
};
this.socket.onerror = event => {
this.handleError();
};
this.socket.onclose = event => {
this.connectionState = false;
this.communication.log.push({
payload: `Disconnected from ${this.url}.`,
source: "info",
color: "#ff5555",
ts: new Date().toLocaleTimeString()
});
this.$toast.error("Disconnected", {
icon: "sync_disabled"
});
};
this.socket.onmessage = event => {
this.communication.log.push({
payload: event.data,
source: "server",
ts: new Date().toLocaleTimeString()
});
};
} catch (ex) {
this.handleError(ex);
this.$toast.error("Something went wrong!", {
icon: "error"
});
}
},
disconnect() {
this.socket.close();
},
handleError(error) {
this.disconnect();
this.connectionState = false;
this.communication.log.push({
payload: `An error has occurred.`,
source: "info",
color: "#ff5555",
ts: new Date().toLocaleTimeString()
});
if (error !== null)
this.communication.log.push({
payload: error,
source: "info",
color: "#ff5555",
ts: new Date().toLocaleTimeString()
});
},
sendMessage() {
const message = this.communication.input;
this.socket.send(message);
this.communication.log.push({
payload: message,
source: "client",
ts: new Date().toLocaleTimeString()
});
this.communication.input = "";
},
collapse({ target }) {
const el = target.parentNode.className;
document.getElementsByClassName(el)[0].classList.toggle("hidden");
},
getSourcePrefix(source) {
const sourceEmojis = {
// Source used for info messages.
info: "\t [INFO]:\t",
// Source used for client to server messages.
client: "\t👽 [SENT]:\t",
// Source used for server to client messages.
server: "\t📥 [RECEIVED]:\t"
};
if (Object.keys(sourceEmojis).includes(source))
return sourceEmojis[source];
return "";
},
toggleSSEConnection() {
// If it is connecting:
if (!this.connectionSSEState) return this.start();
// Otherwise, it's disconnecting.
else return this.stop();
},
start() {
this.events.log = [
{
payload: `Connecting to ${this.server}...`,
source: "info",
color: "var(--ac-color)"
}
];
if (typeof EventSource !== "undefined") {
try {
this.sse = new EventSource(this.server);
this.sse.onopen = event => {
this.connectionSSEState = true;
this.events.log = [
{
payload: `Connected to ${this.server}.`,
source: "info",
color: "var(--ac-color)",
ts: new Date().toLocaleTimeString()
}
];
this.$toast.success("Connected", {
icon: "sync"
});
};
this.sse.onerror = event => {
this.handleSSEError();
};
this.sse.onclose = event => {
this.connectionSSEState = false;
this.events.log.push({
payload: `Disconnected from ${this.server}.`,
source: "info",
color: "#ff5555",
ts: new Date().toLocaleTimeString()
});
this.$toast.error("Disconnected", {
icon: "sync_disabled"
});
};
this.sse.onmessage = event => {
this.events.log.push({
payload: event.data,
source: "server",
ts: new Date().toLocaleTimeString()
});
};
} catch (ex) {
this.handleSSEError(ex);
this.$toast.error("Something went wrong!", {
icon: "error"
});
}
} else {
this.events.log = [
{
payload: `This browser doesn't seems to have Server Sent Events support.`,
source: "info",
color: "#ff5555",
ts: new Date().toLocaleTimeString()
}
];
}
},
handleSSEError(error) {
this.stop();
this.connectionSSEState = false;
this.events.log.push({
payload: `An error has occurred.`,
source: "info",
color: "#ff5555",
ts: new Date().toLocaleTimeString()
});
if (error !== null)
this.events.log.push({
payload: error,
source: "info",
color: "#ff5555",
ts: new Date().toLocaleTimeString()
});
},
stop() {
this.sse.onclose();
this.sse.close();
}
},
updated: function() {
this.$nextTick(function() {
const divLog = document.getElementById("log");
divLog.scrollBy(0, divLog.scrollHeight + 100);
});
}
};
</script>

View File

@@ -3,11 +3,11 @@
<pw-section class="cyan" label="Theme" ref="theme">
<ul>
<li>
<h3 class="title">Background</h3>
<label>{{ $t("background") }}</label>
<div class="backgrounds">
<span
:key="theme.class"
@click="applyTheme(theme.class, theme.color)"
@click="applyTheme(theme)"
v-for="theme in themes"
>
<swatch
@@ -15,6 +15,7 @@
:class="{ vibrant: theme.vibrant }"
:color="theme.color"
:name="theme.name"
class="bg"
></swatch>
</span>
</div>
@@ -22,7 +23,7 @@
</ul>
<ul>
<li>
<h3 class="title">Color</h3>
<label>{{ $t("color") }}</label>
<div class="colors">
<span
:key="entry.color"
@@ -34,6 +35,7 @@
:class="{ vibrant: entry.vibrant }"
:color="entry.color"
:name="entry.name"
class="fg"
/>
</span>
</div>
@@ -41,39 +43,75 @@
</ul>
<ul>
<li>
<h3 class="title">Labels</h3>
<span>
<pw-toggle
:on="settings.FRAME_COLORS_ENABLED"
@change="toggleSetting('FRAME_COLORS_ENABLED')"
>Multi-color {{ settings.FRAME_COLORS_ENABLED ? "Enabled" : "Disabled" }}</pw-toggle>
>
{{ $t("multi_color") }}
{{
settings.FRAME_COLORS_ENABLED ? $t("enabled") : $t("disabled")
}}
</pw-toggle>
</span>
</li>
</ul>
</pw-section>
<br />
<pw-section class="blue" label="Proxy" ref="proxy">
<ul>
<li>
<span>
<pw-toggle
:on="settings.PROXY_ENABLED"
@change="toggleSetting('PROXY_ENABLED')"
>Proxy {{ settings.PROXY_ENABLED ? "enabled" : "disabled" }}</pw-toggle>
</span>
<div class="flex-wrap">
<span>
<pw-toggle
:on="settings.PROXY_ENABLED"
@change="toggleSetting('PROXY_ENABLED')"
>
{{ $t("proxy") }}
{{ settings.PROXY_ENABLED ? $t("enabled") : $t("disabled") }}
</pw-toggle>
</span>
<a
href="https://github.com/liyasthomas/postwoman/wiki/Proxy"
target="_blank"
rel="noopener"
>
<button class="icon" v-tooltip="'Wiki'">
<i class="material-icons">help</i>
</button>
</a>
</div>
</li>
</ul>
<ul>
<li>
<div class="flex-wrap">
<label for="url">{{ $t("url") }}</label>
<button
class="icon"
@click="settings.PROXY_URL = `https://postwoman.apollotv.xyz/`"
v-tooltip.bottom="'Reset to default'"
>
<i class="material-icons">clear_all</i>
</button>
</div>
<input
id="url"
type="url"
v-model="settings.PROXY_URL"
:disabled="!settings.PROXY_ENABLED"
/>
</li>
</ul>
<ul class="info">
<li>
<p>
Postwoman's Proxy is hosted by ApolloTV.
<br />Read the ApolloTV privacy policy
<a
href="https://apollotv.xyz/legal"
target="_blank"
>here</a>.
{{ $t("postwoman_official_proxy_hosting") }}
<br />
{{ $t("read_the") }}
<a href="https://apollotv.xyz/legal" target="_blank" rel="noopener">
{{ $t("apollotv_privacy_policy") }} </a
>.
</p>
</li>
</ul>
@@ -96,23 +134,14 @@
</div>
</template>
<style scoped>
.info {
margin-left: 4px;
color: var(--fg-light-color);
}
</style>
<style scoped lang="scss"></style>
<script>
import section from "../components/section";
import swatch from "../components/settings/swatch";
import toggle from "../components/toggle";
export default {
components: {
"pw-section": section,
"pw-toggle": toggle,
swatch: swatch
"pw-section": () => import("../components/section"),
"pw-toggle": () => import("../components/toggle"),
swatch: () => import("../components/settings/swatch")
},
data() {
@@ -122,26 +151,32 @@ export default {
// set the relevant values.
themes: [
{
color: "#252628",
color: "#202124",
name: "Kinda Dark",
class: ""
class: "",
aceEditor: "twilight"
},
{
color: "#ffffff",
name: "Clearly White",
vibrant: true,
class: "light"
class: "light",
aceEditor: "iplastic"
},
{
color: "#000000",
name: "Just Black",
class: "black"
class: "black",
aceEditor: "vibrant_ink"
},
{
color: "var(--bg-color)",
name: "Auto (system)",
vibrant: window.matchMedia("(prefers-color-scheme: light)").matches,
class: "auto"
class: "auto",
aceEditor: window.matchMedia("(prefers-color-scheme: light)").matches
? "iplastic"
: "twilight"
}
],
// You can define a new color here! It will simply store the color value.
@@ -199,7 +234,9 @@ export default {
this.$store.state.postwoman.settings.FRAME_COLORS_ENABLED || false,
PROXY_ENABLED:
this.$store.state.postwoman.settings.PROXY_ENABLED || false,
PROXY_URL: this.$store.state.postwoman.settings.PROXY_URL || "",
PROXY_URL:
this.$store.state.postwoman.settings.PROXY_URL ||
"https://postwoman.apollotv.xyz/",
PROXY_KEY: this.$store.state.postwoman.settings.PROXY_KEY || ""
}
};
@@ -216,28 +253,22 @@ export default {
},
methods: {
applyTheme(name, color) {
applyTheme({ class: name, color, aceEditor }) {
this.applySetting("THEME_CLASS", name);
this.applySetting("THEME_ACE_EDITOR", aceEditor);
document
.querySelector("meta[name=theme-color]")
.setAttribute("content", color);
this.applySetting("THEME_TAB_COLOR", color);
document.documentElement.className = name;
let imgGitHub = document.getElementById("imgGitHub");
imgGitHub.style["filter"] = "";
imgGitHub.style["webkit-filter"] = "invert(100%)";
if (name.includes("light")) {
imgGitHub.style["filter"] = "invert(100%)";
imgGitHub.style["webkit-filter"] = "invert(100%)";
}
},
setActiveColor(color, vibrant) {
// By default, the color is vibrant.
if (vibrant == null) vibrant = true;
if (vibrant === null) vibrant = true;
document.documentElement.style.setProperty("--ac-color", color);
document.documentElement.style.setProperty(
"--act-color",
vibrant ? "rgb(37, 38, 40)" : "#f8f8f2"
vibrant ? "rgba(32, 33, 36, 1)" : "rgba(255, 255, 255, 1)"
);
this.applySetting("THEME_COLOR", color.toUpperCase());
this.applySetting("THEME_COLOR_VIBRANT", vibrant);
@@ -258,9 +289,6 @@ export default {
toggleSetting(key) {
this.settings[key] = !this.settings[key];
this.$store.commit("postwoman/applySetting", [key, this.settings[key]]);
this.$router.replace("/settings", {
force: true
});
}
},
beforeMount() {

View File

@@ -1,244 +0,0 @@
<template>
<div class="page">
<pw-section class="blue" label="Request" ref="request">
<ul>
<li>
<label for="url">URL</label>
<input
id="url"
type="url"
:class="{ error: !urlValid }"
v-model="url"
@keyup.enter="urlValid ? toggleConnection() : null"
/>
</li>
<li>
<label for="connect" class="hide-on-small-screen">&nbsp;</label>
<button :disabled="!urlValid" id="connect" name="connect" @click="toggleConnection">
{{ toggleConnectionVerb }}
<span>
<i class="material-icons" v-if="!connectionState">sync</i>
<i class="material-icons" v-if="connectionState">sync_disabled</i>
</span>
</button>
</li>
</ul>
</pw-section>
<br />
<pw-section class="purple" label="Communication" id="response" ref="response">
<ul>
<li>
<label for="log">Log</label>
<div id="log" name="log" class="log">
<span v-if="communication.log">
<span
v-for="(logEntry, index) in communication.log"
:style="{ color: logEntry.color }"
:key="index"
>@ {{ logEntry.ts }} {{ getSourcePrefix(logEntry.source) }} {{ logEntry.payload }}</span>
</span>
<span v-else>(waiting for connection)</span>
</div>
</li>
</ul>
<ul>
<li>
<label for="message">Message</label>
<input
id="message"
name="message"
type="text"
v-model="communication.input"
:readonly="!connectionState"
@keyup.enter="connectionState ? sendMessage() : null"
/>
</li>
<li>
<label for="send" class="hide-on-small-screen">&nbsp;</label>
<button id="send" name="send" :disabled="!connectionState" @click="sendMessage">
Send
<span>
<i class="material-icons">send</i>
</span>
</button>
</li>
</ul>
</pw-section>
</div>
</template>
<style lang="scss">
div.log {
margin: 4px;
padding: 8px 16px;
width: calc(100% - 8px);
border-radius: 8px;
background-color: var(--bg-dark-color);
color: var(--fg-color);
height: 256px;
overflow: auto;
&,
span {
font-size: 18px;
font-family: "Roboto Mono", monospace;
}
span {
display: block;
white-space: pre-wrap;
}
}
</style>
<script>
import section from "../components/section";
export default {
components: {
"pw-section": section
},
data() {
return {
connectionState: false,
url: "wss://echo.websocket.org",
socket: null,
communication: {
log: null,
input: ""
}
};
},
computed: {
toggleConnectionVerb() {
return !this.connectionState ? "Connect" : "Disconnect";
},
urlValid() {
const pattern = new RegExp(
"^(wss?:\\/\\/)?" +
"((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|" +
"((\\d{1,3}\\.){3}\\d{1,3}))" +
"(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*" +
"(\\?[;&a-z\\d%_.~+=-]*)?" +
"(\\#[-a-z\\d_]*)?$",
"i"
);
return pattern.test(this.url);
}
},
methods: {
toggleConnection() {
// If it is connecting:
if (!this.connectionState) return this.connect();
// Otherwise, it's disconnecting.
else return this.disconnect();
},
connect() {
this.communication.log = [
{
payload: `Connecting to ${this.url}...`,
source: "info",
color: "var(--ac-color)"
}
];
try {
this.socket = new WebSocket(this.url);
this.socket.onopen = event => {
this.connectionState = true;
this.communication.log = [
{
payload: `Connected to ${this.url}.`,
source: "info",
color: "var(--ac-color)",
ts: new Date().toLocaleTimeString()
}
];
this.$toast.success("Connected", {
icon: "sync"
});
};
this.socket.onerror = event => {
this.handleError();
};
this.socket.onclose = event => {
this.connectionState = false;
this.communication.log.push({
payload: `Disconnected from ${this.url}.`,
source: "info",
color: "#ff5555",
ts: new Date().toLocaleTimeString()
});
this.$toast.error("Disconnected", {
icon: "sync_disabled"
});
};
this.socket.onmessage = event => {
this.communication.log.push({
payload: event.data,
source: "server",
ts: new Date().toLocaleTimeString()
});
};
} catch (ex) {
this.handleError(ex);
this.$toast.error("Something went wrong!", {
icon: "error"
});
}
},
disconnect() {
if (this.socket != null) this.socket.close();
},
handleError(error) {
this.disconnect();
this.connectionState = false;
this.communication.log.push({
payload: `An error has occurred.`,
source: "info",
color: "#ff5555",
ts: new Date().toLocaleTimeString()
});
if (error != null)
this.communication.log.push({
payload: error,
source: "info",
color: "#ff5555",
ts: new Date().toLocaleTimeString()
});
},
sendMessage() {
const message = this.communication.input;
this.socket.send(message);
this.communication.log.push({
payload: message,
source: "client",
ts: new Date().toLocaleTimeString()
});
this.communication.input = "";
},
collapse({ target }) {
const el = target.parentNode.className;
document.getElementsByClassName(el)[0].classList.toggle("hidden");
},
getSourcePrefix(source) {
const sourceEmojis = {
// Source used for info messages.
info: "\t [INFO]:\t",
// Source used for client to server messages.
client: "\t👽 [SENT]:\t",
// Source used for server to client messages.
server: "\t📥 [RECEIVED]:\t"
};
if (Object.keys(sourceEmojis).includes(source))
return sourceEmojis[source];
return "";
}
},
updated: function() {
this.$nextTick(function() {
var divLog = document.getElementById("log");
divLog.scrollBy(0, divLog.scrollHeight + 100);
});
}
};
</script>

View File

@@ -1,4 +1,4 @@
import Vue from 'vue';
import VTooltip from 'v-tooltip';
import Vue from "vue";
import VTooltip from "v-tooltip";
Vue.use(VTooltip);

View File

@@ -1,7 +1,5 @@
import VuexPersistence from "vuex-persist";
export default ({
store
}) => {
export default ({ store }) => {
new VuexPersistence().plugin(store);
}
};

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Capa_1"
x="0px"
y="0px"
viewBox="0 0 612.001 612.001"
style="enable-background:new 0 0 612.001 612.001;"
xml:space="preserve"
width="512px"
height="512px"
class=""
sodipodi:docname="logo.svg"
inkscape:version="0.92.4 (f8dce91, 2019-08-02)"><metadata
id="metadata13"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs11" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1533"
inkscape:window-height="845"
id="namedview9"
showgrid="false"
inkscape:zoom="0.921875"
inkscape:cx="380.48543"
inkscape:cy="276.92414"
inkscape:window-x="67"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="Capa_1" /> <g
id="g3826"
transform="translate(-516.40798,-163.88978)"><circle
transform="scale(1,-1)"
style="stroke-width:1.19531453"
r="178.70923"
cy="-501.55591"
cx="822.40845"
id="circle3814" /><g
id="g3820"
transform="translate(516.40798,163.89028)"><g
id="g3818"><path
id="path3816"
data-old_color="#202124"
class="active-path"
data-original="#202124"
d="M 64.601,236.822 C 64.601,394.256 192.786,612 306.001,612 412.582,612 547.4,394.256 547.4,236.822 547.4,79.388 439.322,0 306,0 172.678,0 64.601,79.388 64.601,236.822 Z m 304.12,116.415 c 29.475,-29.475 70.598,-40.195 108.552,-32.173 8.021,37.954 -2.698,79.077 -32.173,108.552 -29.475,29.475 -70.598,40.195 -108.552,32.173 -8.022,-37.955 2.698,-79.078 32.173,-108.552 z M 134.727,321.063 c 37.954,-8.021 79.077,2.698 108.552,32.173 29.475,29.475 40.195,70.598 32.173,108.552 -37.954,8.021 -79.077,-2.698 -108.552,-32.173 -29.475,-29.476 -40.194,-70.598 -32.173,-108.552 z"
inkscape:connector-curvature="0"
style="fill:#50fa7b" /></g></g></g></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -13,10 +13,10 @@
id="Layer_1"
x="0px"
y="0px"
viewBox="0 0 20 20"
viewBox="0 0 24 24"
xml:space="preserve"
width="20"
height="20"
width="24"
height="24"
sodipodi:docname="github.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)"><metadata
id="metadata13"><rdf:RDF><cc:Work
@@ -59,4 +59,4 @@
id="path6"
inkscape:connector-curvature="0"
style="fill:#fff" />
</svg>
</svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

74
static/icons/graphql.svg Normal file
View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 400 400">
<g>
<g>
<g>
<rect x="122" y="-0.4" transform="matrix(-0.866 -0.5 0.5 -0.866 163.3196 363.3136)" fill="#FFFFFF" width="16.6"
height="320.3"/>
</g>
</g>
<g>
<g>
<rect x="39.8" y="272.2" fill="#FFFFFF" width="320.3" height="16.6"/>
</g>
</g>
<g>
<g>
<rect x="37.9" y="312.2" transform="matrix(-0.866 -0.5 0.5 -0.866 83.0693 663.3409)" fill="#FFFFFF" width="185"
height="16.6"/>
</g>
</g>
<g>
<g>
<rect x="177.1" y="71.1" transform="matrix(-0.866 -0.5 0.5 -0.866 463.3409 283.0693)" fill="#FFFFFF" width="185"
height="16.6"/>
</g>
</g>
<g>
<g>
<rect x="122.1" y="-13" transform="matrix(-0.5 -0.866 0.866 -0.5 126.7903 232.1221)" fill="#FFFFFF" width="16.6"
height="185"/>
</g>
</g>
<g>
<g>
<rect x="109.6" y="151.6" transform="matrix(-0.5 -0.866 0.866 -0.5 266.0828 473.3766)" fill="#FFFFFF"
width="320.3" height="16.6"/>
</g>
</g>
<g>
<g>
<rect x="52.5" y="107.5" fill="#FFFFFF" width="16.6" height="185"/>
</g>
</g>
<g>s
<g>
<rect x="330.9" y="107.5" fill="#FFFFFF" width="16.6" height="185"/>
</g>
</g>
<g>
<g>
<rect x="262.4" y="240.1" transform="matrix(-0.5 -0.866 0.866 -0.5 126.7953 714.2875)" fill="#FFFFFF"
width="14.5" height="160.9"/>
</g>
</g>
<path fill="#FFFFFF" d="M369.5,297.9c-9.6,16.7-31,22.4-47.7,12.8c-16.7-9.6-22.4-31-12.8-47.7c9.6-16.7,31-22.4,47.7-12.8
C373.5,259.9,379.2,281.2,369.5,297.9"/>
<path fill="#FFFFFF" d="M90.9,137c-9.6,16.7-31,22.4-47.7,12.8c-16.7-9.6-22.4-31-12.8-47.7c9.6-16.7,31-22.4,47.7-12.8
C94.8,99,100.5,120.3,90.9,137"/>
<path fill="#FFFFFF" d="M30.5,297.9c-9.6-16.7-3.9-38,12.8-47.7c16.7-9.6,38-3.9,47.7,12.8c9.6,16.7,3.9,38-12.8,47.7
C61.4,320.3,40.1,314.6,30.5,297.9"/>
<path fill="#FFFFFF" d="M309.1,137c-9.6-16.7-3.9-38,12.8-47.7c16.7-9.6,38-3.9,47.7,12.8c9.6,16.7,3.9,38-12.8,47.7
C340.1,159.4,318.7,153.7,309.1,137"/>
<path fill="#FFFFFF" d="M200,395.8c-19.3,0-34.9-15.6-34.9-34.9c0-19.3,15.6-34.9,34.9-34.9c19.3,0,34.9,15.6,34.9,34.9
C234.9,380.1,219.3,395.8,200,395.8"/>
<path fill="#FFFFFF" d="M200,74c-19.3,0-34.9-15.6-34.9-34.9c0-19.3,15.6-34.9,34.9-34.9c19.3,0,34.9,15.6,34.9,34.9
C234.9,58.4,219.3,74,200,74"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full" width="1952" height="734.935" viewBox="0 0 1952.00 734.93" enable-background="new 0 0 1952.00 734.93" xml:space="preserve">
<g>
<path fill="#121212" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 1436.62,603.304L 1493.01,460.705L 1655.83,460.705L 1578.56,244.39L 1675.2,0.000528336L 1952,734.933L 1747.87,734.933L 1700.57,603.304L 1436.62,603.304 Z "/>
<path fill="#5A0FC8" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 1262.47,734.935L 1558.79,0.00156593L 1362.34,0.0025425L 1159.64,474.933L 1015.5,0.00351906L 864.499,0.00351906L 709.731,474.933L 600.585,258.517L 501.812,562.819L 602.096,734.935L 795.427,734.935L 935.284,309.025L 1068.63,734.935L 1262.47,734.935 Z "/>
<path fill="#121212" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 186.476,482.643L 307.479,482.643C 344.133,482.643 376.772,478.552 405.396,470.37L 436.689,373.962L 524.148,104.516C 517.484,93.9535 509.876,83.9667 501.324,74.5569C 456.419,24.852 390.719,0.000406265 304.222,0.000406265L -3.8147e-006,0.000406265L -3.8147e-006,734.933L 186.476,734.933L 186.476,482.643 Z M 346.642,169.079C 364.182,186.732 372.951,210.355 372.951,239.95C 372.951,269.772 365.238,293.424 349.813,310.906C 332.903,330.331 301.766,340.043 256.404,340.043L 186.476,340.043L 186.476,142.598L 256.918,142.598C 299.195,142.598 329.103,151.425 346.642,169.079 Z "/>
</g>
</svg>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 154 KiB

BIN
static/logo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -1,20 +1,18 @@
import Vuex from 'vuex';
import state from './state';
import VuexPersist from 'vuex-persist'
import Vuex from "vuex";
import state from "./state";
import VuexPersist from "vuex-persist";
export default {
install(Vue) {
Vue.use(Vuex);
const vuexLocalStorage = new VuexPersist({
key: 'vuex',
key: "vuex",
storage: window.localStorage,
reducer: ({
...request
}) => ({
reducer: ({ ...request }) => ({
...request
})
})
});
const store = new Vuex.Store({
state,
@@ -22,5 +20,5 @@ export default {
});
Vue.prototype.$store = store;
},
}
};

View File

@@ -1,53 +1,89 @@
export default {
setState(state, object) {
state.request[object.attribute] = object.value
setState({ request }, { attribute, value }) {
request[attribute] = value;
},
addHeaders(state, value) {
state.request.headers.push(value);
setGQLState({ gql }, { attribute, value }) {
gql[attribute] = value;
},
removeHeaders(state, index) {
state.request.headers.splice(index, 1)
addGQLHeader({ gql }, object) {
gql.headers.push(object);
},
setKeyHeader(state, object) {
state.request.headers[object.index].key = object.value
removeGQLHeader({ gql }, index) {
gql.headers.splice(index, 1);
},
setValueHeader(state, object) {
state.request.headers[object.index].value = object.value
setGQLHeaderKey({ gql }, { index, value }) {
gql.headers[index].key = value;
},
addParams(state, value) {
state.request.params.push(value);
setGQLHeaderValue({ gql }, { index, value }) {
gql.headers[index].value = value;
},
removeParams(state, index) {
state.request.params.splice(index, 1)
addGQLVariable({ gql }, object) {
gql.variables.push(object);
},
setKeyParams(state, object) {
state.request.params[object.index].key = object.value
removeGQLVariable({ gql }, index) {
gql.variables.splice(index, 1);
},
setValueParams(state, object) {
state.request.params[object.index].value = object.value
setGQLVariableKey({ gql }, { index, value }) {
gql.variables[index].key = value;
},
addBodyParams(state, value) {
state.request.bodyParams.push(value);
setGQLVariableValue({ gql }, { index, value }) {
gql.variables[index].value = value;
},
removeBodyParams(state, index) {
state.request.bodyParams.splice(index, 1)
addHeaders({ request }, value) {
request.headers.push(value);
},
setKeyBodyParams(state, object) {
state.request.bodyParams[object.index].key = object.value
removeHeaders({ request }, index) {
request.headers.splice(index, 1);
},
setValueBodyParams(state, object) {
state.request.bodyParams[object.index].value = object.value
setKeyHeader({ request }, { index, value }) {
request.headers[index].key = value;
},
setValueHeader({ request }, { index, value }) {
request.headers[index].value = value;
},
addParams({ request }, value) {
request.params.push(value);
},
removeParams({ request }, index) {
request.params.splice(index, 1);
},
setKeyParams({ request }, { index, value }) {
request.params[index].key = value;
},
setValueParams({ request }, { index, value }) {
request.params[index].value = value;
},
addBodyParams({ request }, value) {
request.bodyParams.push(value);
},
removeBodyParams({ request }, index) {
request.bodyParams.splice(index, 1);
},
setKeyBodyParams({ request }, { index, value }) {
request.bodyParams[index].key = value;
},
setValueBodyParams({ request }, { index, value }) {
request.bodyParams[index].value = value;
}
};

View File

@@ -1,4 +1,4 @@
import Vue from 'vue'
import Vue from "vue";
export const SETTINGS_KEYS = [
/**
@@ -26,6 +26,11 @@ export const SETTINGS_KEYS = [
*/
"THEME_COLOR_VIBRANT",
/**
* The Ace editor theme
*/
"THEME_ACE_EDITOR",
/**
* Normally, section frames are multicolored in the UI
* to emphasise the different sections.
@@ -56,29 +61,39 @@ export const SETTINGS_KEYS = [
export const state = () => ({
settings: {},
collections: [{
name: 'My First Collection',
folders: [],
requests: [],
}],
collections: [
{
name: "My Collection",
folders: [],
requests: []
}
],
selectedRequest: {},
editingRequest: {},
editingRequest: {}
});
export const mutations = {
applySetting(state, setting) {
if (setting == null || !(setting instanceof Array) || setting.length !== 2)
throw new Error("You must provide a setting (array in the form [key, value])");
applySetting({ settings }, setting) {
if (
setting == null ||
!(setting instanceof Array) ||
setting.length !== 2
) {
throw new Error(
"You must provide a setting (array in the form [key, value])"
);
}
const [key, value] = setting;
// Do not just remove this check.
// Add your settings key to the SETTINGS_KEYS array at the
// top of the file.
// This is to ensure that application settings remain documented.
if (!SETTINGS_KEYS.includes(key)) throw new Error("The settings structure does not include the key " + key);
if (!SETTINGS_KEYS.includes(key)) {
throw new Error(`The settings structure does not include the key ${key}`);
}
state.settings[key] = value;
settings[key] = value;
},
replaceCollections(state, collections) {
@@ -95,147 +110,160 @@ export const mutations = {
}
},
addNewCollection(state, collection) {
state.collections.push({
name: '',
addNewCollection({ collections }, collection) {
collections.push({
name: "",
folders: [],
requests: [],
...collection,
})
},
removeCollection(state, payload) {
const {
collectionIndex
} = payload;
state.collections.splice(collectionIndex, 1)
},
editCollection(state, payload) {
const {
collection,
collectionIndex
} = payload
state.collections[collectionIndex] = collection
},
addNewFolder(state, payload) {
const {
collectionIndex,
folder
} = payload;
state.collections[collectionIndex].folders.push({
name: '',
requests: [],
...folder,
...collection
});
},
editFolder(state, payload) {
const {
collectionIndex,
folder,
folderIndex
} = payload;
Vue.set(state.collections[collectionIndex].folders, folderIndex, folder)
removeCollection({ collections }, payload) {
const { collectionIndex } = payload;
collections.splice(collectionIndex, 1);
},
removeFolder(state, payload) {
const {
collectionIndex,
folderIndex
} = payload;
state.collections[collectionIndex].folders.splice(folderIndex, 1)
editCollection({ collections }, payload) {
const { collection, collectionIndex } = payload;
collections[collectionIndex] = collection;
},
addRequest(state, payload) {
const {
request
} = payload;
addNewFolder({ collections }, payload) {
const { collectionIndex, folder } = payload;
collections[collectionIndex].folders.push({
name: "",
requests: [],
...folder
});
},
editFolder({ collections }, payload) {
const { collectionIndex, folder, folderIndex } = payload;
Vue.set(collections[collectionIndex].folders, folderIndex, folder);
},
removeFolder({ collections }, payload) {
const { collectionIndex, folderIndex } = payload;
collections[collectionIndex].folders.splice(folderIndex, 1);
},
addRequest({ collections }, payload) {
const { request } = payload;
// Request that is directly attached to collection
if (request.folder === -1) {
state.collections[request.collection].requests.push(request);
return
collections[request.collection].requests.push(request);
return;
}
state.collections[request.collection].folders[request.folder].requests.push(request);
collections[request.collection].folders[request.folder].requests.push(
request
);
},
editRequest(state, payload) {
editRequest({ collections }, payload) {
const {
requestOld,
requestOldCollectionIndex,
requestOldFolderIndex,
requestOldIndex,
requestNew,
requestNewCollectionIndex,
requestNewFolderIndex,
} = payload
requestNewFolderIndex
} = payload;
const changedCollection = requestOldCollectionIndex !== requestNewCollectionIndex
const changedFolder = requestOldFolderIndex !== requestNewFolderIndex
const changedPlace = changedCollection || changedFolder
const changedCollection =
requestOldCollectionIndex !== requestNewCollectionIndex;
const changedFolder = requestOldFolderIndex !== requestNewFolderIndex;
const changedPlace = changedCollection || changedFolder;
// set new request
if (requestNewFolderIndex !== undefined)
Vue.set(state.collections[requestNewCollectionIndex].folders[requestNewFolderIndex].requests, requestOldIndex, requestNew)
else
Vue.set(state.collections[requestNewCollectionIndex].requests, requestOldIndex, requestNew)
if (requestNewFolderIndex !== undefined) {
Vue.set(
collections[requestNewCollectionIndex].folders[requestNewFolderIndex]
.requests,
requestOldIndex,
requestNew
);
} else {
Vue.set(
collections[requestNewCollectionIndex].requests,
requestOldIndex,
requestNew
);
}
// remove old request
if (changedPlace) {
if (requestOldFolderIndex !== undefined)
state.collections[requestOldCollectionIndex].folders[requestOldFolderIndex].requests.splice(requestOldIndex, 1)
else
state.collections[requestOldCollectionIndex].requests.splice(requestOldIndex, 1)
if (requestOldFolderIndex !== undefined) {
collections[requestOldCollectionIndex].folders[
requestOldFolderIndex
].requests.splice(requestOldIndex, 1);
} else {
collections[requestOldCollectionIndex].requests.splice(
requestOldIndex,
1
);
}
}
},
saveRequestAs(state, payload) {
const {
request,
collectionIndex,
folderIndex,
requestIndex,
} = payload
saveRequestAs({ collections }, payload) {
const { request, collectionIndex, folderIndex, requestIndex } = payload;
const specifiedCollection = collectionIndex !== undefined
const specifiedFolder = folderIndex !== undefined
const specifiedRequest = requestIndex !== undefined
const specifiedCollection = collectionIndex !== undefined;
const specifiedFolder = folderIndex !== undefined;
const specifiedRequest = requestIndex !== undefined;
if (specifiedCollection && specifiedFolder && specifiedRequest)
Vue.set(state.collections[collectionIndex].folders[folderIndex].requests, requestIndex, request)
else if (specifiedCollection && specifiedFolder && !specifiedRequest) {
const requests = state.collections[collectionIndex].folders[folderIndex].requests
if (specifiedCollection && specifiedFolder && specifiedRequest) {
Vue.set(
collections[collectionIndex].folders[folderIndex].requests,
requestIndex,
request
);
} else if (specifiedCollection && specifiedFolder && !specifiedRequest) {
const requests =
collections[collectionIndex].folders[folderIndex].requests;
const lastRequestIndex = requests.length - 1;
Vue.set(requests, lastRequestIndex + 1, request)
Vue.set(requests, lastRequestIndex + 1, request);
} else if (specifiedCollection && !specifiedFolder && specifiedRequest) {
const requests = state.collections[collectionIndex].requests
Vue.set(requests, requestIndex, request)
const requests = collections[collectionIndex].requests;
Vue.set(requests, requestIndex, request);
} else if (specifiedCollection && !specifiedFolder && !specifiedRequest) {
const requests = state.collections[collectionIndex].requests
const requests = collections[collectionIndex].requests;
const lastRequestIndex = requests.length - 1;
Vue.set(requests, lastRequestIndex + 1, request)
Vue.set(requests, lastRequestIndex + 1, request);
}
},
saveRequest(state, payload) {
const {
request
} = payload;
saveRequest({ collections }, payload) {
const { request } = payload;
// Remove the old request from collection
if (request.hasOwnProperty('oldCollection') && request.oldCollection > -1) {
const folder = request.hasOwnProperty('oldFolder') && request.oldFolder >= -1 ? request.oldFolder : request.folder;
if (request.hasOwnProperty("oldCollection") && request.oldCollection > -1) {
const folder =
request.hasOwnProperty("oldFolder") && request.oldFolder >= -1
? request.oldFolder
: request.folder;
if (folder > -1) {
state.collections[request.oldCollection].folders[folder].requests.splice(request.requestIndex, 1)
collections[request.oldCollection].folders[folder].requests.splice(
request.requestIndex,
1
);
} else {
state.collections[request.oldCollection].requests.splice(request.requestIndex, 1)
collections[request.oldCollection].requests.splice(
request.requestIndex,
1
);
}
} else if (request.hasOwnProperty('oldFolder') && request.oldFolder !== -1) {
state.collections[request.collection].folders[folder].requests.splice(request.requestIndex, 1)
} else if (
request.hasOwnProperty("oldFolder") &&
request.oldFolder !== -1
) {
collections[request.collection].folders[folder].requests.splice(
request.requestIndex,
1
);
}
delete request.oldCollection;
@@ -243,31 +271,37 @@ export const mutations = {
// Request that is directly attached to collection
if (request.folder === -1) {
Vue.set(state.collections[request.collection].requests, request.requestIndex, request)
return
Vue.set(
collections[request.collection].requests,
request.requestIndex,
request
);
return;
}
Vue.set(state.collections[request.collection].folders[request.folder].requests, request.requestIndex, request)
Vue.set(
collections[request.collection].folders[request.folder].requests,
request.requestIndex,
request
);
},
removeRequest(state, payload) {
const {
collectionIndex,
folderIndex,
requestIndex
} = payload;
removeRequest({ collections }, payload) {
const { collectionIndex, folderIndex, requestIndex } = payload;
// Request that is directly attached to collection
if (folderIndex === -1) {
state.collections[collectionIndex].requests.splice(requestIndex, 1)
return
collections[collectionIndex].requests.splice(requestIndex, 1);
return;
}
state.collections[collectionIndex].folders[folderIndex].requests.splice(requestIndex, 1)
},
selectRequest(state, payload) {
state.selectedRequest = Object.assign({}, payload.request);
collections[collectionIndex].folders[folderIndex].requests.splice(
requestIndex,
1
);
},
selectRequest(state, { request }) {
state.selectedRequest = Object.assign({}, request);
}
};

View File

@@ -1,20 +1,26 @@
export default () => ({
request: {
method: 'GET',
url: 'https://reqres.in',
path: '/api/users',
label: '',
auth: 'None',
httpUser: '',
httpPassword: '',
passwordFieldType: 'password',
bearerToken: '',
method: "GET",
url: "https://reqres.in",
path: "/api/users",
label: "",
auth: "None",
httpUser: "",
httpPassword: "",
passwordFieldType: "password",
bearerToken: "",
headers: [],
params: [],
bodyParams: [],
rawParams: '',
rawParams: "",
rawInput: false,
requestType: 'JavaScript XHR',
contentType: '',
requestType: "",
contentType: ""
},
gql: {
url: "https://rickandmortyapi.com/graphql",
headers: [],
variables: [],
query: ""
}
});

View File

@@ -1,9 +1,9 @@
describe('Methods', () => {
const methods = [ 'POST', 'HEAD', 'POST', 'PUT', 'DELETE','OPTIONS', 'PATCH']
methods.forEach(method => {
methods.forEach((method) => {
it(`Change the default method GET to ${method} with url query`, () => {
cy.visit(`/?method=${method}`)
.get('#method').contains(method)
.get('#method').should('have.value', method)
})
})
})
@@ -11,8 +11,8 @@ describe('Methods', () => {
describe('Url and path', () => {
it('Change default url with query and reset default path to empty string and make a request to cat api', () => {
cy.seedAndVisit('catapi', '/?url=https://api.thecatapi.com&path=')
.get('#url').then(el => expect(el.val() === 'https://api.thecatapi.com').to.equal(true))
.get("#path").then(el => expect(el.val() === '').to.equal(true))
.get('#url').then((el) => expect(el.val() === 'https://api.thecatapi.com').to.equal(true))
.get("#path").then((el) => expect(el.val() === '').to.equal(true))
.get('#response-details-wrapper').should($wrapper => {
expect($wrapper).to.contain('FAKE Cat API')
})
@@ -21,19 +21,19 @@ describe('Url and path', () => {
describe('Authentication', () => {
it(`Change default auth 'None' to 'Basic' and set httpUser and httpPassword with url query`, () => {
cy.visit(`?&auth=Basic&httpUser=foo&httpPassword=bar`, { retryOnStatusCodeFailure: true })
cy.visit(`?&auth=Basic Auth&httpUser=foo&httpPassword=bar`, { retryOnStatusCodeFailure: true })
.get('#authentication').contains('Authentication').click()
.then(() => {
.then(() => {
cy.get('input[name="http_basic_user"]', { timeout: 500 })
.invoke('val')
.then(user => {
.then((user) => {
expect(user === 'foo').to.equal(true)
cy.log('Success! user === foo')
})
cy.get('input[name="http_basic_passwd"]')
.invoke('val')
.then(user => {
.then((user) => {
expect(user === 'bar').to.equal(true)
cy.log('Success! password === bar')
})
@@ -48,7 +48,7 @@ describe('Authentication', () => {
.then(() => {
cy.get('input[name="bearer_token"]', { timeout: 500 })
.invoke('val')
.then(tkn => {
.then((tkn) => {
expect(tkn === base64Tkn).to.equal(true)
cy.log(`Success! input[name="bearer_token"] === ${base64Tkn}`)
})