refactor: init new state for body
This commit is contained in:
74
components/http/Body.vue
Normal file
74
components/http/Body.vue
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="flex flex-1 py-2 items-center justify-between">
|
||||||
|
<tippy
|
||||||
|
ref="contentTypeOptions"
|
||||||
|
interactive
|
||||||
|
tabindex="-1"
|
||||||
|
trigger="click"
|
||||||
|
theme="popover"
|
||||||
|
arrow
|
||||||
|
>
|
||||||
|
<template #trigger>
|
||||||
|
<div class="flex">
|
||||||
|
<span class="select-wrapper">
|
||||||
|
<input
|
||||||
|
id="contentType"
|
||||||
|
v-model="contentType"
|
||||||
|
class="
|
||||||
|
bg-primary
|
||||||
|
rounded-lg
|
||||||
|
flex
|
||||||
|
font-semibold font-mono
|
||||||
|
text-xs
|
||||||
|
w-full
|
||||||
|
py-2
|
||||||
|
px-4
|
||||||
|
transition
|
||||||
|
truncate
|
||||||
|
focus:outline-none
|
||||||
|
"
|
||||||
|
readonly
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<SmartItem
|
||||||
|
v-for="(contentTypeItem, index) in validContentTypes"
|
||||||
|
:key="`contentTypeItem-${index}`"
|
||||||
|
:label="contentTypeItem"
|
||||||
|
@click.native="
|
||||||
|
contentType = contentTypeItem
|
||||||
|
$refs.contentTypeOptions.tippy().hide()
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</tippy>
|
||||||
|
<SmartToggle :on="rawInput" class="px-4" @change="rawInput = !rawInput">
|
||||||
|
{{ $t("raw_input") }}
|
||||||
|
</SmartToggle>
|
||||||
|
</div>
|
||||||
|
<HttpBodyParameters v-if="!rawInput" :content-type="contentType" />
|
||||||
|
<HttpRawBody v-else :content-type="contentType" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from "@nuxtjs/composition-api"
|
||||||
|
import { pluckRef } from "~/helpers/utils/composables"
|
||||||
|
import { useRESTRequestBody } from "~/newstore/RESTSession"
|
||||||
|
import { knownContentTypes } from "~/helpers/utils/contenttypes"
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
contentType: pluckRef(useRESTRequestBody(), "contentType"),
|
||||||
|
rawInput: pluckRef(useRESTRequestBody(), "isRaw"),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
validContentTypes: Object.keys(knownContentTypes),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -104,7 +104,7 @@
|
|||||||
@click.native="toggleActive(index, param)"
|
@click.native="toggleActive(index, param)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="contentType === 'multipart/form-data'">
|
<div>
|
||||||
<label for="attachment" class="p-0">
|
<label for="attachment" class="p-0">
|
||||||
<ButtonSecondary
|
<ButtonSecondary
|
||||||
class="w-full"
|
class="w-full"
|
||||||
@@ -133,10 +133,15 @@
|
|||||||
</AppSection>
|
</AppSection>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
export default {
|
import { defineComponent, toRef } from "@nuxtjs/composition-api"
|
||||||
props: {
|
import { useRESTRequestBody } from "~/newstore/RESTSession"
|
||||||
bodyParams: { type: Array, default: () => [] },
|
|
||||||
|
export default defineComponent({
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
bodyParams: toRef(useRESTRequestBody(), "body"),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
contentType() {
|
contentType() {
|
||||||
@@ -249,7 +254,7 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
</label>
|
</label>
|
||||||
<div>
|
<div>
|
||||||
<ButtonSecondary
|
<ButtonSecondary
|
||||||
v-if="rawInput && contentType.endsWith('json')"
|
v-if="contentType.endsWith('json')"
|
||||||
ref="prettifyRequest"
|
ref="prettifyRequest"
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
:title="$t('prettify_body')"
|
:title="$t('prettify_body')"
|
||||||
@@ -66,43 +66,39 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { defineComponent } from "@nuxtjs/composition-api"
|
||||||
import { getEditorLangForMimeType } from "~/helpers/editorutils"
|
import { getEditorLangForMimeType } from "~/helpers/editorutils"
|
||||||
|
import { pluckRef } from "~/helpers/utils/composables"
|
||||||
|
import { useRESTRequestBody } from "~/newstore/RESTSession"
|
||||||
|
|
||||||
export default {
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
rawParams: { type: String, default: null },
|
contentType: {
|
||||||
contentType: { type: String, default: null },
|
type: String,
|
||||||
rawInput: { type: Boolean, default: false },
|
required: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data() {
|
setup() {
|
||||||
return {
|
return {
|
||||||
|
rawParamsBody: pluckRef(useRESTRequestBody(), "body"),
|
||||||
prettifyIcon: "photo_filter",
|
prettifyIcon: "photo_filter",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
rawParamsBody: {
|
|
||||||
get() {
|
|
||||||
return this.rawParams
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
this.$emit("update-raw-body", value)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
rawInputEditorLang() {
|
rawInputEditorLang() {
|
||||||
return getEditorLangForMimeType(this.contentType)
|
return getEditorLangForMimeType(this.contentType)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
clearContent(bodyParams, $event) {
|
clearContent() {
|
||||||
this.$emit("clear-content", bodyParams, $event)
|
this.rawParamsBody = ""
|
||||||
},
|
},
|
||||||
uploadPayload() {
|
uploadPayload() {
|
||||||
this.$emit("update-raw-input", true)
|
|
||||||
const file = this.$refs.payload.files[0]
|
const file = this.$refs.payload.files[0]
|
||||||
if (file !== undefined && file !== null) {
|
if (file !== undefined && file !== null) {
|
||||||
const reader = new FileReader()
|
const reader = new FileReader()
|
||||||
reader.onload = ({ target }) => {
|
reader.onload = ({ target }) => {
|
||||||
this.$emit("update-raw-body", target.result)
|
this.rawParamsBody = target.result
|
||||||
}
|
}
|
||||||
reader.readAsText(file)
|
reader.readAsText(file)
|
||||||
this.$toast.info(this.$t("file_imported"), {
|
this.$toast.info(this.$t("file_imported"), {
|
||||||
@@ -128,5 +124,5 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
53
components/http/TestResult.vue
Normal file
53
components/http/TestResult.vue
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div v-if="results">
|
||||||
|
<div
|
||||||
|
v-for="(result, index) in results"
|
||||||
|
:key="`result-${index}`"
|
||||||
|
class="flex py-2 px-4 items-center"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
class="mr-4 material-icons"
|
||||||
|
:class="result.status === 'pass' ? 'text-green-500' : 'text-red-500'"
|
||||||
|
>
|
||||||
|
{{ result.status === "pass" ? "check_circle" : "cancel" }}
|
||||||
|
</i>
|
||||||
|
<span
|
||||||
|
v-if="result.message"
|
||||||
|
class="font-semibold text-secondaryDark text-xs"
|
||||||
|
>
|
||||||
|
{{ result.message }}
|
||||||
|
</span>
|
||||||
|
<span class="text-secondaryLight text-xs">
|
||||||
|
{{
|
||||||
|
` \xA0 — \xA0test ${
|
||||||
|
result.status === "pass" ? $t("passed") : $t("failed")
|
||||||
|
}`
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="results.tests">
|
||||||
|
<HttpTestResult
|
||||||
|
v-for="(result, index) in results.expectResults"
|
||||||
|
:key="`result-${index}`"
|
||||||
|
class="divide-y divide-dividerLight"
|
||||||
|
:results="results.expectResults"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, PropType } from "@vue/composition-api"
|
||||||
|
import { HoppTestResult } from "~/helpers/types/HoppTestResult"
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
results: {
|
||||||
|
type: Array as PropType<HoppTestResult>,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -36,42 +36,45 @@
|
|||||||
}"
|
}"
|
||||||
complete-mode="test"
|
complete-mode="test"
|
||||||
/>
|
/>
|
||||||
<div v-if="testReports.length !== 0">
|
<pre>
|
||||||
|
{{ testResults }}
|
||||||
|
</pre>
|
||||||
|
<div v-if="testResults">
|
||||||
<div class="flex flex-1 pl-4 items-center justify-between">
|
<div class="flex flex-1 pl-4 items-center justify-between">
|
||||||
<label class="font-semibold text-xs"> Test Reports </label>
|
<div>
|
||||||
|
<label class="font-semibold text-xs"> Test Report: </label>
|
||||||
|
<span class="font-semibold text-xs text-red-500">
|
||||||
|
{{ failedTests }} failing,
|
||||||
|
</span>
|
||||||
|
<span class="font-semibold text-xs text-green-500">
|
||||||
|
{{ passedTests }} successful,
|
||||||
|
</span>
|
||||||
|
<span class="font-semibold text-xs text-secondaryDark">
|
||||||
|
out of {{ totalTests }} tests.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<ButtonSecondary
|
<ButtonSecondary
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
:title="$t('clear')"
|
:title="$t('clear')"
|
||||||
icon="clear_all"
|
icon="clear_all"
|
||||||
@click.native="clearContent('tests', $event)"
|
@click.native="clearContent()"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-if="testResults.expectResults">
|
||||||
v-for="(testReport, index) in testReports"
|
<HttpTestResult
|
||||||
:key="`testReport-${index}`"
|
v-for="(result, index) in testResults.expectResults"
|
||||||
class="px-4"
|
:key="`result-${index}`"
|
||||||
>
|
class="divide-y divide-dividerLight"
|
||||||
<div v-if="testReport.startBlock">
|
:results="testResults.expectResults"
|
||||||
<hr />
|
/>
|
||||||
<h4 class="heading">
|
</div>
|
||||||
{{ testReport.startBlock }}
|
<div v-if="testResults.tests">
|
||||||
</h4>
|
<HttpTestResult
|
||||||
</div>
|
v-for="(result, index) in testResults.tests"
|
||||||
<p
|
:key="`result-${index}`"
|
||||||
v-else-if="testReport.result"
|
class="divide-y divide-dividerLight"
|
||||||
class="flex font-mono flex-1 text-xs info"
|
:results="testResults.tests"
|
||||||
>
|
/>
|
||||||
<span :class="testReport.styles.class" class="flex items-center">
|
|
||||||
<i class="text-sm material-icons">
|
|
||||||
{{ testReport.styles.icon }}
|
|
||||||
</i>
|
|
||||||
<span> {{ testReport.result }}</span>
|
|
||||||
<span v-if="testReport.message">
|
|
||||||
<label>: {{ testReport.message }}</label>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<div v-else-if="testReport.endBlock"><hr /></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</AppSection>
|
</AppSection>
|
||||||
@@ -79,7 +82,11 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from "@nuxtjs/composition-api"
|
import { defineComponent } from "@nuxtjs/composition-api"
|
||||||
import { useTestScript, restTestResults$ } from "~/newstore/RESTSession"
|
import {
|
||||||
|
useTestScript,
|
||||||
|
restTestResults$,
|
||||||
|
setRESTTestResults,
|
||||||
|
} from "~/newstore/RESTSession"
|
||||||
import { useReadonlyStream } from "~/helpers/utils/composables"
|
import { useReadonlyStream } from "~/helpers/utils/composables"
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@@ -87,8 +94,27 @@ export default defineComponent({
|
|||||||
return {
|
return {
|
||||||
testScript: useTestScript(),
|
testScript: useTestScript(),
|
||||||
testResults: useReadonlyStream(restTestResults$, null),
|
testResults: useReadonlyStream(restTestResults$, null),
|
||||||
testReports: [],
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
totalTests() {
|
||||||
|
return this.testResults.expectResults.length
|
||||||
|
},
|
||||||
|
failedTests() {
|
||||||
|
return this.testResults.expectResults.filter(
|
||||||
|
(result) => result.status === "fail"
|
||||||
|
).length
|
||||||
|
},
|
||||||
|
passedTests() {
|
||||||
|
return this.testResults.expectResults.filter(
|
||||||
|
(result) => result.status === "pass"
|
||||||
|
).length
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clearContent() {
|
||||||
|
setRESTTestResults(null)
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -177,7 +177,7 @@
|
|||||||
</Splitpanes>
|
</Splitpanes>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script>
|
||||||
import { defineComponent } from "@nuxtjs/composition-api"
|
import { defineComponent } from "@nuxtjs/composition-api"
|
||||||
import { Splitpanes, Pane } from "splitpanes"
|
import { Splitpanes, Pane } from "splitpanes"
|
||||||
import { logHoppRequestRunToAnalytics } from "~/helpers/fb/analytics"
|
import { logHoppRequestRunToAnalytics } from "~/helpers/fb/analytics"
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ValidContentTypes } from "../utils/contenttypes"
|
||||||
|
|
||||||
export const RESTReqSchemaVersion = "1"
|
export const RESTReqSchemaVersion = "1"
|
||||||
|
|
||||||
export type HoppRESTParam = {
|
export type HoppRESTParam = {
|
||||||
@@ -12,6 +14,12 @@ export type HoppRESTHeader = {
|
|||||||
active: boolean
|
active: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type HoppRESTReqBody = {
|
||||||
|
contentType: ValidContentTypes
|
||||||
|
body: string
|
||||||
|
isRaw: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export interface HoppRESTRequest {
|
export interface HoppRESTRequest {
|
||||||
v: string
|
v: string
|
||||||
|
|
||||||
@@ -21,6 +29,8 @@ export interface HoppRESTRequest {
|
|||||||
headers: HoppRESTHeader[]
|
headers: HoppRESTHeader[]
|
||||||
preRequestScript: string
|
preRequestScript: string
|
||||||
testScript: string
|
testScript: string
|
||||||
|
|
||||||
|
body: HoppRESTReqBody
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeRESTRequest(
|
export function makeRESTRequest(
|
||||||
@@ -36,6 +46,22 @@ export function isHoppRESTRequest(x: any): x is HoppRESTRequest {
|
|||||||
return x && typeof x === "object" && "v" in x
|
return x && typeof x === "object" && "v" in x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseRequestBody(x: any): HoppRESTReqBody {
|
||||||
|
if (x.contentType === "application/json") {
|
||||||
|
return {
|
||||||
|
contentType: "application/json",
|
||||||
|
body: x.rawParams,
|
||||||
|
isRaw: x.rawInput,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
contentType: "application/json",
|
||||||
|
body: "",
|
||||||
|
isRaw: x.rawInput,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function translateToNewRequest(x: any): HoppRESTRequest {
|
export function translateToNewRequest(x: any): HoppRESTRequest {
|
||||||
if (isHoppRESTRequest(x)) {
|
if (isHoppRESTRequest(x)) {
|
||||||
return x
|
return x
|
||||||
@@ -59,6 +85,8 @@ export function translateToNewRequest(x: any): HoppRESTRequest {
|
|||||||
const preRequestScript = x.preRequestScript
|
const preRequestScript = x.preRequestScript
|
||||||
const testScript = x.testScript
|
const testScript = x.testScript
|
||||||
|
|
||||||
|
const body = parseRequestBody(x)
|
||||||
|
|
||||||
const result: HoppRESTRequest = {
|
const result: HoppRESTRequest = {
|
||||||
endpoint,
|
endpoint,
|
||||||
headers,
|
headers,
|
||||||
@@ -66,6 +94,7 @@ export function translateToNewRequest(x: any): HoppRESTRequest {
|
|||||||
method,
|
method,
|
||||||
preRequestScript,
|
preRequestScript,
|
||||||
testScript,
|
testScript,
|
||||||
|
body,
|
||||||
v: RESTReqSchemaVersion,
|
v: RESTReqSchemaVersion,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import {
|
|||||||
readonly,
|
readonly,
|
||||||
Ref,
|
Ref,
|
||||||
ref,
|
ref,
|
||||||
|
watch,
|
||||||
} from "@nuxtjs/composition-api"
|
} from "@nuxtjs/composition-api"
|
||||||
import { Observable, Subscription } from "rxjs"
|
import { Observable, Subscription } from "rxjs"
|
||||||
|
|
||||||
@@ -58,3 +59,28 @@ export function useStream<T>(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function pluckRef<T, K extends keyof T>(ref: Ref<T>, key: K): Ref<T[K]> {
|
||||||
|
return customRef((track, trigger) => {
|
||||||
|
const stopWatching = watch(ref, (newVal, oldVal) => {
|
||||||
|
if (newVal[key] !== oldVal[key]) {
|
||||||
|
trigger()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
stopWatching()
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
get() {
|
||||||
|
track()
|
||||||
|
return ref.value[key]
|
||||||
|
},
|
||||||
|
set(value: T[K]) {
|
||||||
|
trigger()
|
||||||
|
ref.value = Object.assign(ref.value, { [key]: value })
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
export const knownContentTypes = [
|
|
||||||
"application/json",
|
|
||||||
"application/ld+json",
|
|
||||||
"application/hal+json",
|
|
||||||
"application/vnd.api+json",
|
|
||||||
"application/xml",
|
|
||||||
"application/x-www-form-urlencoded",
|
|
||||||
"multipart/form-data",
|
|
||||||
"text/html",
|
|
||||||
"text/plain",
|
|
||||||
]
|
|
||||||
|
|
||||||
export function isJSONContentType(contentType) {
|
|
||||||
return /\bjson\b/i.test(contentType)
|
|
||||||
}
|
|
||||||
13
helpers/utils/contenttypes.ts
Normal file
13
helpers/utils/contenttypes.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
export const knownContentTypes = {
|
||||||
|
"application/json": "json",
|
||||||
|
"application/ld+json": "json",
|
||||||
|
"application/hal+json": "json",
|
||||||
|
"application/vnd.api+json": "json",
|
||||||
|
"application/xml": "xml",
|
||||||
|
"application/x-www-form-urlencoded": "multipart",
|
||||||
|
"multipart/form-data": "multipart",
|
||||||
|
"text/html": "html",
|
||||||
|
"text/plain": "plain",
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ValidContentTypes = keyof typeof knownContentTypes
|
||||||
@@ -4,6 +4,7 @@ import DispatchingStore, { defineDispatchers } from "./DispatchingStore"
|
|||||||
import {
|
import {
|
||||||
HoppRESTHeader,
|
HoppRESTHeader,
|
||||||
HoppRESTParam,
|
HoppRESTParam,
|
||||||
|
HoppRESTReqBody,
|
||||||
HoppRESTRequest,
|
HoppRESTRequest,
|
||||||
RESTReqSchemaVersion,
|
RESTReqSchemaVersion,
|
||||||
} from "~/helpers/types/HoppRESTRequest"
|
} from "~/helpers/types/HoppRESTRequest"
|
||||||
@@ -127,6 +128,11 @@ const defaultRESTSession: RESTSession = {
|
|||||||
method: "GET",
|
method: "GET",
|
||||||
preRequestScript: "// pw.env.set('variable', 'value');",
|
preRequestScript: "// pw.env.set('variable', 'value');",
|
||||||
testScript: "// pw.expect('variable').toBe('value');",
|
testScript: "// pw.expect('variable').toBe('value');",
|
||||||
|
body: {
|
||||||
|
contentType: "application/json",
|
||||||
|
body: "",
|
||||||
|
isRaw: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
response: null,
|
response: null,
|
||||||
testResults: null,
|
testResults: null,
|
||||||
@@ -310,6 +316,14 @@ const dispatchers = defineDispatchers({
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
setRequestBody(curr: RESTSession, { newBody }: { newBody: HoppRESTReqBody }) {
|
||||||
|
return {
|
||||||
|
request: {
|
||||||
|
...curr.request,
|
||||||
|
body: newBody,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
updateResponse(
|
updateResponse(
|
||||||
_curr: RESTSession,
|
_curr: RESTSession,
|
||||||
{ updatedRes }: { updatedRes: HoppRESTResponse | null }
|
{ updatedRes }: { updatedRes: HoppRESTResponse | null }
|
||||||
@@ -454,6 +468,15 @@ export function setRESTTestScript(newScript: string) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setRESTReqBody(newBody: HoppRESTReqBody | null) {
|
||||||
|
restSessionStore.dispatch({
|
||||||
|
dispatcher: "setRequestBody",
|
||||||
|
payload: {
|
||||||
|
newBody,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export function updateRESTResponse(updatedRes: HoppRESTResponse | null) {
|
export function updateRESTResponse(updatedRes: HoppRESTResponse | null) {
|
||||||
restSessionStore.dispatch({
|
restSessionStore.dispatch({
|
||||||
dispatcher: "updateResponse",
|
dispatcher: "updateResponse",
|
||||||
@@ -522,6 +545,11 @@ export const restTestScript$ = restSessionStore.subject$.pipe(
|
|||||||
distinctUntilChanged()
|
distinctUntilChanged()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export const restReqBody$ = restSessionStore.subject$.pipe(
|
||||||
|
pluck("request", "body"),
|
||||||
|
distinctUntilChanged()
|
||||||
|
)
|
||||||
|
|
||||||
export const restResponse$ = restSessionStore.subject$.pipe(
|
export const restResponse$ = restSessionStore.subject$.pipe(
|
||||||
pluck("response"),
|
pluck("response"),
|
||||||
distinctUntilChanged()
|
distinctUntilChanged()
|
||||||
@@ -572,3 +600,11 @@ export function useTestScript(): Ref<string> {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useRESTRequestBody(): Ref<HoppRESTReqBody> {
|
||||||
|
return useStream(
|
||||||
|
restReqBody$,
|
||||||
|
restSessionStore.value.request.body,
|
||||||
|
setRESTReqBody
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
19
package-lock.json
generated
19
package-lock.json
generated
@@ -63,6 +63,7 @@
|
|||||||
"@testing-library/jest-dom": "^5.14.1",
|
"@testing-library/jest-dom": "^5.14.1",
|
||||||
"@types/cookie": "^0.4.1",
|
"@types/cookie": "^0.4.1",
|
||||||
"@types/lodash": "^4.14.171",
|
"@types/lodash": "^4.14.171",
|
||||||
|
"@types/splitpanes": "^2.2.1",
|
||||||
"@vue/test-utils": "^1.2.1",
|
"@vue/test-utils": "^1.2.1",
|
||||||
"babel-core": "^7.0.0-bridge.0",
|
"babel-core": "^7.0.0-bridge.0",
|
||||||
"babel-jest": "^27.0.6",
|
"babel-jest": "^27.0.6",
|
||||||
@@ -7389,6 +7390,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
|
||||||
"integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA=="
|
"integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/splitpanes": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/splitpanes/-/splitpanes-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-H5BgO6UdJRzz5ddRzuGvLBiPSPEuuHXb5ET+7avLLrEx1uc7f5Ut5oLMDQsfvGtHBBAFczt1QNYuDf27wHbvDQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"vue": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/stack-utils": {
|
"node_modules/@types/stack-utils": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz",
|
||||||
@@ -37392,6 +37402,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
|
||||||
"integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA=="
|
"integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA=="
|
||||||
},
|
},
|
||||||
|
"@types/splitpanes": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/splitpanes/-/splitpanes-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-H5BgO6UdJRzz5ddRzuGvLBiPSPEuuHXb5ET+7avLLrEx1uc7f5Ut5oLMDQsfvGtHBBAFczt1QNYuDf27wHbvDQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"vue": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/stack-utils": {
|
"@types/stack-utils": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz",
|
||||||
|
|||||||
@@ -79,6 +79,7 @@
|
|||||||
"@testing-library/jest-dom": "^5.14.1",
|
"@testing-library/jest-dom": "^5.14.1",
|
||||||
"@types/cookie": "^0.4.1",
|
"@types/cookie": "^0.4.1",
|
||||||
"@types/lodash": "^4.14.171",
|
"@types/lodash": "^4.14.171",
|
||||||
|
"@types/splitpanes": "^2.2.1",
|
||||||
"@vue/test-utils": "^1.2.1",
|
"@vue/test-utils": "^1.2.1",
|
||||||
"babel-core": "^7.0.0-bridge.0",
|
"babel-core": "^7.0.0-bridge.0",
|
||||||
"babel-jest": "^27.0.6",
|
"babel-jest": "^27.0.6",
|
||||||
|
|||||||
@@ -17,77 +17,7 @@
|
|||||||
</SmartTab>
|
</SmartTab>
|
||||||
|
|
||||||
<SmartTab :id="'bodyParams'" :label="$t('body')" info="0">
|
<SmartTab :id="'bodyParams'" :label="$t('body')" info="0">
|
||||||
<div class="flex flex-1 py-2 items-center justify-between">
|
<HttpBody />
|
||||||
<tippy
|
|
||||||
interactive
|
|
||||||
ref="contentTypeOptions"
|
|
||||||
tabindex="-1"
|
|
||||||
trigger="click"
|
|
||||||
theme="popover"
|
|
||||||
arrow
|
|
||||||
>
|
|
||||||
<template #trigger>
|
|
||||||
<div class="flex">
|
|
||||||
<span class="select-wrapper">
|
|
||||||
<input
|
|
||||||
id="contentType"
|
|
||||||
class="
|
|
||||||
bg-primary
|
|
||||||
rounded-lg
|
|
||||||
flex
|
|
||||||
font-semibold font-mono
|
|
||||||
text-xs
|
|
||||||
w-full
|
|
||||||
py-2
|
|
||||||
px-4
|
|
||||||
transition
|
|
||||||
truncate
|
|
||||||
focus:outline-none
|
|
||||||
"
|
|
||||||
v-model="contentType"
|
|
||||||
readonly
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<SmartItem
|
|
||||||
v-for="(contentTypeItem, index) in validContentTypes"
|
|
||||||
:key="`contentTypeItem-${index}`"
|
|
||||||
@click.native="
|
|
||||||
contentType = contentTypeItem
|
|
||||||
$refs.contentTypeOptions.tippy().hide()
|
|
||||||
"
|
|
||||||
:label="contentTypeItem"
|
|
||||||
/>
|
|
||||||
</tippy>
|
|
||||||
<SmartToggle
|
|
||||||
v-if="canListParameters"
|
|
||||||
:on="rawInput"
|
|
||||||
@change="rawInput = !rawInput"
|
|
||||||
class="px-4"
|
|
||||||
>
|
|
||||||
{{ $t("raw_input") }}
|
|
||||||
</SmartToggle>
|
|
||||||
</div>
|
|
||||||
<HttpBodyParameters
|
|
||||||
v-if="!rawInput"
|
|
||||||
:bodyParams="bodyParams"
|
|
||||||
@clear-content="clearContent"
|
|
||||||
@set-route-query-state="setRouteQueryState"
|
|
||||||
@remove-request-body-param="removeRequestBodyParam"
|
|
||||||
@add-request-body-param="addRequestBodyParam"
|
|
||||||
/>
|
|
||||||
<HttpRawBody
|
|
||||||
v-else
|
|
||||||
:rawParams="rawParams"
|
|
||||||
:contentType="contentType"
|
|
||||||
:rawInput="rawInput"
|
|
||||||
@clear-content="clearContent"
|
|
||||||
@update-raw-body="updateRawBody"
|
|
||||||
@update-raw-input="
|
|
||||||
updateRawInput = (value) => (rawInput = value)
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
</SmartTab>
|
</SmartTab>
|
||||||
|
|
||||||
<SmartTab
|
<SmartTab
|
||||||
@@ -555,18 +485,6 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
canListParameters: {
|
|
||||||
immediate: true,
|
|
||||||
handler(canListParameters) {
|
|
||||||
if (canListParameters) {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.rawInput = Boolean(this.rawParams && this.rawParams !== "{}")
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this.rawInput = true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
contentType(contentType, oldContentType) {
|
contentType(contentType, oldContentType) {
|
||||||
const getDefaultParams = (contentType) => {
|
const getDefaultParams = (contentType) => {
|
||||||
if (isJSONContentType(contentType)) return "{}"
|
if (isJSONContentType(contentType)) return "{}"
|
||||||
@@ -632,17 +550,6 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
/**
|
|
||||||
* Check content types that can be automatically
|
|
||||||
* serialized by Hoppscotch.
|
|
||||||
*/
|
|
||||||
canListParameters() {
|
|
||||||
return (
|
|
||||||
this.contentType === "application/x-www-form-urlencoded" ||
|
|
||||||
this.contentType === "multipart/form-data" ||
|
|
||||||
isJSONContentType(this.contentType)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
uri: {
|
uri: {
|
||||||
get() {
|
get() {
|
||||||
return this.$store.state.request.uri
|
return this.$store.state.request.uri
|
||||||
|
|||||||
Reference in New Issue
Block a user