Refactor: Modularize home page (#1372)

* Move HTTP headers section to component

* Move import cURL modal to component

* Move Notes, OAuth token modal to seperate components

* Fix deepcode analysis

* Move parameters section to seperate component

* Move codegen modal to component

* ES6
This commit is contained in:
Liyas Thomas
2020-12-11 05:59:29 +05:30
committed by GitHub
parent a95d37d610
commit 1e6773deb5
19 changed files with 660 additions and 500 deletions

View File

@@ -16,16 +16,14 @@ const regex = { ws, sse, socketio }
// type = ws/sse/socketio // type = ws/sse/socketio
async function validator(type, url) { async function validator(type, url) {
console.time("validator " + url) console.time(`validator ${url}`)
const [res1, res2] = await Promise.all([regex[type][0].test(url), regex[type][1].test(url)]) const [res1, res2] = await Promise.all([regex[type][0].test(url), regex[type][1].test(url)])
console.timeEnd("validator " + url) console.timeEnd(`validator ${url}`)
return res1 || res2 return res1 || res2
} }
onmessage = async function (event) { onmessage = async ({ data }) => {
var { type, url } = event.data const { type, url } = data
const result = await validator(type, url) const result = await validator(type, url)
postMessage({ type, url, result }) postMessage({ type, url, result })
} }

View File

@@ -149,11 +149,11 @@ export default {
}, },
} }
) )
.then((response) => { .then(({ html_url }) => {
this.$toast.success(this.$t("gist_created"), { this.$toast.success(this.$t("gist_created"), {
icon: "done", icon: "done",
}) })
window.open(response.html_url) window.open(html_url)
}) })
.catch((error) => { .catch((error) => {
this.$toast.error(this.$t("something_went_wrong"), { this.$toast.error(this.$t("something_went_wrong"), {
@@ -171,8 +171,8 @@ export default {
Accept: "application/vnd.github.v3+json", Accept: "application/vnd.github.v3+json",
}, },
}) })
.then((response) => { .then(({ files }) => {
let collections = JSON.parse(Object.values(response.files)[0].content) let collections = JSON.parse(Object.values(files)[0].content)
this.$store.commit("postwoman/replaceCollections", collections) this.$store.commit("postwoman/replaceCollections", collections)
this.fileImported() this.fileImported()
this.syncToFBCollections() this.syncToFBCollections()

View File

@@ -188,7 +188,6 @@ export default {
}, },
hideModal() { hideModal() {
this.$emit("hide-modal") this.$emit("hide-modal")
this.$emit("hide-model") // for backward compatibility // TODO: use fixed event
}, },
}, },
} }

View File

@@ -149,11 +149,11 @@ export default {
}, },
} }
) )
.then((response) => { .then(({ html_url }) => {
this.$toast.success(this.$t("gist_created"), { this.$toast.success(this.$t("gist_created"), {
icon: "done", icon: "done",
}) })
window.open(response.html_url) window.open(html_url)
}) })
.catch((error) => { .catch((error) => {
this.$toast.error(this.$t("something_went_wrong"), { this.$toast.error(this.$t("something_went_wrong"), {
@@ -171,8 +171,8 @@ export default {
Accept: "application/vnd.github.v3+json", Accept: "application/vnd.github.v3+json",
}, },
}) })
.then((response) => { .then(({ files }) => {
let environments = JSON.parse(Object.values(response.files)[0].content) let environments = JSON.parse(Object.values(files)[0].content)
this.$store.commit("postwoman/replaceEnvironments", environments) this.$store.commit("postwoman/replaceEnvironments", environments)
this.fileImported() this.fileImported()
this.syncToFBEnvironments() this.syncToFBEnvironments()

View File

@@ -0,0 +1,118 @@
<template>
<modal v-if="show" @close="hideModal">
<div slot="header">
<ul>
<li>
<div class="row-wrapper">
<h3 class="title">{{ $t("generate_code") }}</h3>
<div>
<button class="icon" @click="hideModal">
<i class="material-icons">close</i>
</button>
</div>
</div>
</li>
</ul>
</div>
<div slot="body">
<ul>
<li>
<label for="requestType">{{ $t("request_type") }}</label>
<span class="select-wrapper">
<v-popover>
<pre v-if="requestType">{{ codegens.find((x) => x.id === requestType).name }}</pre>
<input
v-else
id="requestType"
v-model="requestType"
:placeholder="$t('choose_language')"
class="cursor-pointer"
readonly
autofocus
/>
<template slot="popover">
<div v-for="gen in codegens" :key="gen.id">
<button class="icon" @click="requestType = gen.id" v-close-popover>
{{ gen.name }}
</button>
</div>
</template>
</v-popover>
</span>
</li>
</ul>
<ul>
<li>
<div class="row-wrapper">
<label for="generatedCode">{{ $t("generated_code") }}</label>
<div>
<button
class="icon"
@click="copyRequestCode"
id="copyRequestCode"
ref="copyRequestCode"
v-tooltip="$t('copy_code')"
>
<i class="material-icons">content_copy</i>
</button>
</div>
</div>
<textarea
id="generatedCode"
ref="generatedCode"
name="generatedCode"
rows="8"
v-model="requestCode"
readonly
></textarea>
</li>
</ul>
</div>
</modal>
</template>
<script>
import { codegens } from "~/helpers/codegen/codegen"
export default {
props: {
show: Boolean,
requestCode: String,
requestTypeProp: { type: String, default: "" },
},
data() {
return {
codegens,
copyButton: '<i class="material-icons">content_copy</i>',
doneButton: '<i class="material-icons">done</i>',
}
},
computed: {
requestType: {
get() {
return this.requestTypeProp
},
set(val) {
this.$emit("set-request-type", val)
},
},
},
methods: {
hideModal() {
this.$emit("hide-modal")
},
handleImport() {
this.$emit("handle-import")
},
copyRequestCode() {
this.$refs.copyRequestCode.innerHTML = this.doneButton
this.$toast.success(this.$t("copied_to_clipboard"), {
icon: "done",
})
this.$refs.generatedCode.select()
document.execCommand("copy")
setTimeout(() => (this.$refs.copyRequestCode.innerHTML = this.copyButton), 1000)
},
},
}
</script>

View File

@@ -0,0 +1,101 @@
<template>
<pw-section class="orange" label="Headers" ref="headers">
<ul v-if="headers.length !== 0">
<li>
<div class="row-wrapper">
<label for="headerList">{{ $t("header_list") }}</label>
<div>
<button
class="icon"
@click="clearContent('headers', $event)"
v-tooltip.bottom="$t('clear')"
>
<i class="material-icons">clear_all</i>
</button>
</div>
</div>
</li>
</ul>
<ul v-for="(header, index) in headers" :key="`${header.value}_${index}`">
<li>
<autocomplete
:placeholder="$t('header_count', { count: index + 1 })"
:source="commonHeaders"
:spellcheck="false"
:value="header.key"
@input="
$store.commit('setKeyHeader', {
index,
value: $event,
})
"
@keyup.prevent="setRouteQueryState"
autofocus
/>
</li>
<li>
<input
:placeholder="$t('value_count', { count: index + 1 })"
:name="'value' + index"
:value="header.value"
@change="
$store.commit('setValueHeader', {
index,
value: $event.target.value,
})
"
@keyup.prevent="setRouteQueryState"
/>
</li>
<div>
<li>
<button
class="icon"
@click="removeRequestHeader(index)"
v-tooltip.bottom="$t('delete')"
id="header"
>
<i class="material-icons">delete</i>
</button>
</li>
</div>
</ul>
<ul>
<li>
<button class="icon" @click="addRequestHeader">
<i class="material-icons">add</i>
<span>{{ $t("add_new") }}</span>
</button>
</li>
</ul>
</pw-section>
</template>
<script>
import { commonHeaders } from "~/helpers/headers"
export default {
props: {
headers: { type: Array, default: () => [] },
},
data() {
return {
commonHeaders,
}
},
methods: {
clearContent(headers, $event) {
this.$emit("clear-content", headers, $event)
},
setRouteQueryState() {
this.$emit("set-route-query-state")
},
removeRequestHeader(index) {
this.$emit("remove-request-header", index)
},
addRequestHeader() {
this.$emit("add-request-header")
},
},
}
</script>

View File

@@ -0,0 +1,108 @@
<template>
<pw-section class="pink" label="Parameters" ref="parameters">
<ul v-if="params.length !== 0">
<li>
<div class="row-wrapper">
<label for="paramList">{{ $t("parameter_list") }}</label>
<div>
<button
class="icon"
@click="clearContent('parameters', $event)"
v-tooltip.bottom="$t('clear')"
>
<i class="material-icons">clear_all</i>
</button>
</div>
</div>
</li>
</ul>
<ul v-for="(param, index) in params" :key="index">
<li>
<input
:placeholder="$t('parameter_count', { count: index + 1 })"
:name="'param' + index"
:value="param.key"
@change="
$store.commit('setKeyParams', {
index,
value: $event.target.value,
})
"
autofocus
/>
</li>
<li>
<input
:placeholder="$t('value_count', { count: index + 1 })"
:name="'value' + index"
:value="decodeURI(param.value)"
@change="
$store.commit('setValueParams', {
index,
value: $event.target.value,
})
"
/>
</li>
<li>
<span class="select-wrapper">
<select
:name="'type' + index"
@change="
$store.commit('setTypeParams', {
index,
value: $event.target.value,
})
"
>
<option value="query" :selected="param.type === 'query'">
{{ $t("query") }}
</option>
<option value="path" :selected="param.type === 'path'">
{{ $t("path") }}
</option>
</select>
</span>
</li>
<div>
<li>
<button
class="icon"
@click="removeRequestParam(index)"
v-tooltip.bottom="$t('delete')"
id="param"
>
<i class="material-icons">delete</i>
</button>
</li>
</div>
</ul>
<ul>
<li>
<button class="icon" @click="addRequestParam">
<i class="material-icons">add</i>
<span>{{ $t("add_new") }}</span>
</button>
</li>
</ul>
</pw-section>
</template>
<script>
export default {
props: {
params: { type: Array, default: () => [] },
},
methods: {
clearContent(parameters, $event) {
this.$emit("clear-content", parameters, $event)
},
removeRequestParam(index) {
this.$emit("remove-request-param", index)
},
addRequestParam() {
this.$emit("add-request-param")
},
},
}
</script>

View File

@@ -0,0 +1,54 @@
<template>
<modal v-if="show" @close="hideModal">
<div slot="header">
<ul>
<li>
<div class="row-wrapper">
<h3 class="title">{{ $t("import_curl") }}</h3>
<div>
<button class="icon" @click="hideModal">
<i class="material-icons">close</i>
</button>
</div>
</div>
</li>
</ul>
</div>
<div slot="body">
<ul>
<li>
<textarea id="import-curl" autofocus rows="8" :placeholder="$t('enter_curl')"></textarea>
</li>
</ul>
</div>
<div slot="footer">
<div class="row-wrapper">
<span></span>
<span>
<button class="icon" @click="hideModal">
{{ $t("cancel") }}
</button>
<button class="icon primary" @click="handleImport">
{{ $t("import") }}
</button>
</span>
</div>
</div>
</modal>
</template>
<script>
export default {
props: {
show: Boolean,
},
methods: {
hideModal() {
this.$emit("hide-modal")
},
handleImport() {
this.$emit("handle-import")
},
},
}
</script>

30
components/http/notes.vue Normal file
View File

@@ -0,0 +1,30 @@
<template>
<pw-section class="pink" :label="$t('notes')" ref="sync">
<div v-if="fb.currentUser">
<inputform />
<feeds />
</div>
<div v-else>
<ul>
<li>
<label>{{ $t("login_first") }}</label>
<p>
<login />
</p>
</li>
</ul>
</div>
</pw-section>
</template>
<script>
import { fb } from "~/helpers/fb"
export default {
data() {
return {
fb,
}
},
}
</script>

View File

@@ -0,0 +1,95 @@
<template>
<modal v-if="show" @close="hideModal">
<div slot="header">
<ul>
<li>
<div class="row-wrapper">
<h3 class="title">{{ $t("manage_token") }}</h3>
<div>
<button class="icon" @click="hideModal">
<i class="material-icons">close</i>
</button>
</div>
</div>
</li>
</ul>
</div>
<div slot="body">
<ul>
<li>
<div class="row-wrapper">
<label for="token-list">{{ $t("token_list") }}</label>
<div v-if="tokens.length != 0">
<button
class="icon"
@click="clearContent('tokens', $event)"
v-tooltip.bottom="$t('clear')"
>
<i class="material-icons">clear_all</i>
</button>
</div>
</div>
</li>
</ul>
<ul id="token-list" v-for="(token, index) in tokens" :key="index">
<li>
<input
:placeholder="'name ' + (index + 1)"
:value="token.name"
@change="
$store.commit('setOAuthTokenName', {
index,
value: $event.target.value,
})
"
/>
</li>
<li>
<input :value="token.value" readonly />
</li>
<div class="row-wrapper">
<li>
<button
class="icon"
@click="useOAuthToken(token.value)"
v-tooltip.bottom="$t('use_token')"
>
<i class="material-icons">input</i>
</button>
</li>
<li>
<button class="icon" @click="removeOAuthToken(index)" v-tooltip.bottom="$t('delete')">
<i class="material-icons">delete</i>
</button>
</li>
</div>
</ul>
<p v-if="tokens.length === 0" class="info">
{{ $t("empty") }}
</p>
</div>
</modal>
</template>
<script>
export default {
props: {
show: Boolean,
tokens: { type: Array, default: () => [] },
},
methods: {
clearContent(tokens, $event) {
this.$emit("clear-content", tokens, $event)
},
useOAuthToken(token) {
this.$emit("use-oauth-token", token)
},
removeOAuthToken(index) {
this.$emit("remove-oauth-token", index)
},
hideModal() {
this.$emit("hide-modal")
},
},
}
</script>

View File

@@ -116,8 +116,8 @@ export default {
debouncer: debounce(function () { debouncer: debounce(function () {
this.worker.postMessage({ type: "ws", url: this.url }) this.worker.postMessage({ type: "ws", url: this.url })
}, 1000), }, 1000),
workerResponseHandler(message) { workerResponseHandler({ data }) {
if (message.data.url === this.url) this.isUrlValid = message.data.result if (data.url === this.url) this.isUrlValid = data.result
}, },
connect() { connect() {
this.log = [ this.log = [
@@ -163,9 +163,9 @@ export default {
icon: "sync", icon: "sync",
}) })
}, },
onMessageArrived(message) { onMessageArrived({ payloadString, destinationName }) {
this.log.push({ this.log.push({
payload: `Message: ${message.payloadString} arrived on topic: ${message.destinationName}`, payload: `Message: ${payloadString} arrived on topic: ${destinationName}`,
source: "info", source: "info",
color: "var(--ac-color)", color: "var(--ac-color)",
ts: new Date().toLocaleTimeString(), ts: new Date().toLocaleTimeString(),

View File

@@ -147,8 +147,8 @@ export default {
debouncer: debounce(function () { debouncer: debounce(function () {
this.worker.postMessage({ type: "socketio", url: this.url }) this.worker.postMessage({ type: "socketio", url: this.url })
}, 1000), }, 1000),
workerResponseHandler(message) { workerResponseHandler({ data }) {
if (message.data.url === this.url) this.isUrlValid = message.data.result if (data.url === this.url) this.isUrlValid = data.result
}, },
removeCommunicationInput({ index }) { removeCommunicationInput({ index }) {
this.$delete(this.communication.inputs, index) this.$delete(this.communication.inputs, index)

View File

@@ -78,8 +78,8 @@ export default {
debouncer: debounce(function () { debouncer: debounce(function () {
this.worker.postMessage({ type: "sse", url: this.server }) this.worker.postMessage({ type: "sse", url: this.server })
}, 1000), }, 1000),
workerResponseHandler(message) { workerResponseHandler({ data }) {
if (message.data.url === this.url) this.isUrlValid = message.data.result if (data.url === this.url) this.isUrlValid = data.result
}, },
toggleSSEConnection() { toggleSSEConnection() {
// If it is connecting: // If it is connecting:

View File

@@ -105,8 +105,8 @@ export default {
debouncer: debounce(function () { debouncer: debounce(function () {
this.worker.postMessage({ type: "ws", url: this.url }) this.worker.postMessage({ type: "ws", url: this.url })
}, 1000), }, 1000),
workerResponseHandler(message) { workerResponseHandler({ data }) {
if (message.data.url === this.url) this.isUrlValid = message.data.result if (data.url === this.url) this.isUrlValid = data.result
}, },
toggleConnection() { toggleConnection() {
// If it is connecting: // If it is connecting:

View File

@@ -157,7 +157,7 @@ class Expectation {
toBeType(expectedType) { toBeType(expectedType) {
const actualType = typeof this.expectValue const actualType = typeof this.expectValue
if ( if (
[ ![
"string", "string",
"boolean", "boolean",
"number", "number",
@@ -166,7 +166,7 @@ class Expectation {
"bigint", "bigint",
"symbol", "symbol",
"function", "function",
].indexOf(expectedType) < 0 ].includes(expectedType)
) { ) {
return this._fail( return this._fail(
this._fmtNot( this._fmtNot(

View File

@@ -31,7 +31,6 @@
"parameter_list": "Parameter List", "parameter_list": "Parameter List",
"raw_request_body": "Raw Request Body", "raw_request_body": "Raw Request Body",
"show_code": "Show Code", "show_code": "Show Code",
"hide_code": "Hide Code",
"show_prerequest_script": "Show Pre-Request Script", "show_prerequest_script": "Show Pre-Request Script",
"hide_prerequest_script": "Hide Pre-Request Script", "hide_prerequest_script": "Hide Pre-Request Script",
"authentication": "Authentication", "authentication": "Authentication",

View File

@@ -306,16 +306,16 @@ export default {
// Build Configuration (https://go.nuxtjs.dev/config-build) // 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, { isDev, isClient }) {
// Sets webpack's mode to development if `isDev` is true. // Sets webpack's mode to development if `isDev` is true.
if (ctx.isDev) { if (isDev) {
config.mode = "development" config.mode = "development"
} }
config.node = { config.node = {
fs: "empty", fs: "empty",
} }
if (ctx.isClient) { if (isClient) {
config.module.rules.unshift({ config.module.rules.unshift({
test: /\.worker\.(c|m)?js$/i, test: /\.worker\.(c|m)?js$/i,
use: { loader: "worker-loader" }, use: { loader: "worker-loader" },

View File

@@ -384,11 +384,11 @@ export default {
}, },
} }
) )
.then((response) => { .then(({ html_url }) => {
this.$toast.success(this.$t("gist_created"), { this.$toast.success(this.$t("gist_created"), {
icon: "done", icon: "done",
}) })
window.open(response.html_url) window.open(html_url)
}) })
.catch((error) => { .catch((error) => {
this.$toast.error(this.$t("something_went_wrong"), { this.$toast.error(this.$t("something_went_wrong"), {

View File

@@ -252,7 +252,7 @@
<button <button
class="icon" class="icon"
id="show-modal" id="show-modal"
@click="showModal = true" @click="showCurlImportModal = !showCurlImportModal"
v-tooltip.bottom="$t('import_curl')" v-tooltip.bottom="$t('import_curl')"
> >
<i class="material-icons">import_export</i> <i class="material-icons">import_export</i>
@@ -260,11 +260,9 @@
<button <button
class="icon" class="icon"
id="code" id="code"
@click="isHidden = !isHidden" @click="showCodegenModal = !showCodegenModal"
:disabled="!isValidURL" :disabled="!isValidURL"
v-tooltip.bottom="{ v-tooltip.bottom="$t('show_code')"
content: isHidden ? $t('show_code') : $t('hide_code'),
}"
> >
<i class="material-icons">code</i> <i class="material-icons">code</i>
</button> </button>
@@ -312,93 +310,12 @@
" "
:selected="true" :selected="true"
> >
<pw-section class="pink" label="Parameters" ref="parameters"> <http-parameters
<ul v-if="params.length !== 0"> :params="params"
<li> @clear-content="clearContent"
<div class="row-wrapper"> @remove-request-param="removeRequestParam"
<label for="paramList">{{ $t("parameter_list") }}</label> @add-request-param="addRequestParam"
<div> />
<button
class="icon"
@click="clearContent('parameters', $event)"
v-tooltip.bottom="$t('clear')"
>
<i class="material-icons">clear_all</i>
</button>
</div>
</div>
</li>
</ul>
<ul v-for="(param, index) in params" :key="index">
<li>
<input
:placeholder="$t('parameter_count', { count: index + 1 })"
:name="'param' + index"
:value="param.key"
@change="
$store.commit('setKeyParams', {
index,
value: $event.target.value,
})
"
autofocus
/>
</li>
<li>
<input
:placeholder="$t('value_count', { count: index + 1 })"
:name="'value' + index"
:value="decodeURI(param.value)"
@change="
$store.commit('setValueParams', {
index,
value: $event.target.value,
})
"
/>
</li>
<li>
<span class="select-wrapper">
<select
:name="'type' + index"
@change="
$store.commit('setTypeParams', {
index,
value: $event.target.value,
})
"
>
<option value="query" :selected="param.type === 'query'">
{{ $t("query") }}
</option>
<option value="path" :selected="param.type === 'path'">
{{ $t("path") }}
</option>
</select>
</span>
</li>
<div>
<li>
<button
class="icon"
@click="removeRequestParam(index)"
v-tooltip.bottom="$t('delete')"
id="param"
>
<i class="material-icons">delete</i>
</button>
</li>
</div>
</ul>
<ul>
<li>
<button class="icon" @click="addRequestParam">
<i class="material-icons">add</i>
<span>{{ $t("add_new") }}</span>
</button>
</li>
</ul>
</pw-section>
</tab> </tab>
<tab :id="'authentication'" :label="$t('authentication')"> <tab :id="'authentication'" :label="$t('authentication')">
@@ -462,7 +379,7 @@
<button <button
v-if="auth === 'OAuth 2.0'" v-if="auth === 'OAuth 2.0'"
class="icon" class="icon"
@click="showTokenList = !showTokenList" @click="showTokenListModal = !showTokenListModal"
v-tooltip.bottom="$t('use_token')" v-tooltip.bottom="$t('use_token')"
> >
<i class="material-icons">open_in_new</i> <i class="material-icons">open_in_new</i>
@@ -611,76 +528,13 @@
$t('headers') + `${headers.length !== 0 ? ' \xA0 • \xA0 ' + headers.length : ''}` $t('headers') + `${headers.length !== 0 ? ' \xA0 • \xA0 ' + headers.length : ''}`
" "
> >
<pw-section class="orange" label="Headers" ref="headers"> <http-headers
<ul v-if="headers.length !== 0"> :headers="headers"
<li> @clear-content="clearContent"
<div class="row-wrapper"> @set-route-query-state="setRouteQueryState"
<label for="headerList">{{ $t("header_list") }}</label> @remove-request-header="removeRequestHeader"
<div> @add-request-header="addRequestHeader"
<button />
class="icon"
@click="clearContent('headers', $event)"
v-tooltip.bottom="$t('clear')"
>
<i class="material-icons">clear_all</i>
</button>
</div>
</div>
</li>
</ul>
<ul v-for="(header, index) in headers" :key="`${header.value}_${index}`">
<li>
<autocomplete
:placeholder="$t('header_count', { count: index + 1 })"
:source="commonHeaders"
:spellcheck="false"
:value="header.key"
@input="
$store.commit('setKeyHeader', {
index,
value: $event,
})
"
@keyup.prevent="setRouteQueryState"
autofocus
/>
</li>
<li>
<input
:placeholder="$t('value_count', { count: index + 1 })"
:name="'value' + index"
:value="header.value"
@change="
$store.commit('setValueHeader', {
index,
value: $event.target.value,
})
"
@keyup.prevent="setRouteQueryState"
/>
</li>
<div>
<li>
<button
class="icon"
@click="removeRequestHeader(index)"
v-tooltip.bottom="$t('delete')"
id="header"
>
<i class="material-icons">delete</i>
</button>
</li>
</div>
</ul>
<ul>
<li>
<button class="icon" @click="addRequestHeader">
<i class="material-icons">add</i>
<span>{{ $t("add_new") }}</span>
</button>
</li>
</ul>
</pw-section>
</tab> </tab>
<tab :id="'pre_request_script'" :label="$t('pre_request_script')"> <tab :id="'pre_request_script'" :label="$t('pre_request_script')">
@@ -832,314 +686,127 @@
</tab> </tab>
<tab :id="'notes'" :label="$t('notes')"> <tab :id="'notes'" :label="$t('notes')">
<pw-section class="pink" :label="$t('notes')" ref="sync"> <notes />
<div v-if="fb.currentUser">
<inputform />
<feeds />
</div>
<div v-else>
<ul>
<li>
<label>{{ $t("login_first") }}</label>
<p>
<login />
</p>
</li>
</ul>
</div>
</pw-section>
</tab> </tab>
</tabs> </tabs>
</section> </section>
</aside> </aside>
</div>
<save-request-as <save-request-as
:show="showRequestModal" :show="showSaveRequestModal"
@hide-model="hideRequestModal" @hide-modal="hideRequestModal"
:editing-request="editRequest" :editing-request="editRequest"
/> />
<modal v-if="showModal" @close="showModal = false"> <import-curl
<div slot="header"> :show="showCurlImportModal"
<ul> @hide-modal="showCurlImportModal = false"
<li> @handle-import="handleImport"
<div class="row-wrapper"> />
<h3 class="title">{{ $t("import_curl") }}</h3>
<div>
<button class="icon" @click="showModal = false">
<i class="material-icons">close</i>
</button>
</div>
</div>
</li>
</ul>
</div>
<div slot="body">
<ul>
<li>
<textarea
id="import-text"
autofocus
rows="8"
:placeholder="$t('enter_curl')"
></textarea>
</li>
</ul>
</div>
<div slot="footer">
<div class="row-wrapper">
<span></span>
<span>
<button class="icon" @click="showModal = false">
{{ $t("cancel") }}
</button>
<button class="icon primary" @click="handleImport">
{{ $t("import") }}
</button>
</span>
</div>
</div>
</modal>
<modal v-if="!isHidden" @close="isHidden = true"> <codegen-modal
<div slot="header"> :show="showCodegenModal"
<ul> :requestTypeProp="requestType"
<li> :requestCode="requestCode"
<div class="row-wrapper"> @hide-modal="showCodegenModal = false"
<h3 class="title">{{ $t("generate_code") }}</h3> @set-request-type="setRequestType"
<div> />
<button class="icon" @click="isHidden = true">
<i class="material-icons">close</i>
</button>
</div>
</div>
</li>
</ul>
</div>
<div slot="body">
<ul>
<li>
<label for="requestType">{{ $t("request_type") }}</label>
<span class="select-wrapper">
<v-popover>
<pre v-if="requestType">{{
codegens.find((x) => x.id === requestType).name
}}</pre>
<input
v-else
id="requestType"
v-model="requestType"
:placeholder="$t('choose_language')"
class="cursor-pointer"
readonly
autofocus
/>
<template slot="popover">
<div v-for="gen in codegens" :key="gen.id">
<button class="icon" @click="requestType = gen.id" v-close-popover>
{{ gen.name }}
</button>
</div>
</template>
</v-popover>
</span>
</li>
</ul>
<ul>
<li>
<div class="row-wrapper">
<label for="generatedCode">{{ $t("generated_code") }}</label>
<div>
<button
class="icon"
@click="copyRequestCode"
id="copyRequestCode"
ref="copyRequestCode"
v-tooltip="$t('copy_code')"
>
<i class="material-icons">content_copy</i>
</button>
</div>
</div>
<textarea
id="generatedCode"
ref="generatedCode"
name="generatedCode"
rows="8"
v-model="requestCode"
></textarea>
</li>
</ul>
</div>
</modal>
<modal v-if="showTokenList" @close="showTokenList = false"> <token-list
<div slot="header"> :show="showTokenListModal"
<ul> :tokens="tokens"
<li> @clear-content="clearContent"
<div class="row-wrapper"> @use-oauth-token="useOAuthToken"
<h3 class="title">{{ $t("manage_token") }}</h3> @remove-oauth-token="removeOAuthToken"
<div> @hide-modal="showTokenListModal = false"
<button class="icon" @click="showTokenList = false"> />
<i class="material-icons">close</i>
</button> <modal v-if="showTokenRequestList" @close="showTokenRequestList = false">
</div> <div slot="header">
</div> <ul>
</li> <li>
</ul>
</div>
<div slot="body">
<ul>
<li>
<div class="row-wrapper">
<label for="token-list">{{ $t("token_list") }}</label>
<div v-if="tokens.length != 0">
<button
class="icon"
@click="clearContent('tokens', $event)"
v-tooltip.bottom="$t('clear')"
>
<i class="material-icons">clear_all</i>
</button>
</div>
</div>
</li>
</ul>
<ul id="token-list" v-for="(token, index) in tokens" :key="index">
<li>
<input
:placeholder="'name ' + (index + 1)"
:value="token.name"
@change="
$store.commit('setOAuthTokenName', {
index,
value: $event.target.value,
})
"
/>
</li>
<li>
<input :value="token.value" readonly />
</li>
<div class="row-wrapper"> <div class="row-wrapper">
<li> <h3 class="title">{{ $t("manage_token_req") }}</h3>
<div>
<button class="icon" @click="showTokenRequestList = false">
<i class="material-icons">close</i>
</button>
</div>
</div>
</li>
</ul>
</div>
<div slot="body">
<ul>
<li>
<div class="row-wrapper">
<label for="token-req-list">{{ $t("token_req_list") }}</label>
<div>
<button <button
:disabled="this.tokenReqs.length === 0"
class="icon" class="icon"
@click="useOAuthToken(token.value)" @click="showTokenRequestList = false"
v-tooltip.bottom="$t('use_token')" v-tooltip.bottom="$t('use_token_req')"
> >
<i class="material-icons">input</i> <i class="material-icons">input</i>
</button> </button>
</li>
<li>
<button <button
:disabled="this.tokenReqs.length === 0"
class="icon" class="icon"
@click="removeOAuthToken(index)" @click="removeOAuthTokenReq"
v-tooltip.bottom="$t('delete')" v-tooltip.bottom="$t('delete')"
> >
<i class="material-icons">delete</i> <i class="material-icons">delete</i>
</button> </button>
</li> </div>
</div> </div>
</ul> <span class="select-wrapper">
<p v-if="tokens.length === 0" class="info"> <select
{{ $t("empty") }} id="token-req-list"
</p> v-model="tokenReqSelect"
</div> :disabled="this.tokenReqs.length === 0"
</modal> @change="tokenReqChange($event)"
>
<modal v-if="showTokenRequestList" @close="showTokenRequestList = false"> <option v-for="(req, index) in tokenReqs" :key="index" :value="req.name">
<div slot="header"> {{ req.name }}
<ul> </option>
<li> </select>
<div class="row-wrapper">
<h3 class="title">{{ $t("manage_token_req") }}</h3>
<div>
<button class="icon" @click="showTokenRequestList = false">
<i class="material-icons">close</i>
</button>
</div>
</div>
</li>
</ul>
</div>
<div slot="body">
<ul>
<li>
<div class="row-wrapper">
<label for="token-req-list">{{ $t("token_req_list") }}</label>
<div>
<button
:disabled="this.tokenReqs.length === 0"
class="icon"
@click="showTokenRequestList = false"
v-tooltip.bottom="$t('use_token_req')"
>
<i class="material-icons">input</i>
</button>
<button
:disabled="this.tokenReqs.length === 0"
class="icon"
@click="removeOAuthTokenReq"
v-tooltip.bottom="$t('delete')"
>
<i class="material-icons">delete</i>
</button>
</div>
</div>
<span class="select-wrapper">
<select
id="token-req-list"
v-model="tokenReqSelect"
:disabled="this.tokenReqs.length === 0"
@change="tokenReqChange($event)"
>
<option v-for="(req, index) in tokenReqs" :key="index" :value="req.name">
{{ req.name }}
</option>
</select>
</span>
</li>
</ul>
<ul>
<li>
<label for="token-req-name">{{ $t("token_req_name") }}</label>
<input v-model="tokenReqName" />
</li>
</ul>
<ul>
<li>
<label for="token-req-details">
{{ $t("token_req_details") }}
</label>
<textarea
id="token-req-details"
readonly
rows="7"
v-model="tokenReqDetails"
></textarea>
</li>
</ul>
</div>
<div slot="footer">
<div class="row-wrapper">
<span></span>
<span>
<button class="icon primary" @click="addOAuthTokenReq">
{{ $t("save_token_req") }}
</button>
</span> </span>
</div> </li>
</ul>
<ul>
<li>
<label for="token-req-name">{{ $t("token_req_name") }}</label>
<input v-model="tokenReqName" />
</li>
</ul>
<ul>
<li>
<label for="token-req-details">
{{ $t("token_req_details") }}
</label>
<textarea id="token-req-details" readonly rows="7" v-model="tokenReqDetails"></textarea>
</li>
</ul>
</div>
<div slot="footer">
<div class="row-wrapper">
<span></span>
<span>
<button class="icon primary" @click="addOAuthTokenReq">
{{ $t("save_token_req") }}
</button>
</span>
</div> </div>
</modal> </div>
</div> </modal>
</div> </div>
</template> </template>
<script> <script>
import url from "url" import url from "url"
import querystring from "querystring" import querystring from "querystring"
import { commonHeaders } from "~/helpers/headers"
import parseCurlCommand from "~/helpers/curlparser" import parseCurlCommand from "~/helpers/curlparser"
import getEnvironmentVariablesFromScript from "~/helpers/preRequest" import getEnvironmentVariablesFromScript from "~/helpers/preRequest"
import runTestScriptWithVariables from "~/helpers/postwomanTesting" import runTestScriptWithVariables from "~/helpers/postwomanTesting"
@@ -1152,13 +819,13 @@ import { hasPathParams, addPathParamsToVariables, getQueryParams } from "~/helpe
import { parseUrlAndPath } from "~/helpers/utils/uri" import { parseUrlAndPath } from "~/helpers/utils/uri"
import { httpValid } from "~/helpers/utils/valid" import { httpValid } from "~/helpers/utils/valid"
import { knownContentTypes, isJSONContentType } from "~/helpers/utils/contenttypes" import { knownContentTypes, isJSONContentType } from "~/helpers/utils/contenttypes"
import { codegens, generateCodeWithGenerator } from "~/helpers/codegen/codegen" import { generateCodeWithGenerator } from "~/helpers/codegen/codegen"
import findStatusGroup from "~/helpers/findStatusGroup" import findStatusGroup from "~/helpers/findStatusGroup"
export default { export default {
data() { data() {
return { return {
showModal: false, showCurlImportModal: false,
showPreRequestScript: true, showPreRequestScript: true,
testsEnabled: true, testsEnabled: true,
testScript: "// pw.expect('variable').toBe('value');", testScript: "// pw.expect('variable').toBe('value');",
@@ -1167,7 +834,7 @@ export default {
copyButton: '<i class="material-icons">content_copy</i>', copyButton: '<i class="material-icons">content_copy</i>',
downloadButton: '<i class="material-icons">save_alt</i>', downloadButton: '<i class="material-icons">save_alt</i>',
doneButton: '<i class="material-icons">done</i>', doneButton: '<i class="material-icons">done</i>',
isHidden: true, showCodegenModal: false,
response: { response: {
status: "", status: "",
headers: "", headers: "",
@@ -1175,11 +842,10 @@ export default {
}, },
validContentTypes: knownContentTypes, validContentTypes: knownContentTypes,
paramsWatchEnabled: true, paramsWatchEnabled: true,
showTokenList: false, showTokenListModal: false,
showTokenRequest: false, showTokenRequest: false,
showTokenRequestList: false, showTokenRequestList: false,
commonHeaders, showSaveRequestModal: false,
showRequestModal: false,
editRequest: {}, editRequest: {},
urlExcludes: {}, urlExcludes: {},
activeSidebar: true, activeSidebar: true,
@@ -1196,7 +862,6 @@ export default {
: true, : true,
}, },
currentMethodIndex: 0, currentMethodIndex: 0,
codegens,
methodMenuItems: [ methodMenuItems: [
"GET", "GET",
"HEAD", "HEAD",
@@ -1301,7 +966,7 @@ export default {
}, },
editingRequest(newValue) { editingRequest(newValue) {
this.editRequest = newValue this.editRequest = newValue
this.showRequestModal = true this.showSaveRequestModal = true
}, },
method() { method() {
this.contentType = ["POST", "PUT", "PATCH", "DELETE"].includes(this.method) this.contentType = ["POST", "PUT", "PATCH", "DELETE"].includes(this.method)
@@ -2117,15 +1782,6 @@ export default {
setTimeout(() => (this.$refs.copyRequest.innerHTML = this.copyButton), 1000) setTimeout(() => (this.$refs.copyRequest.innerHTML = this.copyButton), 1000)
} }
}, },
copyRequestCode() {
this.$refs.copyRequestCode.innerHTML = this.doneButton
this.$toast.success(this.$t("copied_to_clipboard"), {
icon: "done",
})
this.$refs.generatedCode.select()
document.execCommand("copy")
setTimeout(() => (this.$refs.copyRequestCode.innerHTML = this.copyButton), 1000)
},
setRouteQueryState() { setRouteQueryState() {
const flat = (key) => (this[key] !== "" ? `${key}=${this[key]}&` : "") const flat = (key) => (this[key] !== "" ? `${key}=${this[key]}&` : "")
const deep = (key) => { const deep = (key) => {
@@ -2188,7 +1844,7 @@ export default {
observer.observe(requestElement) observer.observe(requestElement)
}, },
handleImport() { handleImport() {
const { value: text } = document.getElementById("import-text") const { value: text } = document.getElementById("import-curl")
try { try {
const parsedCurl = parseCurlCommand(text) const parsedCurl = parseCurlCommand(text)
const { origin, pathname } = new URL(parsedCurl.url.replace(/"/g, "").replace(/'/g, "")) const { origin, pathname } = new URL(parsedCurl.url.replace(/"/g, "").replace(/'/g, ""))
@@ -2209,9 +1865,9 @@ export default {
this.rawInput = true this.rawInput = true
this.rawParams = parsedCurl["data"] this.rawParams = parsedCurl["data"]
} }
this.showModal = false this.showCurlImportModal = false
} catch (error) { } catch (error) {
this.showModal = false this.showCurlImportModal = false
this.$toast.error(this.$t("curl_invalid_format"), { this.$toast.error(this.$t("curl_invalid_format"), {
icon: "error", icon: "error",
}) })
@@ -2321,10 +1977,10 @@ export default {
if (this.selectedRequest.url) { if (this.selectedRequest.url) {
this.editRequest = Object.assign({}, this.selectedRequest, this.editRequest) this.editRequest = Object.assign({}, this.selectedRequest, this.editRequest)
} }
this.showRequestModal = true this.showSaveRequestModal = true
}, },
hideRequestModal() { hideRequestModal() {
this.showRequestModal = false this.showSaveRequestModal = false
this.editRequest = {} this.editRequest = {}
}, },
setExclude(excludedField, excluded) { setExclude(excludedField, excluded) {
@@ -2429,7 +2085,7 @@ export default {
}, },
useOAuthToken(value) { useOAuthToken(value) {
this.bearerToken = value this.bearerToken = value
this.showTokenList = false this.showTokenListModal = false
}, },
addOAuthTokenReq() { addOAuthTokenReq() {
try { try {
@@ -2473,6 +2129,9 @@ export default {
this.clientId = clientId this.clientId = clientId
this.scope = scope this.scope = scope
}, },
setRequestType(val) {
this.requestType = val
},
}, },
async mounted() { async mounted() {
this.observeRequestButton() this.observeRequestButton()
@@ -2499,8 +2158,7 @@ export default {
} }
if (e.key === "Escape") { if (e.key === "Escape") {
e.preventDefault() e.preventDefault()
this.showModal = this.showTokenList = this.showTokenRequestList = this.showRequestModal = false this.showCurlImportModal = this.showTokenListModal = this.showTokenRequestList = this.showSaveRequestModal = this.showCodegenModal = false
this.isHidden = true
} }
if ((e.key === "g" || e.key === "G") && e.altKey) { if ((e.key === "g" || e.key === "G") && e.altKey) {
this.method = "GET" this.method = "GET"