From 0efbc58b2661cbcfd41cbadd21f636e98ce8cdd5 Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 19 Jan 2022 22:00:13 +0530 Subject: [PATCH 1/9] fix: urlencoded body params being improper --- .../hoppscotch-app/helpers/new-codegen/har.ts | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/packages/hoppscotch-app/helpers/new-codegen/har.ts b/packages/hoppscotch-app/helpers/new-codegen/har.ts index 04b81f59e..d4795ecbf 100644 --- a/packages/hoppscotch-app/helpers/new-codegen/har.ts +++ b/packages/hoppscotch-app/helpers/new-codegen/har.ts @@ -1,3 +1,6 @@ +import * as RA from "fp-ts/ReadonlyArray" +import * as S from "fp-ts/string" +import { pipe, flow } from "fp-ts/function" import * as Har from "har-format" import { HoppRESTRequest } from "@hoppscotch/data" import { FieldEquals, objectFieldIncludes } from "../typeutils" @@ -33,16 +36,24 @@ const buildHarPostParams = ( ): Har.Param[] => { // URL Encoded strings have a string style of contents if (req.body.contentType === "application/x-www-form-urlencoded") { - return req.body.body - .split("&") // Split by separators - .map((keyValue) => { - const [key, value] = keyValue.split("=") + return pipe( + req.body.body, + S.split("\n"), + RA.map( + flow( + // Define how each lines are parsed - return { - name: key, - value, - } - }) + S.split(":"), // Split by ":" + RA.map(S.trim), // Remove trailing spaces in key/value begins and ends + ([key, value]) => ({ + // Convert into a proper key value definition + name: key, + value: value ?? "", // Value can be undefined (if no ":" is present) + }) + ) + ), + RA.toArray + ) } else { // FormData has its own format return req.body.body.flatMap((entry) => { From 09269b3cecc9f44a2cb5e701d5f825e18efc470c Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Wed, 19 Jan 2022 23:11:26 +0530 Subject: [PATCH 2/9] fix: urlencoded form evaluation issues --- .../helpers/functional/debug.ts | 9 ++++++ .../helpers/functional/record.ts | 7 +++++ .../helpers/strategies/AxiosStrategy.ts | 7 +++-- .../helpers/utils/EffectiveURL.ts | 24 ++++++++++++++++ packages/hoppscotch-app/package.json | 1 + pnpm-lock.yaml | 28 +++++++++---------- 6 files changed, 58 insertions(+), 18 deletions(-) create mode 100644 packages/hoppscotch-app/helpers/functional/debug.ts create mode 100644 packages/hoppscotch-app/helpers/functional/record.ts diff --git a/packages/hoppscotch-app/helpers/functional/debug.ts b/packages/hoppscotch-app/helpers/functional/debug.ts new file mode 100644 index 000000000..74c29642b --- /dev/null +++ b/packages/hoppscotch-app/helpers/functional/debug.ts @@ -0,0 +1,9 @@ +/** + * Logs the current value and returns the same value + * @param x The value to log + * @returns The parameter `x` passed to this + */ +export const trace = (x: T) => { + console.log(x) + return x +} diff --git a/packages/hoppscotch-app/helpers/functional/record.ts b/packages/hoppscotch-app/helpers/functional/record.ts new file mode 100644 index 000000000..35ac793c5 --- /dev/null +++ b/packages/hoppscotch-app/helpers/functional/record.ts @@ -0,0 +1,7 @@ +export const tupleToRecord = < + KeyType extends string | number | symbol, + ValueType +>( + tuples: [KeyType, ValueType][] +): Record => + (Object.assign as any)(...tuples.map(([key, val]) => ({ [key]: val }))) diff --git a/packages/hoppscotch-app/helpers/strategies/AxiosStrategy.ts b/packages/hoppscotch-app/helpers/strategies/AxiosStrategy.ts index 82e62129e..5d21ab14e 100644 --- a/packages/hoppscotch-app/helpers/strategies/AxiosStrategy.ts +++ b/packages/hoppscotch-app/helpers/strategies/AxiosStrategy.ts @@ -122,8 +122,9 @@ const axiosWithoutProxy: NetworkStrategy = (req) => ) const axiosStrategy: NetworkStrategy = (req) => - settingsStore.value.PROXY_ENABLED - ? axiosWithProxy(req) - : axiosWithoutProxy(req) + pipe( + req, + settingsStore.value.PROXY_ENABLED ? axiosWithProxy : axiosWithoutProxy + ) export default axiosStrategy diff --git a/packages/hoppscotch-app/helpers/utils/EffectiveURL.ts b/packages/hoppscotch-app/helpers/utils/EffectiveURL.ts index 85630f12f..73dbd0928 100644 --- a/packages/hoppscotch-app/helpers/utils/EffectiveURL.ts +++ b/packages/hoppscotch-app/helpers/utils/EffectiveURL.ts @@ -1,3 +1,7 @@ +import * as RA from "fp-ts/ReadonlyArray" +import * as S from "fp-ts/string" +import qs from "qs" +import { pipe, flow } from "fp-ts/function" import { combineLatest, Observable } from "rxjs" import { map } from "rxjs/operators" import { @@ -6,6 +10,7 @@ import { HoppRESTRequest, } from "@hoppscotch/data" import { parseTemplateString, parseBodyEnvVariables } from "../templating" +import { tupleToRecord } from "../functional/record" import { Environment, getGlobalVariables } from "~/newstore/environments" export interface EffectiveHoppRESTRequest extends HoppRESTRequest { @@ -58,6 +63,25 @@ function getFinalBodyFromRequest( return null } + if (request.body.contentType === "application/x-www-form-urlencoded") { + return pipe( + request.body.body, + S.split("\n"), + RA.map( + flow( + // Define how each lines are parsed + + S.split(":"), // Split by ":" + RA.map(S.trim), // Remove trailing spaces in key/value begins and ends + ([key, value]) => [key, value ?? ""] as [string, string] // Add a default empty by default + ) + ), + RA.toArray, + tupleToRecord, // Convert the tuple to a record + qs.stringify + ) + } + if (request.body.contentType === "multipart/form-data") { const formData = new FormData() diff --git a/packages/hoppscotch-app/package.json b/packages/hoppscotch-app/package.json index 053585b44..c6683ab36 100644 --- a/packages/hoppscotch-app/package.json +++ b/packages/hoppscotch-app/package.json @@ -94,6 +94,7 @@ "openapi-types": "^10.0.0", "paho-mqtt": "^1.1.0", "postman-collection": "^4.1.1", + "qs": "^6.10.3", "rxjs": "^7.5.2", "socket.io-client-v2": "npm:socket.io-client@^2.4.0", "socket.io-client-v3": "npm:socket.io-client@^3.1.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e52495288..a110d19ad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -153,6 +153,7 @@ importers: paho-mqtt: ^1.1.0 postman-collection: ^4.1.1 prettier: ^2.5.1 + qs: ^6.10.3 raw-loader: ^4.0.2 rxjs: ^7.5.2 sass: ^1.47.0 @@ -245,6 +246,7 @@ importers: openapi-types: 10.0.0 paho-mqtt: 1.1.0 postman-collection: 4.1.1 + qs: 6.10.3 rxjs: 7.5.2 socket.io-client-v2: /socket.io-client/2.4.0 socket.io-client-v3: /socket.io-client/3.1.3 @@ -3764,11 +3766,11 @@ packages: ufo: 0.7.9 dev: false - /@nuxt/kit-edge/3.0.0-27376999.6abf75d: - resolution: {integrity: sha512-9VdJR9s9TXHd+lRRZnZRV+5GwkWKYomIS5NONMVgBDFjxotvqkVsCbpHvUja2I0NlcAxKnFePgqeDC20CBrgHQ==} + /@nuxt/kit-edge/3.0.0-27379437.ed2d26f: + resolution: {integrity: sha512-6rGJDifwA4J/9+sN0yVKU3CLsQmK/fRQUvQLqq830wBI8ORPhNu4gXULoT0cdWPzKcera8e8Hz9iqL9aCjFNBw==} engines: {node: ^14.16.0 || ^16.11.0 || ^17.0.0} dependencies: - '@nuxt/schema': /@nuxt/schema-edge/3.0.0-27376999.6abf75d + '@nuxt/schema': /@nuxt/schema-edge/3.0.0-27379437.ed2d26f consola: 2.15.3 defu: 5.0.1 dotenv: 14.2.0 @@ -3806,8 +3808,8 @@ packages: node-fetch: 2.6.6 dev: false - /@nuxt/schema-edge/3.0.0-27376999.6abf75d: - resolution: {integrity: sha512-BdoTPuXoHT3aqQL37g/SPk1jOFO4pHbEClsj/5X6cLKwktTcqSbMkwZJF0tTyhvAwiOSFdlTvI34juPhvLNzPw==} + /@nuxt/schema-edge/3.0.0-27379437.ed2d26f: + resolution: {integrity: sha512-2KJ5/cQasFv0nrkwc2+mi9oGRFkU73luRQGA0SFAONsPTa+x+4C2Qdnav7F9KNnl95OCsGgZMblQUyCTLVdHxA==} engines: {node: ^14.16.0 || ^16.11.0 || ^17.0.0} dependencies: create-require: 1.1.1 @@ -8617,7 +8619,7 @@ packages: is-shared-array-buffer: 1.0.1 is-string: 1.0.7 is-weakref: 1.0.1 - object-inspect: 1.11.0 + object-inspect: 1.12.0 object-keys: 1.1.1 object.assign: 4.1.2 string.prototype.trimend: 1.0.4 @@ -13547,7 +13549,7 @@ packages: /nuxt-windicss/2.2.2: resolution: {integrity: sha512-4tvzk9d2TUFxloty187D+wmO8ZNAvpSmRJ5HQO3/AvZdMMhAl4gomXR9fCgFKQe7Fxcj9nIKNInOx8TWowjiqA==} dependencies: - '@nuxt/kit': /@nuxt/kit-edge/3.0.0-27376999.6abf75d + '@nuxt/kit': /@nuxt/kit-edge/3.0.0-27379437.ed2d26f '@windicss/plugin-utils': 1.6.1 consola: 2.15.3 defu: 5.0.0 @@ -13611,12 +13613,8 @@ packages: define-property: 0.2.5 kind-of: 3.2.2 - /object-inspect/1.11.0: - resolution: {integrity: sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==} - /object-inspect/1.12.0: resolution: {integrity: sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==} - dev: false /object-keys/1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} @@ -13971,7 +13969,7 @@ packages: dependencies: is-ssh: 1.3.3 protocols: 1.4.8 - qs: 6.10.1 + qs: 6.10.3 query-string: 6.14.1 dev: false @@ -15209,8 +15207,8 @@ packages: resolution: {integrity: sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=} engines: {node: '>=0.6.0', teleport: '>=0.2.0'} - /qs/6.10.1: - resolution: {integrity: sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==} + /qs/6.10.3: + resolution: {integrity: sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==} engines: {node: '>=0.6'} dependencies: side-channel: 1.0.4 @@ -16094,7 +16092,7 @@ packages: dependencies: call-bind: 1.0.2 get-intrinsic: 1.1.1 - object-inspect: 1.11.0 + object-inspect: 1.12.0 /sigmund/1.0.1: resolution: {integrity: sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=} From 73cccf73df12df43c0a2303a34483585a94b88c5 Mon Sep 17 00:00:00 2001 From: Andrew Bastin Date: Fri, 21 Jan 2022 19:32:05 +0530 Subject: [PATCH 3/9] refactor: urlencoded key value pair system --- .../hoppscotch-app/components/http/Body.vue | 3 + .../components/http/URLEncodedParams.vue | 342 ++++++++++++++++++ .../helpers/functional/array.ts | 2 + .../hoppscotch-app/helpers/rawKeyValue.ts | 39 ++ .../helpers/utils/EffectiveURL.ts | 25 +- .../hoppscotch-app/newstore/RESTSession.ts | 51 +++ 6 files changed, 448 insertions(+), 14 deletions(-) create mode 100644 packages/hoppscotch-app/components/http/URLEncodedParams.vue create mode 100644 packages/hoppscotch-app/helpers/functional/array.ts create mode 100644 packages/hoppscotch-app/helpers/rawKeyValue.ts diff --git a/packages/hoppscotch-app/components/http/Body.vue b/packages/hoppscotch-app/components/http/Body.vue index f2a635210..368766c44 100644 --- a/packages/hoppscotch-app/components/http/Body.vue +++ b/packages/hoppscotch-app/components/http/Body.vue @@ -50,6 +50,9 @@ +
+
+
+ +
+ + + + +
+
+
+
+
+ + + + + + + + +
+
+ + + {{ t("empty.headers") }} + + +
+
+
+ + + diff --git a/packages/hoppscotch-app/helpers/functional/array.ts b/packages/hoppscotch-app/helpers/functional/array.ts new file mode 100644 index 000000000..f2e387d17 --- /dev/null +++ b/packages/hoppscotch-app/helpers/functional/array.ts @@ -0,0 +1,2 @@ +export const stringArrayJoin = (separator: string) => (arr: string[]) => + arr.join(separator) diff --git a/packages/hoppscotch-app/helpers/rawKeyValue.ts b/packages/hoppscotch-app/helpers/rawKeyValue.ts new file mode 100644 index 000000000..b89f2d3ac --- /dev/null +++ b/packages/hoppscotch-app/helpers/rawKeyValue.ts @@ -0,0 +1,39 @@ +import * as A from "fp-ts/Array" +import * as RA from "fp-ts/ReadonlyArray" +import * as S from "fp-ts/string" +import { pipe, flow } from "fp-ts/function" +import { stringArrayJoin } from "./functional/array" + +export type RawKeyValueEntry = { + key: string + value: string + active: boolean +} + +const parseRawKeyValueEntry = (str: string): RawKeyValueEntry => { + const trimmed = str.trim() + const inactive = trimmed.startsWith("#") + + const [key, value] = trimmed.split(":").map(S.trim) + + return { + key: inactive ? key.replaceAll(/^#+\s*/g, "") : key, // Remove comment hash and early space + value, + active: !inactive, + } +} + +export const parseRawKeyValueEntries = flow( + S.split("\n"), + RA.map(parseRawKeyValueEntry), + RA.toArray +) + +export const rawKeyValueEntriesToString = (entries: RawKeyValueEntry[]) => + pipe( + entries, + A.map(({ key, value, active }) => + active ? `${key}: ${value}` : `# ${key}: ${value}` + ), + stringArrayJoin("\n") + ) diff --git a/packages/hoppscotch-app/helpers/utils/EffectiveURL.ts b/packages/hoppscotch-app/helpers/utils/EffectiveURL.ts index 73dbd0928..d204dd750 100644 --- a/packages/hoppscotch-app/helpers/utils/EffectiveURL.ts +++ b/packages/hoppscotch-app/helpers/utils/EffectiveURL.ts @@ -1,7 +1,6 @@ -import * as RA from "fp-ts/ReadonlyArray" -import * as S from "fp-ts/string" +import * as A from "fp-ts/Array" import qs from "qs" -import { pipe, flow } from "fp-ts/function" +import { pipe } from "fp-ts/function" import { combineLatest, Observable } from "rxjs" import { map } from "rxjs/operators" import { @@ -11,6 +10,7 @@ import { } from "@hoppscotch/data" import { parseTemplateString, parseBodyEnvVariables } from "../templating" import { tupleToRecord } from "../functional/record" +import { parseRawKeyValueEntries } from "../rawKeyValue" import { Environment, getGlobalVariables } from "~/newstore/environments" export interface EffectiveHoppRESTRequest extends HoppRESTRequest { @@ -66,18 +66,15 @@ function getFinalBodyFromRequest( if (request.body.contentType === "application/x-www-form-urlencoded") { return pipe( request.body.body, - S.split("\n"), - RA.map( - flow( - // Define how each lines are parsed + parseRawKeyValueEntries, - S.split(":"), // Split by ":" - RA.map(S.trim), // Remove trailing spaces in key/value begins and ends - ([key, value]) => [key, value ?? ""] as [string, string] // Add a default empty by default - ) - ), - RA.toArray, - tupleToRecord, // Convert the tuple to a record + // Filter out active + A.filter((x) => x.active), + // Convert to tuple + A.map(({ key, value }) => [key, value] as [string, string]), + // Tuple to Record object + tupleToRecord, + // Stringify qs.stringify ) } diff --git a/packages/hoppscotch-app/newstore/RESTSession.ts b/packages/hoppscotch-app/newstore/RESTSession.ts index 324f1aaf9..d00d7314f 100644 --- a/packages/hoppscotch-app/newstore/RESTSession.ts +++ b/packages/hoppscotch-app/newstore/RESTSession.ts @@ -1,3 +1,5 @@ +import * as A from "fp-ts/Array" +import { pipe } from "fp-ts/function" import { pluck, distinctUntilChanged, map, filter } from "rxjs/operators" import { Ref } from "@nuxtjs/composition-api" import { @@ -15,6 +17,11 @@ import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse" import { useStream } from "~/helpers/utils/composables" import { HoppTestResult } from "~/helpers/types/HoppTestResult" import { HoppRequestSaveContext } from "~/helpers/types/HoppRequestSaveContext" +import { + parseRawKeyValueEntries, + rawKeyValueEntriesToString, + RawKeyValueEntry, +} from "~/helpers/rawKeyValue" type RESTSession = { request: HoppRESTRequest @@ -203,9 +210,30 @@ const dispatchers = defineDispatchers({ curr: RESTSession, { newContentType }: { newContentType: ValidContentTypes | null } ) { + // TODO: Cleaner implementation // TODO: persist body evenafter switching content typees if (curr.request.body.contentType !== "multipart/form-data") { if (newContentType === "multipart/form-data") { + // Preserve entries when comping from urlencoded to multipart + if ( + curr.request.body.contentType === "application/x-www-form-urlencoded" + ) { + return { + ...curr.request, + body: { + contentType: "multipart/form-data", + body: pipe( + curr.request.body.body, + parseRawKeyValueEntries, + A.map( + ({ key, value, active }) => + { key, value, active, isFile: false } + ) + ), + }, + } + } + // Going from non-formdata to form-data, discard contents and set empty array as body return { request: { @@ -232,6 +260,29 @@ const dispatchers = defineDispatchers({ } } } else if (newContentType !== "multipart/form-data") { + if (newContentType === "application/x-www-form-urlencoded") { + return { + request: { + ...curr.request, + body: { + contentType: newContentType, + body: pipe( + curr.request.body.body, + A.map( + ({ key, value, isFile, active }) => + { + key, + value: isFile ? "" : value, + active, + } + ), + rawKeyValueEntriesToString + ), + }, + }, + } + } + // Going from formdata to non-formdata, discard contents and set empty string return { request: { From 1ba89a0f0b734e86b22ed765025bba20b89ece30 Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Fri, 21 Jan 2022 23:21:23 +0530 Subject: [PATCH 4/9] fix: url encoded binding --- .../hoppscotch-app/components/http/Body.vue | 2 +- .../components/http/URLEncodedParams.vue | 155 +++++++++--------- 2 files changed, 80 insertions(+), 77 deletions(-) diff --git a/packages/hoppscotch-app/components/http/Body.vue b/packages/hoppscotch-app/components/http/Body.vue index 368766c44..3f4b9fb32 100644 --- a/packages/hoppscotch-app/components/http/Body.vue +++ b/packages/hoppscotch-app/components/http/Body.vue @@ -51,7 +51,7 @@
- @@ -88,25 +83,25 @@ @@ -117,7 +112,7 @@ :title="t('action.remove')" svg="trash" color="red" - @click.native="deleteHeader(index)" + @click.native="deleteUrlEncodedParam(index)" />
@@ -129,17 +124,17 @@ :src="`/images/states/${$colorMode.value}/add_category.svg`" loading="lazy" class="inline-flex flex-col object-contain object-center w-16 h-16 my-4" - :alt="`${t('empty.headers')}`" + :alt="`${t('empty.body')}`" /> - {{ t("empty.headers") }} + {{ t("empty.body") }}
@@ -150,11 +145,11 @@ import { Ref, ref, watch } from "@nuxtjs/composition-api" import isEqual from "lodash/isEqual" import clone from "lodash/clone" -import { HoppRESTHeader } from "@hoppscotch/data" +import { HoppRESTReqBody } from "@hoppscotch/data" import { useCodemirror } from "~/helpers/editor/codemirror" -import { restHeaders$, setRESTHeaders } from "~/newstore/RESTSession" -import { commonHeaders } from "~/helpers/headers" -import { useI18n, useStream, useToast } from "~/helpers/utils/composables" +import { useRESTRequestBody } from "~/newstore/RESTSession" +import { pluckRef, useI18n, useToast } from "~/helpers/utils/composables" +import { RawKeyValueEntry } from "~/helpers/rawKeyValue" const t = useI18n() const toast = useToast() @@ -175,13 +170,16 @@ useCodemirror(bulkEditor, bulkUrlEncodedParams, { environmentHighlights: true, }) -// The functional headers list (the headers actually in the system) -const headers = useStream(restHeaders$, [], setRESTHeaders) as Ref< - HoppRESTHeader[] -> +// The functional urlEncodedParams list (the urlEncodedParams actually in the system) +const urlEncodedParams = pluckRef( + useRESTRequestBody() as Ref< + HoppRESTReqBody & { contentType: "application/x-www-form-urlencoded" } + >, + "body" +) -// The UI representation of the headers list (has the empty end header) -const workingUrlEncodedParams = ref([ +// The UI representation of the urlEncodedParams list (has the empty end urlEncodedParam) +const workingUrlEncodedParams = ref([ { key: "", value: "", @@ -189,11 +187,11 @@ const workingUrlEncodedParams = ref([ }, ]) -// Rule: Working Headers always have one empty header or the last element is always an empty header -watch(workingUrlEncodedParams, (headersList) => { +// Rule: Working urlEncodedParams always have one empty urlEncodedParam or the last element is always an empty urlEncodedParams +watch(workingUrlEncodedParams, (urlEncodedParamList) => { if ( - headersList.length > 0 && - headersList[headersList.length - 1].key !== "" + urlEncodedParamList.length > 0 && + urlEncodedParamList[urlEncodedParamList.length - 1].key !== "" ) { workingUrlEncodedParams.value.push({ key: "", @@ -203,29 +201,31 @@ watch(workingUrlEncodedParams, (headersList) => { } }) -// Sync logic between headers and working headers +// Sync logic between urlEncodedParams and working urlEncodedParams watch( - headers, - (newHeadersList) => { - // Sync should overwrite working headers + urlEncodedParams, + (newurlEncodedParamList) => { + // Sync should overwrite working urlEncodedParams const filteredWorkingUrlEncodedParams = workingUrlEncodedParams.value.filter((e) => e.key !== "") - if (!isEqual(newHeadersList, filteredWorkingUrlEncodedParams)) { - workingUrlEncodedParams.value = newHeadersList + if (!isEqual(newurlEncodedParamList, filteredWorkingUrlEncodedParams)) { + workingUrlEncodedParams.value = newurlEncodedParamList } }, { immediate: true } ) watch(workingUrlEncodedParams, (newWorkingUrlEncodedParams) => { - const fixedHeaders = newWorkingUrlEncodedParams.filter((e) => e.key !== "") - if (!isEqual(headers.value, fixedHeaders)) { - headers.value = fixedHeaders + const fixedUrlEncodedParams = newWorkingUrlEncodedParams.filter( + (e) => e.key !== "" + ) + if (!isEqual(urlEncodedParams.value, fixedUrlEncodedParams)) { + urlEncodedParams.value = fixedUrlEncodedParams } }) -// Bulk Editor Syncing with Working Headers +// Bulk Editor Syncing with Working urlEncodedParams watch(bulkUrlEncodedParams, () => { try { const transformation = bulkUrlEncodedParams.value @@ -237,11 +237,11 @@ watch(bulkUrlEncodedParams, () => { active: !item.trim().startsWith("#"), })) - const filteredHeaders = workingUrlEncodedParams.value.filter( + const filteredUrlEncodedParams = workingUrlEncodedParams.value.filter( (x) => x.key !== "" ) - if (!isEqual(filteredHeaders, transformation)) { + if (!isEqual(filteredUrlEncodedParams, transformation)) { workingUrlEncodedParams.value = transformation } } catch (e) { @@ -250,7 +250,7 @@ watch(bulkUrlEncodedParams, () => { } }) -watch(workingUrlEncodedParams, (newHeadersList) => { +watch(workingUrlEncodedParams, (newurlEncodedParamList) => { // If we are in bulk mode, don't apply direct changes if (bulkMode.value) return @@ -263,12 +263,14 @@ watch(workingUrlEncodedParams, (newHeadersList) => { active: !item.trim().startsWith("#"), })) - const filteredHeaders = newHeadersList.filter((x) => x.key !== "") + const filteredUrlEncodedParams = newurlEncodedParamList.filter( + (x) => x.key !== "" + ) - if (!isEqual(currentBulkUrlEncodedParams, filteredHeaders)) { - bulkUrlEncodedParams.value = filteredHeaders - .map((header) => { - return `${header.active ? "" : "#"}${header.key}: ${header.value}` + if (!isEqual(currentBulkUrlEncodedParams, filteredUrlEncodedParams)) { + bulkUrlEncodedParams.value = filteredUrlEncodedParams + .map((param) => { + return `${param.active ? "" : "#"}${param.key}: ${param.value}` }) .join("\n") } @@ -278,7 +280,8 @@ watch(workingUrlEncodedParams, (newHeadersList) => { } }) -const addHeader = () => { +const addUrlEncodedParam = () => { + debugger workingUrlEncodedParams.value.push({ key: "", value: "", @@ -286,19 +289,19 @@ const addHeader = () => { }) } -const updateHeader = (index: number, header: HoppRESTHeader) => { - workingUrlEncodedParams.value = workingUrlEncodedParams.value.map((h, i) => - i === index ? header : h +const updateUrlEncodedParam = (index: number, param: RawKeyValueEntry) => { + workingUrlEncodedParams.value = workingUrlEncodedParams.value.map((p, i) => + i === index ? param : p ) } -const deleteHeader = (index: number) => { - const headersBeforeDeletion = clone(workingUrlEncodedParams.value) +const deleteUrlEncodedParam = (index: number) => { + const urlEncodedParamsBeforeDeletion = clone(workingUrlEncodedParams.value) if ( !( - headersBeforeDeletion.length > 0 && - index === headersBeforeDeletion.length - 1 + urlEncodedParamsBeforeDeletion.length > 0 && + index === urlEncodedParamsBeforeDeletion.length - 1 ) ) { if (deletionToast.value) { @@ -311,7 +314,7 @@ const deleteHeader = (index: number) => { { text: `${t("action.undo")}`, onClick: (_, toastObject) => { - workingUrlEncodedParams.value = headersBeforeDeletion + workingUrlEncodedParams.value = urlEncodedParamsBeforeDeletion toastObject.goAway(0) deletionToast.value = null }, @@ -328,7 +331,7 @@ const deleteHeader = (index: number) => { } const clearContent = () => { - // set headers list to the initial state + // set urlEncodedParams list to the initial state workingUrlEncodedParams.value = [ { key: "", From b57b9481070d83faa51ca6b40dd158e865edc948 Mon Sep 17 00:00:00 2001 From: liyasthomas Date: Sat, 22 Jan 2022 19:12:23 +0530 Subject: [PATCH 5/9] fix: urlencoded formdata key value params ui Co-authored-by: Andrew Bastin --- .../components/http/URLEncodedParams.vue | 22 ++++++++++++++----- .../helpers/functional/record.ts | 4 +++- .../hoppscotch-app/helpers/rawKeyValue.ts | 1 + 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/packages/hoppscotch-app/components/http/URLEncodedParams.vue b/packages/hoppscotch-app/components/http/URLEncodedParams.vue index 292392f1d..7d219f957 100644 --- a/packages/hoppscotch-app/components/http/URLEncodedParams.vue +++ b/packages/hoppscotch-app/components/http/URLEncodedParams.vue @@ -142,14 +142,18 @@