Merge branch 'master' of https://github.com/liyasthomas/postwoman
This commit is contained in:
@@ -326,7 +326,7 @@ docker run -p 3000:3000 postwoman:latest
|
|||||||
|
|
||||||
1. [Clone this repo](https://help.github.com/en/articles/cloning-a-repository) with git.
|
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 `hoppscotch`).
|
2. Install dependencies by running `npm install` within the directory that you cloned (probably `hoppscotch`).
|
||||||
3. Build the release files with `npm run build`.
|
3. Build the release files with `npm run generate`.
|
||||||
4. Find the built project in `./dist`.
|
4. Find the built project in `./dist`.
|
||||||
|
|
||||||
## **Contributing**
|
## **Contributing**
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ $responsiveWidth: 768px;
|
|||||||
|
|
||||||
:root {
|
:root {
|
||||||
@apply antialiased;
|
@apply antialiased;
|
||||||
|
|
||||||
font-variant-ligatures: common-ligatures;
|
font-variant-ligatures: common-ligatures;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,6 +55,7 @@ body {
|
|||||||
@apply transition;
|
@apply transition;
|
||||||
@apply ease-in-out;
|
@apply ease-in-out;
|
||||||
@apply duration-200;
|
@apply duration-200;
|
||||||
|
|
||||||
-webkit-tap-highlight-color: transparent;
|
-webkit-tap-highlight-color: transparent;
|
||||||
-webkit-touch-callout: none;
|
-webkit-touch-callout: none;
|
||||||
}
|
}
|
||||||
@@ -211,6 +213,7 @@ hr {
|
|||||||
.tooltip-arrow {
|
.tooltip-arrow {
|
||||||
@apply mt-0;
|
@apply mt-0;
|
||||||
@apply mb-0;
|
@apply mb-0;
|
||||||
|
|
||||||
border-width: 5px 5px 0 5px;
|
border-width: 5px 5px 0 5px;
|
||||||
border-left-color: transparent !important;
|
border-left-color: transparent !important;
|
||||||
border-right-color: transparent !important;
|
border-right-color: transparent !important;
|
||||||
@@ -226,6 +229,7 @@ hr {
|
|||||||
.tooltip-arrow {
|
.tooltip-arrow {
|
||||||
@apply mt-0;
|
@apply mt-0;
|
||||||
@apply mb-0;
|
@apply mb-0;
|
||||||
|
|
||||||
border-width: 0 5px 5px 5px;
|
border-width: 0 5px 5px 5px;
|
||||||
border-left-color: transparent !important;
|
border-left-color: transparent !important;
|
||||||
border-right-color: transparent !important;
|
border-right-color: transparent !important;
|
||||||
@@ -241,6 +245,7 @@ hr {
|
|||||||
.tooltip-arrow {
|
.tooltip-arrow {
|
||||||
@apply ml-0;
|
@apply ml-0;
|
||||||
@apply mr-0;
|
@apply mr-0;
|
||||||
|
|
||||||
border-width: 5px 5px 5px 0;
|
border-width: 5px 5px 5px 0;
|
||||||
border-left-color: transparent !important;
|
border-left-color: transparent !important;
|
||||||
border-top-color: transparent !important;
|
border-top-color: transparent !important;
|
||||||
@@ -256,6 +261,7 @@ hr {
|
|||||||
.tooltip-arrow {
|
.tooltip-arrow {
|
||||||
@apply ml-0;
|
@apply ml-0;
|
||||||
@apply mr-0;
|
@apply mr-0;
|
||||||
|
|
||||||
border-width: 5px 0 5px 5px;
|
border-width: 5px 0 5px 5px;
|
||||||
border-top-color: transparent !important;
|
border-top-color: transparent !important;
|
||||||
border-right-color: transparent !important;
|
border-right-color: transparent !important;
|
||||||
@@ -278,11 +284,14 @@ hr {
|
|||||||
@apply rounded-lg;
|
@apply rounded-lg;
|
||||||
@apply overflow-auto;
|
@apply overflow-auto;
|
||||||
@apply shadow-lg;
|
@apply shadow-lg;
|
||||||
|
|
||||||
max-height: 256px;
|
max-height: 256px;
|
||||||
|
|
||||||
button {
|
button {
|
||||||
@apply flex-1;
|
@apply flex-1;
|
||||||
@apply m-0;
|
@apply m-0;
|
||||||
|
@apply justify-start;
|
||||||
|
@apply text-left;
|
||||||
}
|
}
|
||||||
|
|
||||||
div {
|
div {
|
||||||
@@ -290,11 +299,6 @@ hr {
|
|||||||
@apply items-stretch;
|
@apply items-stretch;
|
||||||
@apply flex-col;
|
@apply flex-col;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
|
||||||
@apply justify-start;
|
|
||||||
@apply text-left;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.popover-arrow {
|
.popover-arrow {
|
||||||
@@ -362,6 +366,7 @@ button {
|
|||||||
@apply text-actColor;
|
@apply text-actColor;
|
||||||
@apply fill-current;
|
@apply fill-current;
|
||||||
@apply outline-none;
|
@apply outline-none;
|
||||||
|
|
||||||
box-shadow: inset 0 0 0 2px var(--fg-color);
|
box-shadow: inset 0 0 0 2px var(--fg-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,6 +428,7 @@ button {
|
|||||||
@apply tracking-normal;
|
@apply tracking-normal;
|
||||||
@apply whitespace-no-wrap;
|
@apply whitespace-no-wrap;
|
||||||
@apply antialiased;
|
@apply antialiased;
|
||||||
|
|
||||||
word-wrap: normal;
|
word-wrap: normal;
|
||||||
direction: ltr;
|
direction: ltr;
|
||||||
text-rendering: optimizeLegibility;
|
text-rendering: optimizeLegibility;
|
||||||
@@ -481,6 +487,7 @@ code {
|
|||||||
@apply select-text;
|
@apply select-text;
|
||||||
@apply resize-y;
|
@apply resize-y;
|
||||||
@apply outline-none;
|
@apply outline-none;
|
||||||
|
|
||||||
width: calc(100% - 16px);
|
width: calc(100% - 16px);
|
||||||
|
|
||||||
&:not([readonly]):not(.ace_editor):hover,
|
&:not([readonly]):not(.ace_editor):hover,
|
||||||
@@ -493,6 +500,7 @@ code {
|
|||||||
.method {
|
.method {
|
||||||
@apply cursor-pointer;
|
@apply cursor-pointer;
|
||||||
@apply uppercase;
|
@apply uppercase;
|
||||||
|
|
||||||
min-width: 128px;
|
min-width: 128px;
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
@@ -530,11 +538,12 @@ pre {
|
|||||||
@apply w-full;
|
@apply w-full;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:after {
|
&::after {
|
||||||
@apply inline-block;
|
@apply inline-block;
|
||||||
@apply absolute;
|
@apply absolute;
|
||||||
@apply pointer-events-none;
|
@apply pointer-events-none;
|
||||||
@apply font-icon;
|
@apply font-icon;
|
||||||
|
|
||||||
content: "\e313";
|
content: "\e313";
|
||||||
top: 16px;
|
top: 16px;
|
||||||
right: 16px;
|
right: 16px;
|
||||||
@@ -544,6 +553,7 @@ pre {
|
|||||||
select {
|
select {
|
||||||
@apply cursor-pointer;
|
@apply cursor-pointer;
|
||||||
@apply appearance-none;
|
@apply appearance-none;
|
||||||
|
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
|
||||||
&::-ms-expand {
|
&::-ms-expand {
|
||||||
@@ -563,7 +573,7 @@ input[type="checkbox"] {
|
|||||||
@apply align-middle;
|
@apply align-middle;
|
||||||
@apply cursor-pointer;
|
@apply cursor-pointer;
|
||||||
|
|
||||||
&:before {
|
&::before {
|
||||||
@apply border;
|
@apply border;
|
||||||
@apply border-fgColor;
|
@apply border-fgColor;
|
||||||
@apply rounded-lg;
|
@apply rounded-lg;
|
||||||
@@ -574,6 +584,7 @@ input[type="checkbox"] {
|
|||||||
@apply transition;
|
@apply transition;
|
||||||
@apply ease-in-out;
|
@apply ease-in-out;
|
||||||
@apply duration-200;
|
@apply duration-200;
|
||||||
|
|
||||||
content: "\2714";
|
content: "\2714";
|
||||||
height: 16px;
|
height: 16px;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
@@ -581,7 +592,7 @@ input[type="checkbox"] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:checked + label:before {
|
&:checked + label::before {
|
||||||
@apply bg-acColor;
|
@apply bg-acColor;
|
||||||
@apply border-acColor;
|
@apply border-acColor;
|
||||||
@apply text-actColor;
|
@apply text-actColor;
|
||||||
@@ -616,6 +627,7 @@ ol {
|
|||||||
@apply flex;
|
@apply flex;
|
||||||
@apply p-0;
|
@apply p-0;
|
||||||
@apply list-none;
|
@apply list-none;
|
||||||
|
|
||||||
margin: 4px 0 4px;
|
margin: 4px 0 4px;
|
||||||
|
|
||||||
ul,
|
ul,
|
||||||
@@ -684,6 +696,7 @@ ol li {
|
|||||||
textarea {
|
textarea {
|
||||||
@apply m-0;
|
@apply m-0;
|
||||||
@apply w-full;
|
@apply w-full;
|
||||||
|
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -708,6 +721,7 @@ ol li {
|
|||||||
@apply ease-in-out;
|
@apply ease-in-out;
|
||||||
@apply duration-200;
|
@apply duration-200;
|
||||||
@apply shadow-lg;
|
@apply shadow-lg;
|
||||||
|
|
||||||
bottom: 86px;
|
bottom: 86px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
z-index: 10001;
|
z-index: 10001;
|
||||||
@@ -753,6 +767,7 @@ section {
|
|||||||
@apply flex;
|
@apply flex;
|
||||||
@apply order-2;
|
@apply order-2;
|
||||||
@apply ml-4;
|
@apply ml-4;
|
||||||
|
|
||||||
width: 33%;
|
width: 33%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -807,15 +822,17 @@ section {
|
|||||||
@apply text-sm;
|
@apply text-sm;
|
||||||
@apply rounded-lg;
|
@apply rounded-lg;
|
||||||
@apply shadow-lg;
|
@apply shadow-lg;
|
||||||
|
|
||||||
padding: 16px !important;
|
padding: 16px !important;
|
||||||
|
|
||||||
.action {
|
.action {
|
||||||
@apply bg-gray-50;
|
@apply bg-gray-50;
|
||||||
@apply text-gray-900;
|
@apply text-gray-900;
|
||||||
@apply rounded-lg;
|
@apply rounded-lg;
|
||||||
|
@apply font-bold;
|
||||||
|
|
||||||
text-transform: none !important;
|
text-transform: none !important;
|
||||||
padding: 12px 16px !important;
|
padding: 12px 16px !important;
|
||||||
font-weight: 500 !important;
|
|
||||||
font-size: 16px !important;
|
font-size: 16px !important;
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
margin-left: 8px !important;
|
margin-left: 8px !important;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@mixin baseTheme {
|
@mixin baseTheme {
|
||||||
--font-body: "Poppins", "sans-serif";
|
--font-body: "Poppins", "sans-serif";
|
||||||
--font-mono: "Roboto Mono", "monoscpace";
|
--font-mono: "Roboto Mono", "monospace";
|
||||||
--font-icon: "Material Icons";
|
--font-icon: "Material Icons";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
type="text"
|
type="text"
|
||||||
v-model="name"
|
v-model="name"
|
||||||
:placeholder="$t('my_new_folder')"
|
:placeholder="$t('my_new_folder')"
|
||||||
@keyup.enter="addNewFolder"
|
@keyup.enter="addFolder"
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
<button class="icon" @click="hideModal">
|
<button class="icon" @click="hideModal">
|
||||||
{{ $t("cancel") }}
|
{{ $t("cancel") }}
|
||||||
</button>
|
</button>
|
||||||
<button class="icon primary" @click="addNewFolder">
|
<button class="icon primary" @click="addFolder">
|
||||||
{{ $t("save") }}
|
{{ $t("save") }}
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
@@ -52,7 +52,7 @@ export default {
|
|||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
show: Boolean,
|
show: Boolean,
|
||||||
collection: Object,
|
folder: Object,
|
||||||
collectionIndex: Number,
|
collectionIndex: Number,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@@ -61,14 +61,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
addNewFolder() {
|
|
||||||
this.$store.commit("postwoman/addNewFolder", {
|
|
||||||
folder: { name: this.$data.name },
|
|
||||||
collectionIndex: this.$props.collectionIndex,
|
|
||||||
})
|
|
||||||
this.hideModal()
|
|
||||||
this.syncCollections()
|
|
||||||
},
|
|
||||||
syncCollections() {
|
syncCollections() {
|
||||||
if (fb.currentUser !== null) {
|
if (fb.currentUser !== null) {
|
||||||
if (fb.currentSettings[0].value) {
|
if (fb.currentSettings[0].value) {
|
||||||
@@ -76,6 +68,14 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
addFolder() {
|
||||||
|
this.$store.commit("postwoman/addFolder", {
|
||||||
|
name: this.$data.name,
|
||||||
|
folder: this.$props.folder,
|
||||||
|
})
|
||||||
|
this.hideModal()
|
||||||
|
this.syncCollections()
|
||||||
|
},
|
||||||
hideModal() {
|
hideModal() {
|
||||||
this.$emit("hide-modal")
|
this.$emit("hide-modal")
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="row-wrapper">
|
<div
|
||||||
|
:class="['row-wrapper', dragging ? 'drop-zone' : '']"
|
||||||
|
@dragover.prevent
|
||||||
|
@drop.prevent="dropEvent"
|
||||||
|
@dragover="dragging = true"
|
||||||
|
@drop="dragging = false"
|
||||||
|
@dragleave="dragging = false"
|
||||||
|
@dragend="dragging = false"
|
||||||
|
>
|
||||||
<button class="icon" @click="toggleShowChildren">
|
<button class="icon" @click="toggleShowChildren">
|
||||||
<i class="material-icons" v-show="!showChildren && !isFiltered">arrow_right</i>
|
<i class="material-icons" v-show="!showChildren && !isFiltered">arrow_right</i>
|
||||||
<i class="material-icons" v-show="showChildren || isFiltered">arrow_drop_down</i>
|
<i class="material-icons" v-show="showChildren || isFiltered">arrow_drop_down</i>
|
||||||
@@ -22,7 +30,11 @@
|
|||||||
</button>
|
</button>
|
||||||
<template slot="popover">
|
<template slot="popover">
|
||||||
<div>
|
<div>
|
||||||
<button class="icon" @click="$emit('add-folder')" v-close-popover>
|
<button
|
||||||
|
class="icon"
|
||||||
|
@click="$emit('add-folder', { folder: collection })"
|
||||||
|
v-close-popover
|
||||||
|
>
|
||||||
<i class="material-icons">create_new_folder</i>
|
<i class="material-icons">create_new_folder</i>
|
||||||
<span>{{ $t("new_folder") }}</span>
|
<span>{{ $t("new_folder") }}</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -53,18 +65,16 @@
|
|||||||
>
|
>
|
||||||
<folder
|
<folder
|
||||||
:folder="folder"
|
:folder="folder"
|
||||||
:folderIndex="index"
|
:folder-index="index"
|
||||||
:collection-index="collectionIndex"
|
:collection-index="collectionIndex"
|
||||||
:doc="doc"
|
:doc="doc"
|
||||||
:isFiltered="isFiltered"
|
:isFiltered="isFiltered"
|
||||||
@edit-folder="editFolder(collectionIndex, folder, index)"
|
@add-folder="$emit('add-folder', $event)"
|
||||||
|
@edit-folder="$emit('edit-folder', $event)"
|
||||||
@edit-request="$emit('edit-request', $event)"
|
@edit-request="$emit('edit-request', $event)"
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li v-if="collection.folders.length === 0 && collection.requests.length === 0">
|
||||||
v-if="collection.folders.length === 0 && collection.requests.length === 0"
|
|
||||||
class="ml-8 border-l border-brdColor"
|
|
||||||
>
|
|
||||||
<label>{{ $t("collection_empty") }}</label>
|
<label>{{ $t("collection_empty") }}</label>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -78,16 +88,10 @@
|
|||||||
:request="request"
|
:request="request"
|
||||||
:collection-index="collectionIndex"
|
:collection-index="collectionIndex"
|
||||||
:folder-index="-1"
|
:folder-index="-1"
|
||||||
|
:folder-name="collection.name"
|
||||||
:request-index="index"
|
:request-index="index"
|
||||||
:doc="doc"
|
:doc="doc"
|
||||||
@edit-request="
|
@edit-request="$emit('edit-request', $event)"
|
||||||
$emit('edit-request', {
|
|
||||||
request,
|
|
||||||
collectionIndex,
|
|
||||||
folderIndex: undefined,
|
|
||||||
requestIndex: index,
|
|
||||||
})
|
|
||||||
"
|
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -111,6 +115,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showChildren: false,
|
showChildren: false,
|
||||||
|
dragging: false,
|
||||||
selectedFolder: {},
|
selectedFolder: {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -135,8 +140,22 @@ export default {
|
|||||||
})
|
})
|
||||||
this.syncCollections()
|
this.syncCollections()
|
||||||
},
|
},
|
||||||
editFolder(collectionIndex, folder, folderIndex) {
|
dropEvent({ dataTransfer }) {
|
||||||
this.$emit("edit-folder", { collectionIndex, folder, folderIndex })
|
this.dragging = !this.dragging
|
||||||
|
const oldCollectionIndex = dataTransfer.getData("oldCollectionIndex")
|
||||||
|
const oldFolderIndex = dataTransfer.getData("oldFolderIndex")
|
||||||
|
const oldFolderName = dataTransfer.getData("oldFolderName")
|
||||||
|
const requestIndex = dataTransfer.getData("requestIndex")
|
||||||
|
this.$store.commit("postwoman/moveRequest", {
|
||||||
|
oldCollectionIndex,
|
||||||
|
newCollectionIndex: this.$props.collectionIndex,
|
||||||
|
newFolderIndex: -1,
|
||||||
|
newFolderName: this.$props.collection.name,
|
||||||
|
oldFolderIndex,
|
||||||
|
oldFolderName,
|
||||||
|
requestIndex,
|
||||||
|
})
|
||||||
|
this.syncCollections()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ export default {
|
|||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
show: Boolean,
|
show: Boolean,
|
||||||
collection: Object,
|
|
||||||
collectionIndex: Number,
|
collectionIndex: Number,
|
||||||
folder: Object,
|
folder: Object,
|
||||||
folderIndex: Number,
|
folderIndex: Number,
|
||||||
@@ -70,6 +69,7 @@ export default {
|
|||||||
collectionIndex: this.$props.collectionIndex,
|
collectionIndex: this.$props.collectionIndex,
|
||||||
folder: { ...this.$props.folder, name: this.$data.name },
|
folder: { ...this.$props.folder, name: this.$data.name },
|
||||||
folderIndex: this.$props.folderIndex,
|
folderIndex: this.$props.folderIndex,
|
||||||
|
folderName: this.$props.folder.name,
|
||||||
})
|
})
|
||||||
this.hideModal()
|
this.hideModal()
|
||||||
this.syncCollections()
|
this.syncCollections()
|
||||||
|
|||||||
@@ -15,42 +15,14 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div slot="body">
|
<div slot="body">
|
||||||
<ul>
|
<label for="selectLabel">{{ $t("label") }}</label>
|
||||||
<li>
|
<input
|
||||||
<label for="selectLabel">{{ $t("label") }}</label>
|
type="text"
|
||||||
<input
|
id="selectLabel"
|
||||||
type="text"
|
v-model="requestUpdateData.name"
|
||||||
id="selectLabel"
|
@keyup.enter="saveRequest"
|
||||||
v-model="requestUpdateData.name"
|
:placeholder="request.name"
|
||||||
@keyup.enter="saveRequest"
|
/>
|
||||||
:placeholder="request.name"
|
|
||||||
/>
|
|
||||||
<label for="selectCollection">{{ $t("collection") }}</label>
|
|
||||||
<span class="select-wrapper">
|
|
||||||
<select type="text" id="selectCollection" v-model="requestUpdateData.collectionIndex">
|
|
||||||
<option :key="undefined" :value="undefined" hidden disabled selected>
|
|
||||||
{{ $t("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">{{ $t("folder") }}</label>
|
|
||||||
<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>
|
||||||
<div slot="footer">
|
<div slot="footer">
|
||||||
<div class="row-wrapper">
|
<div class="row-wrapper">
|
||||||
@@ -80,6 +52,7 @@ export default {
|
|||||||
show: Boolean,
|
show: Boolean,
|
||||||
collectionIndex: Number,
|
collectionIndex: Number,
|
||||||
folderIndex: Number,
|
folderIndex: Number,
|
||||||
|
folderName: String,
|
||||||
request: Object,
|
request: Object,
|
||||||
requestIndex: Number,
|
requestIndex: Number,
|
||||||
},
|
},
|
||||||
@@ -87,27 +60,9 @@ export default {
|
|||||||
return {
|
return {
|
||||||
requestUpdateData: {
|
requestUpdateData: {
|
||||||
name: undefined,
|
name: undefined,
|
||||||
collectionIndex: undefined,
|
|
||||||
folderIndex: undefined,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
"requestUpdateData.collectionIndex": function resetFolderIndex() {
|
|
||||||
// if user choosen some folder, than selected other collection, which doesn't have any folders
|
|
||||||
// than `requestUpdateData.folderIndex` won't be reseted
|
|
||||||
this.$data.requestUpdateData.folderIndex = undefined
|
|
||||||
},
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
folders() {
|
|
||||||
const userSelectedAnyCollection = this.$data.requestUpdateData.collectionIndex !== undefined
|
|
||||||
if (!userSelectedAnyCollection) return []
|
|
||||||
|
|
||||||
return this.$store.state.postwoman.collections[this.$data.requestUpdateData.collectionIndex]
|
|
||||||
.folders
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
syncCollections() {
|
syncCollections() {
|
||||||
if (fb.currentUser !== null) {
|
if (fb.currentUser !== null) {
|
||||||
@@ -117,26 +72,17 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
saveRequest() {
|
saveRequest() {
|
||||||
const userSelectedAnyCollection = this.$data.requestUpdateData.collectionIndex !== undefined
|
|
||||||
|
|
||||||
const requestUpdated = {
|
const requestUpdated = {
|
||||||
...this.$props.request,
|
...this.$props.request,
|
||||||
name: this.$data.requestUpdateData.name || this.$props.request.name,
|
name: this.$data.requestUpdateData.name || this.$props.request.name,
|
||||||
collection: userSelectedAnyCollection
|
|
||||||
? this.$data.requestUpdateData.collectionIndex
|
|
||||||
: this.$props.collectionIndex,
|
|
||||||
folder: this.$data.requestUpdateData.folderIndex,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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", {
|
this.$store.commit("postwoman/editRequest", {
|
||||||
requestOldCollectionIndex: this.$props.collectionIndex,
|
requestCollectionIndex: this.$props.collectionIndex,
|
||||||
requestOldFolderIndex: this.$props.folderIndex,
|
requestFolderName: this.$props.folderName,
|
||||||
requestOldIndex: this.$props.requestIndex,
|
requestFolderIndex: this.$props.folderIndex,
|
||||||
requestNew: requestUpdated,
|
requestNew: requestUpdated,
|
||||||
requestNewCollectionIndex: requestUpdated.collection,
|
requestIndex: this.$props.requestIndex,
|
||||||
requestNewFolderIndex: requestUpdated.folder,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
this.hideModal()
|
this.hideModal()
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="row-wrapper">
|
<div
|
||||||
|
:class="['row-wrapper', dragging ? 'drop-zone' : '']"
|
||||||
|
@dragover.prevent
|
||||||
|
@drop.prevent="dropEvent"
|
||||||
|
@dragover="dragging = true"
|
||||||
|
@drop="dragging = false"
|
||||||
|
@dragleave="dragging = false"
|
||||||
|
@dragend="dragging = false"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<button class="icon" @click="toggleShowChildren">
|
<button class="icon" @click="toggleShowChildren">
|
||||||
<i class="material-icons" v-show="!showChildren && !isFiltered">arrow_right</i>
|
<i class="material-icons" v-show="!showChildren && !isFiltered">arrow_right</i>
|
||||||
@@ -15,7 +23,17 @@
|
|||||||
</button>
|
</button>
|
||||||
<template slot="popover">
|
<template slot="popover">
|
||||||
<div>
|
<div>
|
||||||
<button class="icon" @click="editFolder" v-close-popover>
|
<button class="icon" @click="$emit('add-folder', { folder })" v-close-popover>
|
||||||
|
<i class="material-icons">create_new_folder</i>
|
||||||
|
<span>{{ $t("new_folder") }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
class="icon"
|
||||||
|
@click="$emit('edit-folder', { folder, folderIndex, collectionIndex })"
|
||||||
|
v-close-popover
|
||||||
|
>
|
||||||
<i class="material-icons">edit</i>
|
<i class="material-icons">edit</i>
|
||||||
<span>{{ $t("edit") }}</span>
|
<span>{{ $t("edit") }}</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -41,20 +59,24 @@
|
|||||||
:request="request"
|
:request="request"
|
||||||
:collection-index="collectionIndex"
|
:collection-index="collectionIndex"
|
||||||
:folder-index="folderIndex"
|
:folder-index="folderIndex"
|
||||||
|
:folder-name="folder.name"
|
||||||
:request-index="index"
|
:request-index="index"
|
||||||
:doc="doc"
|
:doc="doc"
|
||||||
@edit-request="
|
@edit-request="$emit('edit-request', $event)"
|
||||||
$emit('edit-request', {
|
|
||||||
request,
|
|
||||||
collectionIndex,
|
|
||||||
folderIndex,
|
|
||||||
requestIndex: index,
|
|
||||||
})
|
|
||||||
"
|
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="folder.requests.length === 0" class="flex ml-8 border-l border-brdColor">
|
</ul>
|
||||||
<label>{{ $t("folder_empty") }}</label>
|
<ul v-if="folder.folders && folder.folders.length" class="flex-col">
|
||||||
|
<li v-for="(subFolder, subFolderIndex) in folder.folders" :key="subFolder.name">
|
||||||
|
<folder
|
||||||
|
:folder="subFolder"
|
||||||
|
:folder-index="subFolderIndex"
|
||||||
|
:collection-index="collectionIndex"
|
||||||
|
:doc="doc"
|
||||||
|
@add-folder="$emit('add-folder', $event)"
|
||||||
|
@edit-folder="$emit('edit-folder', $event)"
|
||||||
|
@edit-request="$emit('edit-request', $event)"
|
||||||
|
/>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -67,16 +89,18 @@ import deleteIcon from "~/static/icons/delete-24px.svg?inline"
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { deleteIcon },
|
components: { deleteIcon },
|
||||||
|
name: "folder",
|
||||||
props: {
|
props: {
|
||||||
folder: Object,
|
folder: Object,
|
||||||
collectionIndex: Number,
|
|
||||||
folderIndex: Number,
|
folderIndex: Number,
|
||||||
|
collectionIndex: Number,
|
||||||
doc: Boolean,
|
doc: Boolean,
|
||||||
isFiltered: Boolean,
|
isFiltered: Boolean,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showChildren: false,
|
showChildren: false,
|
||||||
|
dragging: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -90,22 +114,35 @@ export default {
|
|||||||
toggleShowChildren() {
|
toggleShowChildren() {
|
||||||
this.showChildren = !this.showChildren
|
this.showChildren = !this.showChildren
|
||||||
},
|
},
|
||||||
selectRequest(request) {
|
|
||||||
this.$store.commit("postwoman/selectRequest", { request })
|
|
||||||
},
|
|
||||||
removeFolder() {
|
removeFolder() {
|
||||||
if (!confirm(this.$t("are_you_sure_remove_folder"))) return
|
if (!confirm(this.$t("are_you_sure_remove_folder"))) return
|
||||||
this.$store.commit("postwoman/removeFolder", {
|
this.$store.commit("postwoman/removeFolder", {
|
||||||
collectionIndex: this.collectionIndex,
|
collectionIndex: this.$props.collectionIndex,
|
||||||
folderIndex: this.folderIndex,
|
folderName: this.$props.folder.name,
|
||||||
|
folderIndex: this.$props.folderIndex,
|
||||||
})
|
})
|
||||||
this.syncCollections()
|
this.syncCollections()
|
||||||
this.$toast.error(this.$t("deleted"), {
|
this.$toast.error(this.$t("deleted"), {
|
||||||
icon: "delete",
|
icon: "delete",
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
editFolder() {
|
dropEvent({ dataTransfer }) {
|
||||||
this.$emit("edit-folder")
|
this.dragging = !this.dragging
|
||||||
|
const oldCollectionIndex = dataTransfer.getData("oldCollectionIndex")
|
||||||
|
const oldFolderIndex = dataTransfer.getData("oldFolderIndex")
|
||||||
|
const oldFolderName = dataTransfer.getData("oldFolderName")
|
||||||
|
const requestIndex = dataTransfer.getData("requestIndex")
|
||||||
|
|
||||||
|
this.$store.commit("postwoman/moveRequest", {
|
||||||
|
oldCollectionIndex,
|
||||||
|
newCollectionIndex: this.$props.collectionIndex,
|
||||||
|
newFolderIndex: this.$props.folderIndex,
|
||||||
|
newFolderName: this.$props.folder.name,
|
||||||
|
oldFolderIndex,
|
||||||
|
oldFolderName,
|
||||||
|
requestIndex,
|
||||||
|
})
|
||||||
|
this.syncCollections()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,8 +108,8 @@ export default {
|
|||||||
},
|
},
|
||||||
replaceWithJSON() {
|
replaceWithJSON() {
|
||||||
let reader = new FileReader()
|
let reader = new FileReader()
|
||||||
reader.onload = (event) => {
|
reader.onload = ({ target }) => {
|
||||||
let content = event.target.result
|
let content = target.result
|
||||||
let collections = JSON.parse(content)
|
let collections = JSON.parse(content)
|
||||||
if (collections[0]) {
|
if (collections[0]) {
|
||||||
let [name, folders, requests] = Object.keys(collections[0])
|
let [name, folders, requests] = Object.keys(collections[0])
|
||||||
@@ -117,7 +117,7 @@ export default {
|
|||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
} else if (collections.info && collections.info.schema.includes("v2.1.0")) {
|
} else if (collections.info && collections.info.schema.includes("v2.1.0")) {
|
||||||
collections = this.parsePostmanCollection(collections)
|
collections = [this.parsePostmanCollection(collections)]
|
||||||
} else {
|
} else {
|
||||||
return this.failedImport()
|
return this.failedImport()
|
||||||
}
|
}
|
||||||
@@ -130,8 +130,8 @@ export default {
|
|||||||
},
|
},
|
||||||
importFromJSON() {
|
importFromJSON() {
|
||||||
let reader = new FileReader()
|
let reader = new FileReader()
|
||||||
reader.onload = (event) => {
|
reader.onload = ({ target }) => {
|
||||||
let content = event.target.result
|
let content = target.result
|
||||||
let collections = JSON.parse(content)
|
let collections = JSON.parse(content)
|
||||||
if (collections[0]) {
|
if (collections[0]) {
|
||||||
let [name, folders, requests] = Object.keys(collections[0])
|
let [name, folders, requests] = Object.keys(collections[0])
|
||||||
@@ -141,8 +141,7 @@ export default {
|
|||||||
} else if (collections.info && collections.info.schema.includes("v2.1.0")) {
|
} else if (collections.info && collections.info.schema.includes("v2.1.0")) {
|
||||||
//replace the variables, postman uses {{var}}, Hoppscotch uses <<var>>
|
//replace the variables, postman uses {{var}}, Hoppscotch uses <<var>>
|
||||||
collections = JSON.parse(content.replaceAll(/{{([a-z]+)}}/gi, "<<$1>>"))
|
collections = JSON.parse(content.replaceAll(/{{([a-z]+)}}/gi, "<<$1>>"))
|
||||||
collections.item = this.flattenPostmanFolders(collections)
|
collections = [this.parsePostmanCollection(collections)]
|
||||||
collections = this.parsePostmanCollection(collections)
|
|
||||||
} else {
|
} else {
|
||||||
return this.failedImport()
|
return this.failedImport()
|
||||||
}
|
}
|
||||||
@@ -192,36 +191,30 @@ export default {
|
|||||||
icon: "error",
|
icon: "error",
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
parsePostmanCollection(collection, folders = true) {
|
parsePostmanCollection({ info, name, item }) {
|
||||||
let postwomanCollection = folders
|
let postwomanCollection = {
|
||||||
? [
|
name: "",
|
||||||
{
|
folders: [],
|
||||||
name: "",
|
requests: [],
|
||||||
folders: [],
|
|
||||||
requests: [],
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: {
|
|
||||||
name: "",
|
|
||||||
requests: [],
|
|
||||||
}
|
|
||||||
if (folders) {
|
|
||||||
//pick up collection name even when all children are folders
|
|
||||||
postwomanCollection[0].name = collection.info ? collection.info.name : ""
|
|
||||||
}
|
}
|
||||||
for (let collectionItem of collection.item) {
|
|
||||||
if (collectionItem.request) {
|
postwomanCollection.name = info ? info.name : name
|
||||||
if (postwomanCollection[0]) {
|
|
||||||
postwomanCollection[0].name = collection.info ? collection.info.name : ""
|
if (item && item.length > 0) {
|
||||||
postwomanCollection[0].requests.push(this.parsePostmanRequest(collectionItem))
|
for (let collectionItem of item) {
|
||||||
|
if (collectionItem.request) {
|
||||||
|
if (postwomanCollection.hasOwnProperty("folders")) {
|
||||||
|
postwomanCollection.name = info ? info.name : name
|
||||||
|
postwomanCollection.requests.push(this.parsePostmanRequest(collectionItem))
|
||||||
|
} else {
|
||||||
|
postwomanCollection.name = name ? name : ""
|
||||||
|
postwomanCollection.requests.push(this.parsePostmanRequest(collectionItem))
|
||||||
|
}
|
||||||
|
} else if (this.hasFolder(collectionItem)) {
|
||||||
|
postwomanCollection.folders.push(this.parsePostmanCollection(collectionItem))
|
||||||
} else {
|
} else {
|
||||||
postwomanCollection.name = collection.name ? collection.name : ""
|
|
||||||
postwomanCollection.requests.push(this.parsePostmanRequest(collectionItem))
|
postwomanCollection.requests.push(this.parsePostmanRequest(collectionItem))
|
||||||
}
|
}
|
||||||
} else if (collectionItem.item) {
|
|
||||||
if (collectionItem.item[0]) {
|
|
||||||
postwomanCollection[0].folders.push(this.parsePostmanCollection(collectionItem, false))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return postwomanCollection
|
return postwomanCollection
|
||||||
@@ -300,46 +293,8 @@ export default {
|
|||||||
}
|
}
|
||||||
return pwRequest
|
return pwRequest
|
||||||
},
|
},
|
||||||
flattenPostmanFolders(collection) {
|
|
||||||
let items = []
|
|
||||||
|
|
||||||
for (let collectionItem of collection.item) {
|
|
||||||
if (this.hasFolder(collectionItem)) {
|
|
||||||
let newFolderItems = []
|
|
||||||
for (let folderItem of collectionItem.item) {
|
|
||||||
if (this.isSubFolder(folderItem)) {
|
|
||||||
newFolderItems = newFolderItems.concat(this.flattenPostmanItem(folderItem))
|
|
||||||
} else {
|
|
||||||
newFolderItems.push(folderItem)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
collectionItem.item = newFolderItems
|
|
||||||
}
|
|
||||||
items.push(collectionItem)
|
|
||||||
}
|
|
||||||
return items
|
|
||||||
},
|
|
||||||
hasFolder(item) {
|
hasFolder(item) {
|
||||||
return Object.prototype.hasOwnProperty.call(item, "item")
|
return item.hasOwnProperty("item")
|
||||||
},
|
|
||||||
isSubFolder(item) {
|
|
||||||
return (
|
|
||||||
Object.prototype.hasOwnProperty.call(item, "_postman_isSubFolder") &&
|
|
||||||
item._postman_isSubFolder
|
|
||||||
)
|
|
||||||
},
|
|
||||||
flattenPostmanItem(subFolder, subFolderGlue = " -- ") {
|
|
||||||
delete subFolder._postman_isSubFolder
|
|
||||||
let flattenedItems = []
|
|
||||||
for (let subFolderItem of subFolder.item) {
|
|
||||||
subFolderItem.name = subFolder.name + subFolderGlue + subFolderItem.name
|
|
||||||
if (this.isSubFolder(subFolderItem)) {
|
|
||||||
flattenedItems = flattenedItems.concat(this.flattenPostmanItem(subFolderItem))
|
|
||||||
} else {
|
|
||||||
flattenedItems.push(subFolderItem)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return flattenedItems
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,30 +14,29 @@ TODO:
|
|||||||
<add-collection :show="showModalAdd" @hide-modal="displayModalAdd(false)" />
|
<add-collection :show="showModalAdd" @hide-modal="displayModalAdd(false)" />
|
||||||
<edit-collection
|
<edit-collection
|
||||||
:show="showModalEdit"
|
:show="showModalEdit"
|
||||||
:editingCollection="editingCollection"
|
:editing-collection="editingCollection"
|
||||||
:editingCollectionIndex="editingCollectionIndex"
|
:editing-collection-index="editingCollectionIndex"
|
||||||
@hide-modal="displayModalEdit(false)"
|
@hide-modal="displayModalEdit(false)"
|
||||||
/>
|
/>
|
||||||
<add-folder
|
<add-folder
|
||||||
:show="showModalAddFolder"
|
:show="showModalAddFolder"
|
||||||
:collection="editingCollection"
|
:folder="editingFolder"
|
||||||
:collectionIndex="editingCollectionIndex"
|
|
||||||
@hide-modal="displayModalAddFolder(false)"
|
@hide-modal="displayModalAddFolder(false)"
|
||||||
/>
|
/>
|
||||||
<edit-folder
|
<edit-folder
|
||||||
:show="showModalEditFolder"
|
:show="showModalEditFolder"
|
||||||
:collection="editingCollection"
|
:collection-index="editingCollectionIndex"
|
||||||
:collectionIndex="editingCollectionIndex"
|
|
||||||
:folder="editingFolder"
|
:folder="editingFolder"
|
||||||
:folderIndex="editingFolderIndex"
|
:folder-index="editingFolderIndex"
|
||||||
@hide-modal="displayModalEditFolder(false)"
|
@hide-modal="displayModalEditFolder(false)"
|
||||||
/>
|
/>
|
||||||
<edit-request
|
<edit-request
|
||||||
:show="showModalEditRequest"
|
:show="showModalEditRequest"
|
||||||
:collectionIndex="editingCollectionIndex"
|
:collection-index="editingCollectionIndex"
|
||||||
:folderIndex="editingFolderIndex"
|
:folder-index="editingFolderIndex"
|
||||||
|
:folder-name="editingFolderName"
|
||||||
:request="editingRequest"
|
:request="editingRequest"
|
||||||
:requestIndex="editingRequestIndex"
|
:request-index="editingRequestIndex"
|
||||||
@hide-modal="displayModalEditRequest(false)"
|
@hide-modal="displayModalEditRequest(false)"
|
||||||
/>
|
/>
|
||||||
<import-export-collections
|
<import-export-collections
|
||||||
@@ -74,12 +73,13 @@ TODO:
|
|||||||
<ul class="flex-col">
|
<ul class="flex-col">
|
||||||
<li v-for="(collection, index) in filteredCollections" :key="collection.name">
|
<li v-for="(collection, index) in filteredCollections" :key="collection.name">
|
||||||
<collection
|
<collection
|
||||||
|
:name="collection.name"
|
||||||
:collection-index="index"
|
:collection-index="index"
|
||||||
:collection="collection"
|
:collection="collection"
|
||||||
:doc="doc"
|
:doc="doc"
|
||||||
:isFiltered="filterText.length > 0"
|
:isFiltered="filterText.length > 0"
|
||||||
@edit-collection="editCollection(collection, index)"
|
@edit-collection="editCollection(collection, index)"
|
||||||
@add-folder="addFolder(collection, index)"
|
@add-folder="addFolder($event)"
|
||||||
@edit-folder="editFolder($event)"
|
@edit-folder="editFolder($event)"
|
||||||
@edit-request="editRequest($event)"
|
@edit-request="editRequest($event)"
|
||||||
@select-collection="$emit('use-collection', collection)"
|
@select-collection="$emit('use-collection', collection)"
|
||||||
@@ -119,6 +119,7 @@ export default {
|
|||||||
editingCollection: undefined,
|
editingCollection: undefined,
|
||||||
editingCollectionIndex: undefined,
|
editingCollectionIndex: undefined,
|
||||||
editingFolder: undefined,
|
editingFolder: undefined,
|
||||||
|
editingFolderName: undefined,
|
||||||
editingFolderIndex: undefined,
|
editingFolderIndex: undefined,
|
||||||
editingRequest: undefined,
|
editingRequest: undefined,
|
||||||
editingRequestIndex: undefined,
|
editingRequestIndex: undefined,
|
||||||
@@ -212,15 +213,14 @@ export default {
|
|||||||
this.displayModalEdit(true)
|
this.displayModalEdit(true)
|
||||||
this.syncCollections()
|
this.syncCollections()
|
||||||
},
|
},
|
||||||
addFolder(collection, collectionIndex) {
|
addFolder(payload) {
|
||||||
this.$data.editingCollection = collection
|
const { folder } = payload
|
||||||
this.$data.editingCollectionIndex = collectionIndex
|
this.$data.editingFolder = folder
|
||||||
this.displayModalAddFolder(true)
|
this.displayModalAddFolder(true)
|
||||||
this.syncCollections()
|
this.syncCollections()
|
||||||
},
|
},
|
||||||
editFolder(payload) {
|
editFolder(payload) {
|
||||||
const { collection, collectionIndex, folder, folderIndex } = payload
|
const { collectionIndex, folder, folderIndex } = payload
|
||||||
this.$data.editingCollection = collection
|
|
||||||
this.$data.editingCollectionIndex = collectionIndex
|
this.$data.editingCollectionIndex = collectionIndex
|
||||||
this.$data.editingFolder = folder
|
this.$data.editingFolder = folder
|
||||||
this.$data.editingFolderIndex = folderIndex
|
this.$data.editingFolderIndex = folderIndex
|
||||||
@@ -228,9 +228,10 @@ export default {
|
|||||||
this.syncCollections()
|
this.syncCollections()
|
||||||
},
|
},
|
||||||
editRequest(payload) {
|
editRequest(payload) {
|
||||||
const { request, collectionIndex, folderIndex, requestIndex } = payload
|
const { collectionIndex, folderIndex, folderName, request, requestIndex } = payload
|
||||||
this.$data.editingCollectionIndex = collectionIndex
|
this.$data.editingCollectionIndex = collectionIndex
|
||||||
this.$data.editingFolderIndex = folderIndex
|
this.$data.editingFolderIndex = folderIndex
|
||||||
|
this.$data.editingFolderName = folderName
|
||||||
this.$data.editingRequest = request
|
this.$data.editingRequest = request
|
||||||
this.$data.editingRequestIndex = requestIndex
|
this.$data.editingRequestIndex = requestIndex
|
||||||
this.displayModalEditRequest(true)
|
this.displayModalEditRequest(true)
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="row-wrapper">
|
<div
|
||||||
|
:class="['row-wrapper', dragging ? 'drag-el' : '']"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart="dragStart"
|
||||||
|
@dragover.stop
|
||||||
|
@dragleave="dragging = false"
|
||||||
|
@dragend="dragging = false"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
class="icon"
|
class="icon"
|
||||||
@@ -16,7 +23,19 @@
|
|||||||
</button>
|
</button>
|
||||||
<template slot="popover">
|
<template slot="popover">
|
||||||
<div>
|
<div>
|
||||||
<button class="icon" @click="$emit('edit-request')" v-close-popover>
|
<button
|
||||||
|
class="icon"
|
||||||
|
@click="
|
||||||
|
$emit('edit-request', {
|
||||||
|
collectionIndex,
|
||||||
|
folderIndex,
|
||||||
|
folderName,
|
||||||
|
request,
|
||||||
|
requestIndex,
|
||||||
|
})
|
||||||
|
"
|
||||||
|
v-close-popover
|
||||||
|
>
|
||||||
<i class="material-icons">edit</i>
|
<i class="material-icons">edit</i>
|
||||||
<span>{{ $t("edit") }}</span>
|
<span>{{ $t("edit") }}</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -42,9 +61,15 @@ export default {
|
|||||||
request: Object,
|
request: Object,
|
||||||
collectionIndex: Number,
|
collectionIndex: Number,
|
||||||
folderIndex: Number,
|
folderIndex: Number,
|
||||||
|
folderName: String,
|
||||||
requestIndex: Number,
|
requestIndex: Number,
|
||||||
doc: Boolean,
|
doc: Boolean,
|
||||||
},
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dragging: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
syncCollections() {
|
syncCollections() {
|
||||||
if (fb.currentUser !== null) {
|
if (fb.currentUser !== null) {
|
||||||
@@ -56,12 +81,19 @@ export default {
|
|||||||
selectRequest() {
|
selectRequest() {
|
||||||
this.$store.commit("postwoman/selectRequest", { request: this.request })
|
this.$store.commit("postwoman/selectRequest", { request: this.request })
|
||||||
},
|
},
|
||||||
|
dragStart({ dataTransfer }) {
|
||||||
|
this.dragging = !this.dragging
|
||||||
|
dataTransfer.setData("oldCollectionIndex", this.$props.collectionIndex)
|
||||||
|
dataTransfer.setData("oldFolderIndex", this.$props.folderIndex)
|
||||||
|
dataTransfer.setData("oldFolderName", this.$props.folderName)
|
||||||
|
dataTransfer.setData("requestIndex", this.$props.requestIndex)
|
||||||
|
},
|
||||||
removeRequest() {
|
removeRequest() {
|
||||||
if (!confirm(this.$t("are_you_sure_remove_request"))) return
|
if (!confirm(this.$t("are_you_sure_remove_request"))) return
|
||||||
this.$store.commit("postwoman/removeRequest", {
|
this.$store.commit("postwoman/removeRequest", {
|
||||||
collectionIndex: this.collectionIndex,
|
collectionIndex: this.$props.collectionIndex,
|
||||||
folderIndex: this.folderIndex,
|
folderName: this.$props.folderName,
|
||||||
requestIndex: this.requestIndex,
|
requestIndex: this.$props.requestIndex,
|
||||||
})
|
})
|
||||||
this.$toast.error(this.$t("deleted"), {
|
this.$toast.error(this.$t("deleted"), {
|
||||||
icon: "delete",
|
icon: "delete",
|
||||||
|
|||||||
@@ -40,15 +40,13 @@
|
|||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</span>
|
</span>
|
||||||
<label for="selectFolder">{{ $t("folder") }}</label>
|
<label>{{ $t("folder") }}</label>
|
||||||
<span class="select-wrapper">
|
<autocomplete
|
||||||
<select type="text" id="selectFolder" v-model="requestData.folderIndex">
|
:placeholder="$t('search')"
|
||||||
<option :key="undefined" :value="undefined">/</option>
|
:source="folders"
|
||||||
<option v-for="(folder, index) in folders" :key="index" :value="index">
|
:spellcheck="false"
|
||||||
{{ folder.name }}
|
v-model="requestData.folderName"
|
||||||
</option>
|
/>
|
||||||
</select>
|
|
||||||
</span>
|
|
||||||
<label for="selectRequest">{{ $t("request") }}</label>
|
<label for="selectRequest">{{ $t("request") }}</label>
|
||||||
<span class="select-wrapper">
|
<span class="select-wrapper">
|
||||||
<select type="text" id="selectRequest" v-model="requestData.requestIndex">
|
<select type="text" id="selectRequest" v-model="requestData.requestIndex">
|
||||||
@@ -95,60 +93,62 @@ export default {
|
|||||||
requestData: {
|
requestData: {
|
||||||
name: undefined,
|
name: undefined,
|
||||||
collectionIndex: undefined,
|
collectionIndex: undefined,
|
||||||
folderIndex: undefined,
|
folderName: undefined,
|
||||||
requestIndex: undefined,
|
requestIndex: undefined,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
"requestData.collectionIndex": function resetFolderAndRequestIndex() {
|
"requestData.collectionIndex": function resetFolderAndRequestIndex() {
|
||||||
// if user choosen some folder, than selected other collection, which doesn't have any folders
|
// if user has chosen some folder, than selected other collection, which doesn't have any folders
|
||||||
// than `requestUpdateData.folderIndex` won't be reseted
|
// than `requestUpdateData.folderName` won't be reseted
|
||||||
this.$data.requestData.folderIndex = undefined
|
this.$data.requestData.folderName = undefined
|
||||||
this.$data.requestData.requestIndex = undefined
|
this.$data.requestData.requestIndex = undefined
|
||||||
},
|
},
|
||||||
"requestData.folderIndex": function resetRequestIndex() {
|
"requestData.folderName": function resetRequestIndex() {
|
||||||
this.$data.requestData.requestIndex = undefined
|
this.$data.requestData.requestIndex = undefined
|
||||||
},
|
},
|
||||||
editingRequest(request) {
|
editingRequest({ label }) {
|
||||||
this.defaultRequestName = request.label || "My Request"
|
this.defaultRequestName = label || "My Request"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
folders() {
|
folders() {
|
||||||
const userSelectedAnyCollection = this.$data.requestData.collectionIndex !== undefined
|
const collections = this.$store.state.postwoman.collections
|
||||||
|
const collectionIndex = this.$data.requestData.collectionIndex
|
||||||
|
const userSelectedAnyCollection = collectionIndex !== undefined
|
||||||
if (!userSelectedAnyCollection) return []
|
if (!userSelectedAnyCollection) return []
|
||||||
|
|
||||||
const noCollectionAvailable =
|
const noCollectionAvailable = collections[collectionIndex] !== undefined
|
||||||
this.$store.state.postwoman.collections[this.$data.requestData.collectionIndex] !==
|
|
||||||
undefined
|
|
||||||
if (!noCollectionAvailable) return []
|
if (!noCollectionAvailable) return []
|
||||||
|
|
||||||
return this.$store.state.postwoman.collections[this.$data.requestData.collectionIndex].folders
|
return getFolderNames(collections[collectionIndex].folders, [])
|
||||||
},
|
},
|
||||||
requests() {
|
requests() {
|
||||||
const userSelectedAnyCollection = this.$data.requestData.collectionIndex !== undefined
|
const collections = this.$store.state.postwoman.collections
|
||||||
if (!userSelectedAnyCollection) return []
|
const collectionIndex = this.$data.requestData.collectionIndex
|
||||||
|
const folderName = this.$data.requestData.folderName
|
||||||
|
|
||||||
|
const userSelectedAnyCollection = collectionIndex !== undefined
|
||||||
|
if (!userSelectedAnyCollection) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
const userSelectedAnyFolder = folderName !== undefined && folderName !== ""
|
||||||
|
|
||||||
const userSelectedAnyFolder = this.$data.requestData.folderIndex !== undefined
|
|
||||||
if (userSelectedAnyFolder) {
|
if (userSelectedAnyFolder) {
|
||||||
const collection = this.$store.state.postwoman.collections[
|
const collection = collections[collectionIndex]
|
||||||
this.$data.requestData.collectionIndex
|
const folder = findFolder(folderName, collection)
|
||||||
]
|
return folder.requests
|
||||||
const folder = collection.folders[this.$data.requestData.folderIndex]
|
|
||||||
const requests = folder.requests
|
|
||||||
return requests
|
|
||||||
} else {
|
} else {
|
||||||
const collection = this.$store.state.postwoman.collections[
|
const collection = collections[collectionIndex]
|
||||||
this.$data.requestData.collectionIndex
|
const noCollectionAvailable = collection !== undefined
|
||||||
]
|
|
||||||
const noCollectionAvailable =
|
|
||||||
this.$store.state.postwoman.collections[this.$data.requestData.collectionIndex] !==
|
|
||||||
undefined
|
|
||||||
if (!noCollectionAvailable) return []
|
|
||||||
|
|
||||||
const requests = collection.requests
|
if (!noCollectionAvailable) {
|
||||||
return requests
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
return collection.requests
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -178,7 +178,7 @@ export default {
|
|||||||
this.$store.commit("postwoman/saveRequestAs", {
|
this.$store.commit("postwoman/saveRequestAs", {
|
||||||
request: requestUpdated,
|
request: requestUpdated,
|
||||||
collectionIndex: this.$data.requestData.collectionIndex,
|
collectionIndex: this.$data.requestData.collectionIndex,
|
||||||
folderIndex: this.$data.requestData.folderIndex,
|
folderName: this.$data.requestData.folderName,
|
||||||
requestIndex: this.$data.requestData.requestIndex,
|
requestIndex: this.$data.requestData.requestIndex,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -191,4 +191,36 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getFolderNames(folders, namesList) {
|
||||||
|
if (folders.length) {
|
||||||
|
folders.forEach((folder) => {
|
||||||
|
namesList.push(folder.name)
|
||||||
|
if (folder.folders && folder.folders.length) {
|
||||||
|
getFolderNames(folder.folders, namesList)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return namesList
|
||||||
|
}
|
||||||
|
|
||||||
|
function findFolder(folderName, currentFolder) {
|
||||||
|
let selectedFolder
|
||||||
|
let result
|
||||||
|
|
||||||
|
if (folderName === currentFolder.name) {
|
||||||
|
return currentFolder
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < currentFolder.folders.length; i++) {
|
||||||
|
selectedFolder = currentFolder.folders[i]
|
||||||
|
|
||||||
|
result = findFolder(folderName, selectedFolder)
|
||||||
|
|
||||||
|
if (result !== false) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
editingEnvironment: function (update) {
|
editingEnvironment(update) {
|
||||||
this.name =
|
this.name =
|
||||||
this.$props.editingEnvironment && this.$props.editingEnvironment.name
|
this.$props.editingEnvironment && this.$props.editingEnvironment.name
|
||||||
? this.$props.editingEnvironment.name
|
? this.$props.editingEnvironment.name
|
||||||
@@ -151,13 +151,13 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
clearContent(e) {
|
clearContent({ target }) {
|
||||||
this.$store.commit("postwoman/removeVariables", [])
|
this.$store.commit("postwoman/removeVariables", [])
|
||||||
e.target.innerHTML = this.doneButton
|
target.innerHTML = this.doneButton
|
||||||
this.$toast.info(this.$t("cleared"), {
|
this.$toast.info(this.$t("cleared"), {
|
||||||
icon: "clear_all",
|
icon: "clear_all",
|
||||||
})
|
})
|
||||||
setTimeout(() => (e.target.innerHTML = '<i class="material-icons">clear_all</i>'), 1000)
|
setTimeout(() => (target.innerHTML = '<i class="material-icons">clear_all</i>'), 1000)
|
||||||
},
|
},
|
||||||
addEnvironmentVariable() {
|
addEnvironmentVariable() {
|
||||||
let value = { key: "", value: "" }
|
let value = { key: "", value: "" }
|
||||||
|
|||||||
@@ -108,8 +108,8 @@ export default {
|
|||||||
},
|
},
|
||||||
replaceWithJSON() {
|
replaceWithJSON() {
|
||||||
let reader = new FileReader()
|
let reader = new FileReader()
|
||||||
reader.onload = (event) => {
|
reader.onload = ({ target }) => {
|
||||||
let content = event.target.result
|
let content = target.result
|
||||||
let environments = JSON.parse(content)
|
let environments = JSON.parse(content)
|
||||||
this.$store.commit("postwoman/replaceEnvironments", environments)
|
this.$store.commit("postwoman/replaceEnvironments", environments)
|
||||||
}
|
}
|
||||||
@@ -120,8 +120,8 @@ export default {
|
|||||||
},
|
},
|
||||||
importFromJSON() {
|
importFromJSON() {
|
||||||
let reader = new FileReader()
|
let reader = new FileReader()
|
||||||
reader.onload = (event) => {
|
reader.onload = ({ target }) => {
|
||||||
let content = event.target.result
|
let content = target.result
|
||||||
let importFileObj = JSON.parse(content)
|
let importFileObj = JSON.parse(content)
|
||||||
if (
|
if (
|
||||||
importFileObj["_postman_variable_scope"] === "environment" ||
|
importFileObj["_postman_variable_scope"] === "environment" ||
|
||||||
@@ -143,11 +143,9 @@ export default {
|
|||||||
confirmation,
|
confirmation,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
importFromPostman(importFileObj) {
|
importFromPostman({ name, values }) {
|
||||||
let environment = { name: importFileObj.name, variables: [] }
|
let environment = { name, variables: [] }
|
||||||
importFileObj.values.forEach((element) =>
|
values.forEach(({ key, value }) => environment.variables.push({ key, value }))
|
||||||
environment.variables.push({ key: element.key, value: element.value })
|
|
||||||
)
|
|
||||||
let environments = [environment]
|
let environments = [environment]
|
||||||
this.importFromPostwoman(environments)
|
this.importFromPostwoman(environments)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -54,8 +54,8 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async deleteFeed(feed) {
|
async deleteFeed({ id }) {
|
||||||
await fb.deleteFeed(feed.id)
|
await fb.deleteFeed(id)
|
||||||
this.$toast.error(this.$t("deleted"), {
|
this.$toast.error(this.$t("deleted"), {
|
||||||
icon: "delete",
|
icon: "delete",
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -35,9 +35,7 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
isFieldHighlighted({ field }) {
|
isFieldHighlighted({ field }) {
|
||||||
return !!this.highlightedFields.find(
|
return !!this.highlightedFields.find(({ name }) => name === field.name)
|
||||||
(highlightedField) => highlightedField.name === field.name
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -368,8 +368,8 @@ export default {
|
|||||||
useHistory(entry) {
|
useHistory(entry) {
|
||||||
this.$emit("useHistory", entry)
|
this.$emit("useHistory", entry)
|
||||||
},
|
},
|
||||||
findEntryStatus(entry) {
|
findEntryStatus({ status }) {
|
||||||
const foundStatusGroup = findStatusGroup(entry.status)
|
const foundStatusGroup = findStatusGroup(status)
|
||||||
return (
|
return (
|
||||||
foundStatusGroup || {
|
foundStatusGroup || {
|
||||||
className: "",
|
className: "",
|
||||||
|
|||||||
@@ -359,34 +359,34 @@ export default {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// let showAd = localStorage.getItem("showAd") === "no"
|
let showAd = localStorage.getItem("showAd") === "no"
|
||||||
// if (!showAd) {
|
if (!showAd) {
|
||||||
// setTimeout(() => {
|
setTimeout(() => {
|
||||||
// this.$toast.clear()
|
this.$toast.clear()
|
||||||
// this.$toast.show(
|
this.$toast.show(
|
||||||
// "<span>Postwoman is now Hoppscotch 🎉<br><u><a href='https://dev.to/liyasthomas/postwoman-is-changing-name-igp' target='_blank' rel='noopener'>Read the announcement</a></u> →<br><sub>Whoosh this away to dismiss.</sub></span>",
|
"<span><a href='https://github.com/sponsors/hoppscotch' target='_blank' rel='noopener'>Make a donation to support Hoppscotch open source project 🎉</a><br><sub>Whoosh this away to dismiss.</sub></span>",
|
||||||
// {
|
{
|
||||||
// icon: "",
|
icon: "",
|
||||||
// duration: 0,
|
duration: 0,
|
||||||
// theme: "toasted-ad",
|
theme: "toasted-ad",
|
||||||
// action: [
|
action: [
|
||||||
// {
|
{
|
||||||
// text: "GitHub",
|
text: "DONATE",
|
||||||
// icon: "chevron_right",
|
icon: "favorite",
|
||||||
// onClick: (e, toastObject) => {
|
onClick: (e, toastObject) => {
|
||||||
// // localStorage.setItem("showAd", "no")
|
localStorage.setItem("showAd", "no")
|
||||||
// toastObject.goAway(0)
|
toastObject.goAway(0)
|
||||||
// window.open("https://github.com/hoppscotch/hoppscotch")
|
window.open("https://github.com/sponsors/hoppscotch")
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// ],
|
],
|
||||||
// onComplete() {
|
onComplete() {
|
||||||
// // localStorage.setItem("showAd", "no")
|
localStorage.setItem("showAd", "no")
|
||||||
// },
|
},
|
||||||
// }
|
}
|
||||||
// )
|
)
|
||||||
// }, 8000)
|
}, 8000)
|
||||||
// }
|
}
|
||||||
|
|
||||||
let showExtensionsToast = localStorage.getItem("showExtensionsToast") === "yes"
|
let showExtensionsToast = localStorage.getItem("showExtensionsToast") === "yes"
|
||||||
|
|
||||||
@@ -452,11 +452,5 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
|
||||||
availableLocales() {
|
|
||||||
return this.$i18n.locales.filter((i) => i.code !== this.$i18n.locale)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -73,6 +73,7 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import TextContentRendererMixin from "./mixins/TextContentRendererMixin"
|
import TextContentRendererMixin from "./mixins/TextContentRendererMixin"
|
||||||
|
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ export default {
|
|||||||
const blob = new Blob([bytes.buffer])
|
const blob = new Blob([bytes.buffer])
|
||||||
|
|
||||||
const reader = new FileReader()
|
const reader = new FileReader()
|
||||||
reader.onload = (e) => {
|
reader.onload = ({ target }) => {
|
||||||
this.imageSource = e.target.result
|
this.imageSource = target.result
|
||||||
}
|
}
|
||||||
reader.readAsDataURL(blob)
|
reader.readAsDataURL(blob)
|
||||||
},
|
},
|
||||||
@@ -65,8 +65,8 @@ export default {
|
|||||||
const blob = new Blob([bytes.buffer])
|
const blob = new Blob([bytes.buffer])
|
||||||
|
|
||||||
const reader = new FileReader()
|
const reader = new FileReader()
|
||||||
reader.onload = (e) => {
|
reader.onload = ({ target }) => {
|
||||||
this.imageSource = e.target.result
|
this.imageSource = target.result
|
||||||
}
|
}
|
||||||
reader.readAsDataURL(blob)
|
reader.readAsDataURL(blob)
|
||||||
},
|
},
|
||||||
@@ -78,7 +78,8 @@ export default {
|
|||||||
const url = URL.createObjectURL(file)
|
const url = URL.createObjectURL(file)
|
||||||
a.href = url
|
a.href = url
|
||||||
// TODO get uri from meta
|
// TODO get uri from meta
|
||||||
a.download = `response on ${Date()}`.replace(/\./g, "[dot]")
|
a.download = `${url.split("/").pop().split("#")[0].split("?")[0]}.${this.responseType}`
|
||||||
|
// `response on ${Date()}`.replace(/\./g, "[dot]")
|
||||||
document.body.appendChild(a)
|
document.body.appendChild(a)
|
||||||
a.click()
|
a.click()
|
||||||
this.$refs.downloadResponse.innerHTML = this.doneButton
|
this.$refs.downloadResponse.innerHTML = this.doneButton
|
||||||
|
|||||||
@@ -55,6 +55,7 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { isJSONContentType } from "~/helpers/utils/contenttypes"
|
import { isJSONContentType } from "~/helpers/utils/contenttypes"
|
||||||
import TextContentRendererMixin from "./mixins/TextContentRendererMixin"
|
import TextContentRendererMixin from "./mixins/TextContentRendererMixin"
|
||||||
|
|||||||
@@ -55,6 +55,7 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import TextContentRendererMixin from "./mixins/TextContentRendererMixin"
|
import TextContentRendererMixin from "./mixins/TextContentRendererMixin"
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
getSourcePrefix,
|
getSourcePrefix,
|
||||||
},
|
},
|
||||||
updated: function () {
|
updated() {
|
||||||
this.$nextTick(function () {
|
this.$nextTick(function () {
|
||||||
if (this.$refs.log) {
|
if (this.$refs.log) {
|
||||||
this.$refs.log.scrollBy(0, this.$refs.log.scrollHeight + 100)
|
this.$refs.log.scrollBy(0, this.$refs.log.scrollHeight + 100)
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ import Paho from "paho-mqtt"
|
|||||||
import { wsValid } from "~/helpers/utils/valid"
|
import { wsValid } from "~/helpers/utils/valid"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data: function () {
|
data() {
|
||||||
return {
|
return {
|
||||||
url: "wss://test.mosquitto.org:8081",
|
url: "wss://test.mosquitto.org:8081",
|
||||||
client: null,
|
client: null,
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
lang(value) {
|
lang(value) {
|
||||||
this.editor.getSession().setMode("ace/mode/" + value)
|
this.editor.getSession().setMode(`ace/mode/${value}`)
|
||||||
},
|
},
|
||||||
options(value) {
|
options(value) {
|
||||||
this.editor.setOptions(value)
|
this.editor.setOptions(value)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
@keydown="handleKeystroke"
|
@keydown="handleKeystroke"
|
||||||
ref="acInput"
|
ref="acInput"
|
||||||
:spellcheck="spellcheck"
|
:spellcheck="spellcheck"
|
||||||
:autocapitalize="spellcheck"
|
:autocapitalize="autocapitalize"
|
||||||
:autocorrect="spellcheck"
|
:autocorrect="spellcheck"
|
||||||
/>
|
/>
|
||||||
<ul
|
<ul
|
||||||
@@ -86,6 +86,12 @@ export default {
|
|||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
autocapitalize: {
|
||||||
|
type: String,
|
||||||
|
default: "off",
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
|
||||||
placeholder: {
|
placeholder: {
|
||||||
type: String,
|
type: String,
|
||||||
default: "",
|
default: "",
|
||||||
@@ -190,12 +196,11 @@ export default {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
this.source
|
this.source
|
||||||
.filter((entry) => {
|
.filter(
|
||||||
return (
|
(entry) =>
|
||||||
entry.toLowerCase().startsWith(input.toLowerCase()) &&
|
entry.toLowerCase().startsWith(input.toLowerCase()) &&
|
||||||
input.toLowerCase() !== entry.toLowerCase()
|
input.toLowerCase() !== entry.toLowerCase()
|
||||||
)
|
)
|
||||||
})
|
|
||||||
// Cut off the part that's already been typed.
|
// Cut off the part that's already been typed.
|
||||||
.map((entry) => entry.substring(this.selectionStart))
|
.map((entry) => entry.substring(this.selectionStart))
|
||||||
// We only want the top 6 suggestions.
|
// We only want the top 6 suggestions.
|
||||||
|
|||||||
@@ -121,35 +121,6 @@ beforeEach(async () => {
|
|||||||
value: true,
|
value: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
await mocksdk
|
|
||||||
.firestore()
|
|
||||||
.collection("users")
|
|
||||||
.doc(testuser.uid)
|
|
||||||
.collection("settings")
|
|
||||||
.doc("syncTeams")
|
|
||||||
.set({
|
|
||||||
author: testuser.uid,
|
|
||||||
author_image: testuser.photoURL,
|
|
||||||
author_name: testuser.displayName,
|
|
||||||
name: "syncTeams",
|
|
||||||
updatedOn: new Date(1598703948000),
|
|
||||||
value: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
await mocksdk
|
|
||||||
.firestore()
|
|
||||||
.collection("users")
|
|
||||||
.doc(testuser.uid)
|
|
||||||
.collection("teams")
|
|
||||||
.doc("sync")
|
|
||||||
.set({
|
|
||||||
author: testuser.uid,
|
|
||||||
author_image: testuser.photoURL,
|
|
||||||
author_name: testuser.displayName,
|
|
||||||
team: [],
|
|
||||||
updatedOn: new Date(1598703948000),
|
|
||||||
})
|
|
||||||
|
|
||||||
await mocksdk
|
await mocksdk
|
||||||
.firestore()
|
.firestore()
|
||||||
.collection("users")
|
.collection("users")
|
||||||
@@ -1232,78 +1203,4 @@ describe("FirebaseInstance", () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("writeTeams", () => {
|
|
||||||
test("resolves for proper authenticated request", async () => {
|
|
||||||
const fb = new FirebaseInstance(mocksdk)
|
|
||||||
|
|
||||||
signInUser()
|
|
||||||
|
|
||||||
await expect(fb.writeTeams([])).resolves.toBeUndefined()
|
|
||||||
})
|
|
||||||
|
|
||||||
test("rejects for non-authenticated request", async () => {
|
|
||||||
const fb = new FirebaseInstance(mocksdk)
|
|
||||||
|
|
||||||
signOutUser()
|
|
||||||
|
|
||||||
await expect(fb.writeTeams([])).rejects.toBeDefined()
|
|
||||||
})
|
|
||||||
|
|
||||||
test("stores data on firestore with proper structure", async () => {
|
|
||||||
const fb = new FirebaseInstance(mocksdk)
|
|
||||||
|
|
||||||
signInUser()
|
|
||||||
|
|
||||||
await fb.writeTeams([])
|
|
||||||
|
|
||||||
const doc = (
|
|
||||||
await mocksdk
|
|
||||||
.firestore()
|
|
||||||
.collection("users")
|
|
||||||
.doc(testuser.uid)
|
|
||||||
.collection("teams")
|
|
||||||
.doc("sync")
|
|
||||||
.get()
|
|
||||||
).data()
|
|
||||||
|
|
||||||
expect(doc).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
updatedOn: expect.any(Date),
|
|
||||||
author: expect.any(String),
|
|
||||||
author_name: expect.any(String),
|
|
||||||
author_image: expect.any(String),
|
|
||||||
team: expect.anything(),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("stores data on firestore with fields having proper values", async () => {
|
|
||||||
const fb = new FirebaseInstance(mocksdk)
|
|
||||||
|
|
||||||
signInUser()
|
|
||||||
|
|
||||||
await fb.writeTeams([])
|
|
||||||
|
|
||||||
const doc = (
|
|
||||||
await mocksdk
|
|
||||||
.firestore()
|
|
||||||
.collection("users")
|
|
||||||
.doc(testuser.uid)
|
|
||||||
.collection("teams")
|
|
||||||
.doc("sync")
|
|
||||||
.get()
|
|
||||||
).data()
|
|
||||||
|
|
||||||
expect(doc).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
updatedOn: expect.any(Date),
|
|
||||||
author: testuser.uid,
|
|
||||||
author_name: testuser.displayName,
|
|
||||||
author_image: testuser.photoURL,
|
|
||||||
team: expect.anything(),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ export class FirebaseInstance {
|
|||||||
this.currentHistory = []
|
this.currentHistory = []
|
||||||
this.currentCollections = []
|
this.currentCollections = []
|
||||||
this.currentEnvironments = []
|
this.currentEnvironments = []
|
||||||
this.currentTeams = []
|
|
||||||
|
|
||||||
this.app.auth().onAuthStateChanged((user) => {
|
this.app.auth().onAuthStateChanged((user) => {
|
||||||
if (user) {
|
if (user) {
|
||||||
@@ -121,19 +120,6 @@ export class FirebaseInstance {
|
|||||||
this.currentEnvironments = environments[0].environment
|
this.currentEnvironments = environments[0].environment
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
this.usersCollection
|
|
||||||
.doc(this.currentUser.uid)
|
|
||||||
.collection("teams")
|
|
||||||
.onSnapshot((teamsRef) => {
|
|
||||||
const teams = []
|
|
||||||
teamsRef.forEach((doc) => {
|
|
||||||
const team = doc.data()
|
|
||||||
team.id = doc.id
|
|
||||||
teams.push(team)
|
|
||||||
})
|
|
||||||
this.currentTeams = teams[0].team
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
this.currentUser = null
|
this.currentUser = null
|
||||||
}
|
}
|
||||||
@@ -302,24 +288,6 @@ export class FirebaseInstance {
|
|||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async writeTeams(team) {
|
|
||||||
const ev = {
|
|
||||||
updatedOn: new Date(),
|
|
||||||
author: this.currentUser.uid,
|
|
||||||
author_name: this.currentUser.displayName,
|
|
||||||
author_image: this.currentUser.photoURL,
|
|
||||||
team,
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.usersCollection.doc(this.currentUser.uid).collection("teams").doc("sync").set(ev)
|
|
||||||
} catch (e) {
|
|
||||||
console.error("error updating", ev, e)
|
|
||||||
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fb = new FirebaseInstance(firebase.initializeApp(firebaseConfig), authProviders)
|
export const fb = new FirebaseInstance(firebase.initializeApp(firebaseConfig), authProviders)
|
||||||
|
|||||||
107
nuxt.config.js
107
nuxt.config.js
@@ -1,5 +1,4 @@
|
|||||||
// Some helpful application constants.
|
// Common options
|
||||||
// TODO: Use these when rendering the pages (rather than just for head/meta tags...)
|
|
||||||
export const options = {
|
export const options = {
|
||||||
name: "Hoppscotch",
|
name: "Hoppscotch",
|
||||||
shortDescription: "A free, fast and beautiful API request builder",
|
shortDescription: "A free, fast and beautiful API request builder",
|
||||||
@@ -15,14 +14,20 @@ export const options = {
|
|||||||
twitter: "@liyasthomas",
|
twitter: "@liyasthomas",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
// Disable server-side rendering (https://go.nuxtjs.dev/ssr-mode)
|
||||||
ssr: false,
|
ssr: false,
|
||||||
|
|
||||||
|
// Target (https://go.nuxtjs.dev/config-target)
|
||||||
|
target: "static",
|
||||||
|
|
||||||
|
// Default: localhost
|
||||||
server: {
|
server: {
|
||||||
host: "0.0.0.0", // default: localhost
|
host: "0.0.0.0",
|
||||||
},
|
},
|
||||||
/*
|
|
||||||
** Headers of the page
|
// Global page headers (https://go.nuxtjs.dev/config-head)
|
||||||
*/
|
|
||||||
head: {
|
head: {
|
||||||
title: `${options.name} • ${options.shortDescription}`,
|
title: `${options.name} • ${options.shortDescription}`,
|
||||||
meta: [
|
meta: [
|
||||||
@@ -81,66 +86,60 @@ export default {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
/*
|
|
||||||
** Customize the progress-bar color
|
// Customize the progress-bar color (https://nuxtjs.org/api/configuration-loading/#customizing-the-progress-bar)
|
||||||
*/
|
|
||||||
loading: {
|
loading: {
|
||||||
color: options.loading.color,
|
color: options.loading.color,
|
||||||
continuous: true,
|
continuous: true,
|
||||||
},
|
},
|
||||||
/*
|
|
||||||
** Customize the loading indicator
|
// Customize the loading indicator (https://nuxtjs.org/api/configuration-loading-indicator)
|
||||||
*/
|
|
||||||
loadingIndicator: {
|
loadingIndicator: {
|
||||||
name: "pulse",
|
name: "pulse",
|
||||||
color: options.loading.color,
|
color: options.loading.color,
|
||||||
background: options.loading.background,
|
background: options.loading.background,
|
||||||
},
|
},
|
||||||
/*
|
|
||||||
** Global CSS
|
// Global CSS (https://go.nuxtjs.dev/config-css)
|
||||||
*/
|
|
||||||
css: ["~/assets/scss/styles.scss", "~/assets/scss/themes.scss", "~/assets/scss/fonts.scss"],
|
css: ["~/assets/scss/styles.scss", "~/assets/scss/themes.scss", "~/assets/scss/fonts.scss"],
|
||||||
/*
|
|
||||||
** Plugins to load before mounting the App
|
// Plugins to run before rendering page (https://go.nuxtjs.dev/config-plugins)
|
||||||
*/
|
|
||||||
plugins: ["~/plugins/vuex-persist", "~/plugins/v-tooltip"],
|
plugins: ["~/plugins/vuex-persist", "~/plugins/v-tooltip"],
|
||||||
/*
|
|
||||||
** Auto import components
|
// Auto import components (https://go.nuxtjs.dev/config-components)
|
||||||
** See https://nuxtjs.org/api/configuration-components
|
|
||||||
*/
|
|
||||||
components: true,
|
components: true,
|
||||||
/*
|
|
||||||
** Nuxt.js dev-modules
|
// Modules for dev and build (recommended) (https://go.nuxtjs.dev/config-modules)
|
||||||
*/
|
|
||||||
buildModules: [
|
buildModules: [
|
||||||
// https://pwa.nuxtjs.org
|
// https://github.com/nuxt-community/pwa-module
|
||||||
"@nuxtjs/pwa",
|
"@nuxtjs/pwa",
|
||||||
// Doc: https://github.com/nuxt-community/analytics-module
|
// https://github.com/nuxt-community/analytics-module
|
||||||
"@nuxtjs/google-analytics",
|
"@nuxtjs/google-analytics",
|
||||||
// Doc: https://github.com/nuxt-community/gtm-module
|
// https://github.com/nuxt-community/gtm-module
|
||||||
"@nuxtjs/gtm",
|
"@nuxtjs/gtm",
|
||||||
// Doc: https://github.com/nuxt-community/svg-module
|
// https://github.com/nuxt-community/svg-module
|
||||||
"@nuxtjs/svg",
|
"@nuxtjs/svg",
|
||||||
// Doc: https://tailwindcss.nuxtjs.org
|
// https://github.com/nuxt-community/nuxt-tailwindcss
|
||||||
"@nuxtjs/tailwindcss",
|
"@nuxtjs/tailwindcss",
|
||||||
// Doc: https://color-mode.nuxtjs.org
|
// https://github.com/nuxt-community/color-mode-module
|
||||||
"@nuxtjs/color-mode",
|
"@nuxtjs/color-mode",
|
||||||
],
|
],
|
||||||
/*
|
|
||||||
** Nuxt.js modules
|
// Modules (https://go.nuxtjs.dev/config-modules)
|
||||||
*/
|
|
||||||
modules: [
|
modules: [
|
||||||
// https://axios.nuxtjs.org
|
// https://github.com/nuxt-community/axios-module
|
||||||
"@nuxtjs/axios",
|
"@nuxtjs/axios",
|
||||||
// https://github.com/nuxt-community/modules/tree/master/packages/toast
|
// https://github.com/nuxt-community/modules/tree/master/packages/toast
|
||||||
"@nuxtjs/toast",
|
"@nuxtjs/toast",
|
||||||
// Doc: https://github.com/nuxt-community/nuxt-i18n
|
// https://github.com/nuxt-community/i18n-module
|
||||||
"nuxt-i18n",
|
"nuxt-i18n",
|
||||||
// Doc: https://github.com/nuxt-community/robots-module
|
// https://github.com/nuxt-community/robots-module
|
||||||
"@nuxtjs/robots",
|
"@nuxtjs/robots",
|
||||||
// Doc: https://github.com/nuxt-community/sitemap-module
|
// https://github.com/nuxt-community/sitemap-module
|
||||||
"@nuxtjs/sitemap",
|
"@nuxtjs/sitemap",
|
||||||
],
|
],
|
||||||
|
|
||||||
|
// PWA module configuration (https://pwa.nuxtjs.org/setup)
|
||||||
pwa: {
|
pwa: {
|
||||||
meta: {
|
meta: {
|
||||||
ogHost: process.env.BASE_URL,
|
ogHost: process.env.BASE_URL,
|
||||||
@@ -160,32 +159,46 @@ export default {
|
|||||||
},
|
},
|
||||||
workbox: false,
|
workbox: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Toast module configuration (https://github.com/nuxt-community/modules/tree/master/packages/toast)
|
||||||
toast: {
|
toast: {
|
||||||
position: "bottom-center",
|
position: "bottom-center",
|
||||||
duration: 3000,
|
duration: 3000,
|
||||||
theme: "bubble",
|
theme: "bubble",
|
||||||
keepOnHover: true,
|
keepOnHover: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Google Analytics module configuration (https://github.com/nuxt-community/analytics-module)
|
||||||
googleAnalytics: {
|
googleAnalytics: {
|
||||||
id: process.env.GA_ID,
|
id: process.env.GA_ID,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Google Tag Manager module configuration (https://github.com/nuxt-community/gtm-module)
|
||||||
gtm: {
|
gtm: {
|
||||||
id: process.env.GTM_ID,
|
id: process.env.GTM_ID,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Sitemap module configuration (https://github.com/nuxt-community/sitemap-module)
|
||||||
sitemap: {
|
sitemap: {
|
||||||
hostname: process.env.BASE_URL || "https://hoppscotch.io/",
|
hostname: process.env.BASE_URL || "https://hoppscotch.io/",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Robots module configuration (https://github.com/nuxt-community/robots-module)
|
||||||
robots: {
|
robots: {
|
||||||
UserAgent: "*",
|
UserAgent: "*",
|
||||||
Disallow: "",
|
Disallow: "",
|
||||||
Allow: "/",
|
Allow: "/",
|
||||||
Sitemap: `${process.env.BASE_URL}sitemap.xml`,
|
Sitemap: `${process.env.BASE_URL}sitemap.xml`,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Color Mode module configuration (https://github.com/nuxt-community/color-mode-module)
|
||||||
colorMode: {
|
colorMode: {
|
||||||
classSuffix: "",
|
classSuffix: "",
|
||||||
preference: "dark",
|
preference: "dark",
|
||||||
fallback: "dark",
|
fallback: "dark",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// i18n module configuration (https://github.com/nuxt-community/i18n-module)
|
||||||
i18n: {
|
i18n: {
|
||||||
locales: [
|
locales: [
|
||||||
{
|
{
|
||||||
@@ -296,13 +309,10 @@ export default {
|
|||||||
fallbackLocale: "en",
|
fallbackLocale: "en",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
/*
|
|
||||||
** Build configuration
|
// Build Configuration (https://go.nuxtjs.dev/config-build)
|
||||||
*/
|
|
||||||
build: {
|
build: {
|
||||||
/*
|
// You can extend webpack config here
|
||||||
** You can extend webpack config here
|
|
||||||
*/
|
|
||||||
extend(config, ctx) {
|
extend(config, ctx) {
|
||||||
// Sets webpack's mode to development if `isDev` is true.
|
// Sets webpack's mode to development if `isDev` is true.
|
||||||
if (ctx.isDev) {
|
if (ctx.isDev) {
|
||||||
@@ -316,17 +326,20 @@ export default {
|
|||||||
cache: true,
|
cache: true,
|
||||||
// hardSource: true,
|
// hardSource: true,
|
||||||
},
|
},
|
||||||
/*
|
|
||||||
** Generate configuration
|
// Generate configuration (https://nuxtjs.org/api/configuration-generate)
|
||||||
*/
|
|
||||||
generate: {
|
generate: {
|
||||||
fallback: true,
|
fallback: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Public runtime configuration (https://nuxtjs.org/guide/runtime-config)
|
||||||
publicRuntimeConfig: {
|
publicRuntimeConfig: {
|
||||||
GA_ID: process.env.GA_ID || "UA-61422507-4",
|
GA_ID: process.env.GA_ID || "UA-61422507-4",
|
||||||
GTM_ID: process.env.GTM_ID || "GTM-NMKVBMV",
|
GTM_ID: process.env.GTM_ID || "GTM-NMKVBMV",
|
||||||
BASE_URL: process.env.BASE_URL || "https://hoppscotch.io/",
|
BASE_URL: process.env.BASE_URL || "https://hoppscotch.io/",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Private runtime configuration (https://nuxtjs.org/guide/runtime-config)
|
||||||
privateRuntimeConfig: {
|
privateRuntimeConfig: {
|
||||||
API_KEY: process.env.API_KEY,
|
API_KEY: process.env.API_KEY,
|
||||||
AUTH_DOMAIN: process.env.AUTH_DOMAIN,
|
AUTH_DOMAIN: process.env.AUTH_DOMAIN,
|
||||||
|
|||||||
@@ -11,15 +11,19 @@
|
|||||||
type="url"
|
type="url"
|
||||||
v-model="url"
|
v-model="url"
|
||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
@keyup.enter="getSchema()"
|
@keyup.enter="onPollSchemaClick()"
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
<div>
|
<div>
|
||||||
<li>
|
<li>
|
||||||
<label for="get" class="hide-on-small-screen"> </label>
|
<label for="get" class="hide-on-small-screen"> </label>
|
||||||
<button id="get" name="get" @click="getSchema">
|
<button id="get" name="get" @click="onPollSchemaClick">
|
||||||
{{ $t("get_schema") }}
|
{{ !isPollingSchema ? $t("connect") : $t("disconnect") }}
|
||||||
<span><i class="material-icons">send</i></span>
|
<span
|
||||||
|
><i class="material-icons">{{
|
||||||
|
!isPollingSchema ? "sync" : "sync_disabled"
|
||||||
|
}}</i></span
|
||||||
|
>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
@@ -356,6 +360,8 @@ export default {
|
|||||||
expandResponse: false,
|
expandResponse: false,
|
||||||
responseBodyMaxLines: 16,
|
responseBodyMaxLines: 16,
|
||||||
graphqlFieldsFilterText: undefined,
|
graphqlFieldsFilterText: undefined,
|
||||||
|
isPollingSchema: false,
|
||||||
|
timeoutSubscription: null,
|
||||||
|
|
||||||
settings: {
|
settings: {
|
||||||
SCROLL_INTO_ENABLED:
|
SCROLL_INTO_ENABLED:
|
||||||
@@ -455,6 +461,12 @@ export default {
|
|||||||
this.getDocsFromSchema(gqlSchema)
|
this.getDocsFromSchema(gqlSchema)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
beforeRouteLeave(_to, _from, next) {
|
||||||
|
this.isPollingSchema = false
|
||||||
|
if (this.timeoutSubscription) clearTimeout(this.timeoutSubscription)
|
||||||
|
|
||||||
|
next()
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
isGqlTypeHighlighted({ gqlType }) {
|
isGqlTypeHighlighted({ gqlType }) {
|
||||||
if (!this.graphqlFieldsFilterText) return false
|
if (!this.graphqlFieldsFilterText) return false
|
||||||
@@ -471,12 +483,12 @@ export default {
|
|||||||
|
|
||||||
if (!fields || fields.length === 0) return []
|
if (!fields || fields.length === 0) return []
|
||||||
|
|
||||||
return fields.filter((field) => {
|
return fields.filter((field) =>
|
||||||
return this.isTextFoundInGraphqlFieldObject({
|
this.isTextFoundInGraphqlFieldObject({
|
||||||
text: this.graphqlFieldsFilterText,
|
text: this.graphqlFieldsFilterText,
|
||||||
graphqlFieldObject: field,
|
graphqlFieldObject: field,
|
||||||
})
|
})
|
||||||
})
|
)
|
||||||
},
|
},
|
||||||
isTextFoundInGraphqlFieldObject({ text, graphqlFieldObject }) {
|
isTextFoundInGraphqlFieldObject({ text, graphqlFieldObject }) {
|
||||||
const normalizedText = text.toLowerCase()
|
const normalizedText = text.toLowerCase()
|
||||||
@@ -491,9 +503,9 @@ export default {
|
|||||||
getFilteredGraphqlFields({ filterText, fields }) {
|
getFilteredGraphqlFields({ filterText, fields }) {
|
||||||
if (!filterText) return fields
|
if (!filterText) return fields
|
||||||
|
|
||||||
return fields.filter((field) => {
|
return fields.filter((field) =>
|
||||||
return this.isTextFoundInGraphqlFieldObject({ text: filterText, graphqlFieldObject: field })
|
this.isTextFoundInGraphqlFieldObject({ text: filterText, graphqlFieldObject: field })
|
||||||
})
|
)
|
||||||
},
|
},
|
||||||
getFilteredGraphqlTypes({ filterText, types }) {
|
getFilteredGraphqlTypes({ filterText, types }) {
|
||||||
if (!filterText) return types
|
if (!filterText) return types
|
||||||
@@ -509,12 +521,11 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isFilterTextMatchingAtLeastOneField = Object.values(type._fields || {}).some(
|
const isFilterTextMatchingAtLeastOneField = Object.values(type._fields || {}).some(
|
||||||
(field) => {
|
(field) =>
|
||||||
return this.isTextFoundInGraphqlFieldObject({
|
this.isTextFoundInGraphqlFieldObject({
|
||||||
text: filterText,
|
text: filterText,
|
||||||
graphqlFieldObject: field,
|
graphqlFieldObject: field,
|
||||||
})
|
})
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return isFilterTextMatchingAtLeastOneField
|
return isFilterTextMatchingAtLeastOneField
|
||||||
@@ -682,6 +693,79 @@ export default {
|
|||||||
}
|
}
|
||||||
this.gqlTypes = types
|
this.gqlTypes = types
|
||||||
},
|
},
|
||||||
|
async onPollSchemaClick() {
|
||||||
|
if (this.isPollingSchema) {
|
||||||
|
this.isPollingSchema = false
|
||||||
|
} else {
|
||||||
|
this.isPollingSchema = true
|
||||||
|
await this.getSchema()
|
||||||
|
|
||||||
|
this.pollSchema()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async pollSchema() {
|
||||||
|
if (!this.isPollingSchema) return
|
||||||
|
|
||||||
|
this.$nuxt.$loading.start()
|
||||||
|
|
||||||
|
try {
|
||||||
|
const query = JSON.stringify({
|
||||||
|
query: gql.getIntrospectionQuery(),
|
||||||
|
})
|
||||||
|
|
||||||
|
let headers = {}
|
||||||
|
this.headers.forEach(({ key, value }) => {
|
||||||
|
headers[key] = value
|
||||||
|
})
|
||||||
|
|
||||||
|
const reqOptions = {
|
||||||
|
method: "post",
|
||||||
|
url: this.url,
|
||||||
|
headers: {
|
||||||
|
...headers,
|
||||||
|
"content-type": "application/json",
|
||||||
|
},
|
||||||
|
data: query,
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await sendNetworkRequest(reqOptions, this.$store)
|
||||||
|
|
||||||
|
// HACK : Temporary trailing null character issue from the extension fix
|
||||||
|
const response = new TextDecoder("utf-8").decode(data.data).replace(/\0+$/, "")
|
||||||
|
const introspectResponse = JSON.parse(response)
|
||||||
|
|
||||||
|
const schema = gql.buildClientSchema(introspectResponse.data)
|
||||||
|
|
||||||
|
this.$store.commit("setGQLState", {
|
||||||
|
value: JSON.stringify(introspectResponse.data),
|
||||||
|
attribute: "schemaIntrospection",
|
||||||
|
})
|
||||||
|
|
||||||
|
this.schema = gql.printSchema(schema, {
|
||||||
|
commentDescriptions: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
this.getDocsFromSchema(schema)
|
||||||
|
|
||||||
|
this.$refs.queryEditor.setValidationSchema(schema)
|
||||||
|
this.$nuxt.$loading.finish()
|
||||||
|
} catch (error) {
|
||||||
|
this.$nuxt.$loading.finish()
|
||||||
|
|
||||||
|
this.schema = `${error}. ${this.$t("check_console_details")}`
|
||||||
|
this.$toast.error(
|
||||||
|
`${this.$t("graphql_introspect_failed")} ${this.$t("check_graphql_valid")}`,
|
||||||
|
{
|
||||||
|
icon: "error",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
console.log("Error", error)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$nuxt.$loading.finish()
|
||||||
|
|
||||||
|
if (this.isPollingSchema) this.timeoutSubscription = setTimeout(this.pollSchema, 7000)
|
||||||
|
},
|
||||||
async getSchema() {
|
async getSchema() {
|
||||||
const startTime = Date.now()
|
const startTime = Date.now()
|
||||||
|
|
||||||
|
|||||||
@@ -1361,7 +1361,7 @@ export default {
|
|||||||
: true,
|
: true,
|
||||||
},
|
},
|
||||||
currentMethodIndex: 0,
|
currentMethodIndex: 0,
|
||||||
codegens: codegens,
|
codegens,
|
||||||
methodMenuItems: [
|
methodMenuItems: [
|
||||||
"GET",
|
"GET",
|
||||||
"HEAD",
|
"HEAD",
|
||||||
@@ -1416,7 +1416,7 @@ export default {
|
|||||||
this.setRouteQueryState()
|
this.setRouteQueryState()
|
||||||
},
|
},
|
||||||
params: {
|
params: {
|
||||||
handler: function (newValue) {
|
handler(newValue) {
|
||||||
if (!this.paramsWatchEnabled) {
|
if (!this.paramsWatchEnabled) {
|
||||||
this.paramsWatchEnabled = true
|
this.paramsWatchEnabled = true
|
||||||
return
|
return
|
||||||
@@ -1474,7 +1474,7 @@ export default {
|
|||||||
? "application/json"
|
? "application/json"
|
||||||
: ""
|
: ""
|
||||||
},
|
},
|
||||||
preRequestScript: function (val, oldVal) {
|
preRequestScript(val, oldVal) {
|
||||||
this.uri = this.uri
|
this.uri = this.uri
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1826,7 +1826,7 @@ export default {
|
|||||||
httpUser: this.httpUser,
|
httpUser: this.httpUser,
|
||||||
httpPassword: this.httpPassword,
|
httpPassword: this.httpPassword,
|
||||||
bearerToken: this.bearerToken,
|
bearerToken: this.bearerToken,
|
||||||
headers: headers,
|
headers,
|
||||||
rawInput: this.rawInput,
|
rawInput: this.rawInput,
|
||||||
rawParams: this.rawParams,
|
rawParams: this.rawParams,
|
||||||
rawRequestBody: this.rawRequestBody,
|
rawRequestBody: this.rawRequestBody,
|
||||||
@@ -1860,7 +1860,7 @@ export default {
|
|||||||
if (env.name === "Globals" || env.name === "globals") {
|
if (env.name === "Globals" || env.name === "globals") {
|
||||||
preRequestScriptString += this.useSelectedEnvironment({
|
preRequestScriptString += this.useSelectedEnvironment({
|
||||||
environment: env,
|
environment: env,
|
||||||
environments: environments,
|
environments,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2390,6 +2390,7 @@ export default {
|
|||||||
switch (name) {
|
switch (name) {
|
||||||
case "bodyParams":
|
case "bodyParams":
|
||||||
this.bodyParams = []
|
this.bodyParams = []
|
||||||
|
this.files = []
|
||||||
break
|
break
|
||||||
case "rawParams":
|
case "rawParams":
|
||||||
this.rawParams = "{}"
|
this.rawParams = "{}"
|
||||||
@@ -2518,7 +2519,6 @@ export default {
|
|||||||
icon: "attach_file",
|
icon: "attach_file",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.$refs.attachment.value = ""
|
|
||||||
},
|
},
|
||||||
uploadPayload() {
|
uploadPayload() {
|
||||||
this.rawInput = true
|
this.rawInput = true
|
||||||
|
|||||||
@@ -257,9 +257,9 @@ export default {
|
|||||||
watch: {
|
watch: {
|
||||||
proxySettings: {
|
proxySettings: {
|
||||||
deep: true,
|
deep: true,
|
||||||
handler(value) {
|
handler({ url, key }) {
|
||||||
this.applySetting("PROXY_URL", value.url)
|
this.applySetting("PROXY_URL", url)
|
||||||
this.applySetting("PROXY_KEY", value.key)
|
this.applySetting("PROXY_KEY", key)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -205,86 +205,70 @@ export const mutations = {
|
|||||||
collections[collectionIndex] = collection
|
collections[collectionIndex] = collection
|
||||||
},
|
},
|
||||||
|
|
||||||
addNewFolder({ collections }, payload) {
|
addFolder({ collections }, payload) {
|
||||||
const { collectionIndex, folder } = payload
|
const { name, folder } = payload
|
||||||
collections[collectionIndex].folders.push({
|
|
||||||
name: "",
|
const newFolder = {
|
||||||
|
name: name,
|
||||||
requests: [],
|
requests: [],
|
||||||
...folder,
|
folders: [],
|
||||||
})
|
}
|
||||||
|
folder.folders.push(newFolder)
|
||||||
},
|
},
|
||||||
|
|
||||||
editFolder({ collections }, payload) {
|
editFolder({ collections }, payload) {
|
||||||
const { collectionIndex, folder, folderIndex } = payload
|
const { collectionIndex, folder, folderIndex, folderName } = payload
|
||||||
Vue.set(collections[collectionIndex].folders, folderIndex, folder)
|
const collection = collections[collectionIndex]
|
||||||
|
|
||||||
|
let parentFolder = findFolder(folderName, collection, true)
|
||||||
|
if (parentFolder && parentFolder.folders) {
|
||||||
|
Vue.set(parentFolder.folders, folderIndex, folder)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
removeFolder({ collections }, payload) {
|
removeFolder({ collections }, payload) {
|
||||||
const { collectionIndex, folderIndex } = payload
|
const { collectionIndex, folderIndex, folderName } = payload
|
||||||
collections[collectionIndex].folders.splice(folderIndex, 1)
|
const collection = collections[collectionIndex]
|
||||||
},
|
|
||||||
|
|
||||||
addRequest({ collections }, payload) {
|
let parentFolder = findFolder(folderName, collection, true)
|
||||||
const { request } = payload
|
if (parentFolder && parentFolder.folders) {
|
||||||
|
parentFolder.folders.splice(folderIndex, 1)
|
||||||
// Request that is directly attached to collection
|
|
||||||
if (request.folder === -1) {
|
|
||||||
collections[request.collection].requests.push(request)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
collections[request.collection].folders[request.folder].requests.push(request)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
editRequest({ collections }, payload) {
|
editRequest({ collections }, payload) {
|
||||||
const {
|
const {
|
||||||
requestOldCollectionIndex,
|
requestCollectionIndex,
|
||||||
requestOldFolderIndex,
|
requestFolderName,
|
||||||
requestOldIndex,
|
requestFolderIndex,
|
||||||
requestNew,
|
requestNew,
|
||||||
requestNewCollectionIndex,
|
requestIndex,
|
||||||
requestNewFolderIndex,
|
|
||||||
} = payload
|
} = payload
|
||||||
|
|
||||||
const changedCollection = requestOldCollectionIndex !== requestNewCollectionIndex
|
let collection = collections[requestCollectionIndex]
|
||||||
const changedFolder = requestOldFolderIndex !== requestNewFolderIndex
|
|
||||||
const changedPlace = changedCollection || changedFolder
|
|
||||||
|
|
||||||
// set new request
|
if (requestFolderIndex === -1) {
|
||||||
if (requestNewFolderIndex !== undefined) {
|
Vue.set(collection.requests, requestIndex, requestNew)
|
||||||
Vue.set(
|
return
|
||||||
collections[requestNewCollectionIndex].folders[requestNewFolderIndex].requests,
|
|
||||||
requestOldIndex,
|
|
||||||
requestNew
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Vue.set(collections[requestNewCollectionIndex].requests, requestOldIndex, requestNew)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove old request
|
let folder = findFolder(requestFolderName, collection, false)
|
||||||
if (changedPlace) {
|
Vue.set(folder.requests, requestIndex, requestNew)
|
||||||
if (requestOldFolderIndex !== undefined) {
|
|
||||||
collections[requestOldCollectionIndex].folders[requestOldFolderIndex].requests.splice(
|
|
||||||
requestOldIndex,
|
|
||||||
1
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
collections[requestOldCollectionIndex].requests.splice(requestOldIndex, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
saveRequestAs({ collections }, payload) {
|
saveRequestAs({ collections }, payload) {
|
||||||
const { request, collectionIndex, folderIndex, requestIndex } = payload
|
const { request, collectionIndex, folderName, requestIndex } = payload
|
||||||
|
|
||||||
const specifiedCollection = collectionIndex !== undefined
|
const specifiedCollection = collectionIndex !== undefined
|
||||||
const specifiedFolder = folderIndex !== undefined
|
const specifiedFolder = folderName !== undefined
|
||||||
const specifiedRequest = requestIndex !== undefined
|
const specifiedRequest = requestIndex !== undefined
|
||||||
|
|
||||||
if (specifiedCollection && specifiedFolder && specifiedRequest) {
|
if (specifiedCollection && specifiedFolder && specifiedRequest) {
|
||||||
Vue.set(collections[collectionIndex].folders[folderIndex].requests, requestIndex, request)
|
const folder = findFolder(folderName, collections[collectionIndex])
|
||||||
|
Vue.set(folder.requests, requestIndex, request)
|
||||||
} else if (specifiedCollection && specifiedFolder && !specifiedRequest) {
|
} else if (specifiedCollection && specifiedFolder && !specifiedRequest) {
|
||||||
const requests = collections[collectionIndex].folders[folderIndex].requests
|
const folder = findFolder(folderName, collections[collectionIndex])
|
||||||
|
const requests = folder.requests
|
||||||
const lastRequestIndex = requests.length - 1
|
const lastRequestIndex = requests.length - 1
|
||||||
Vue.set(requests, lastRequestIndex + 1, request)
|
Vue.set(requests, lastRequestIndex + 1, request)
|
||||||
} else if (specifiedCollection && !specifiedFolder && specifiedRequest) {
|
} else if (specifiedCollection && !specifiedFolder && specifiedRequest) {
|
||||||
@@ -297,61 +281,53 @@ export const mutations = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
saveRequest({ collections }, payload) {
|
|
||||||
const { request } = payload
|
|
||||||
|
|
||||||
// Remove the old request from collection
|
|
||||||
if (
|
|
||||||
Object.prototype.hasOwnProperty.call(request, "oldCollection") &&
|
|
||||||
request.oldCollection > -1
|
|
||||||
) {
|
|
||||||
const folder =
|
|
||||||
Object.prototype.hasOwnProperty.call(request, "oldFolder") && request.oldFolder >= -1
|
|
||||||
? request.oldFolder
|
|
||||||
: request.folder
|
|
||||||
if (folder > -1) {
|
|
||||||
collections[request.oldCollection].folders[folder].requests.splice(request.requestIndex, 1)
|
|
||||||
} else {
|
|
||||||
collections[request.oldCollection].requests.splice(request.requestIndex, 1)
|
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
Object.prototype.hasOwnProperty.call(request, "oldFolder") &&
|
|
||||||
request.oldFolder !== -1
|
|
||||||
) {
|
|
||||||
collections[request.collection].folders[folder].requests.splice(request.requestIndex, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
delete request.oldCollection
|
|
||||||
delete request.oldFolder
|
|
||||||
|
|
||||||
// Request that is directly attached to collection
|
|
||||||
if (request.folder === -1) {
|
|
||||||
Vue.set(collections[request.collection].requests, request.requestIndex, request)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Vue.set(
|
|
||||||
collections[request.collection].folders[request.folder].requests,
|
|
||||||
request.requestIndex,
|
|
||||||
request
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|
|
||||||
removeRequest({ collections }, payload) {
|
removeRequest({ collections }, payload) {
|
||||||
const { collectionIndex, folderIndex, requestIndex } = payload
|
const { collectionIndex, folderName, requestIndex } = payload
|
||||||
|
let collection = collections[collectionIndex]
|
||||||
|
|
||||||
// Request that is directly attached to collection
|
if (collection.name === folderName) {
|
||||||
if (folderIndex === -1) {
|
collection.requests.splice(requestIndex, 1)
|
||||||
collections[collectionIndex].requests.splice(requestIndex, 1)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
let folder = findFolder(folderName, collection, false)
|
||||||
|
|
||||||
collections[collectionIndex].folders[folderIndex].requests.splice(requestIndex, 1)
|
if (folder) {
|
||||||
|
folder.requests.splice(requestIndex, 1)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
selectRequest(state, { request }) {
|
selectRequest(state, { request }) {
|
||||||
state.selectedRequest = Object.assign({}, request)
|
state.selectedRequest = Object.assign({}, request)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
moveRequest({ collections }, payload) {
|
||||||
|
const {
|
||||||
|
oldCollectionIndex,
|
||||||
|
newCollectionIndex,
|
||||||
|
newFolderIndex,
|
||||||
|
newFolderName,
|
||||||
|
oldFolderName,
|
||||||
|
requestIndex,
|
||||||
|
} = payload
|
||||||
|
|
||||||
|
const isCollection = newFolderIndex === -1
|
||||||
|
const oldCollection = collections[oldCollectionIndex]
|
||||||
|
const newCollection = collections[newCollectionIndex]
|
||||||
|
const request = findRequest(oldFolderName, oldCollection, requestIndex)
|
||||||
|
|
||||||
|
if (isCollection) {
|
||||||
|
newCollection.requests.push(request)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isCollection) {
|
||||||
|
const folder = findFolder(newFolderName, newCollection, false)
|
||||||
|
if (folder) {
|
||||||
|
folder.requests.push(request)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
function testValue(myValue) {
|
function testValue(myValue) {
|
||||||
@@ -362,3 +338,45 @@ function testValue(myValue) {
|
|||||||
return myValue
|
return myValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findRequest(folderName, currentFolder, requestIndex) {
|
||||||
|
let selectedFolder, result
|
||||||
|
|
||||||
|
if (folderName === currentFolder.name) {
|
||||||
|
let request = currentFolder.requests[requestIndex]
|
||||||
|
currentFolder.requests.splice(requestIndex, 1)
|
||||||
|
return request
|
||||||
|
} else {
|
||||||
|
for (let i = 0; i < currentFolder.folders.length; i += 1) {
|
||||||
|
selectedFolder = currentFolder.folders[i]
|
||||||
|
|
||||||
|
result = findRequest(folderName, selectedFolder, requestIndex)
|
||||||
|
|
||||||
|
if (result !== false) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function findFolder(folderName, currentFolder, returnParent, parentFolder) {
|
||||||
|
let selectedFolder, result
|
||||||
|
|
||||||
|
if (folderName === currentFolder.name && returnParent) {
|
||||||
|
return parentFolder
|
||||||
|
} else if (folderName === currentFolder.name && !returnParent) {
|
||||||
|
return currentFolder
|
||||||
|
} else {
|
||||||
|
for (let i = 0; i < currentFolder.folders.length; i++) {
|
||||||
|
selectedFolder = currentFolder.folders[i]
|
||||||
|
|
||||||
|
result = findFolder(folderName, selectedFolder, returnParent, currentFolder)
|
||||||
|
|
||||||
|
if (result !== false) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user