From 6b1ca1dce111b426aa39b045b3d0869b567d6598 Mon Sep 17 00:00:00 2001 From: Nivedin <53208152+nivedin@users.noreply.github.com> Date: Fri, 10 Jun 2022 18:12:40 +0530 Subject: [PATCH] feat: filter json body response (#2404) --- .../hoppscotch-app/assets/icons/filter.svg | 13 ++ .../hoppscotch-app/assets/scss/themes.scss | 3 + .../lenses/renderers/JSONLensRenderer.vue | 134 +++++++++++++++++- packages/hoppscotch-app/locales/en.json | 4 + packages/hoppscotch-app/package.json | 1 + .../hoppscotch-app/types/jsonpath-plus.d.ts | 6 + packages/hoppscotch-app/windi.config.js | 1 + pnpm-lock.yaml | 25 ++-- 8 files changed, 174 insertions(+), 13 deletions(-) create mode 100644 packages/hoppscotch-app/assets/icons/filter.svg create mode 100644 packages/hoppscotch-app/types/jsonpath-plus.d.ts diff --git a/packages/hoppscotch-app/assets/icons/filter.svg b/packages/hoppscotch-app/assets/icons/filter.svg new file mode 100644 index 000000000..7a4f7d09c --- /dev/null +++ b/packages/hoppscotch-app/assets/icons/filter.svg @@ -0,0 +1,13 @@ + + + diff --git a/packages/hoppscotch-app/assets/scss/themes.scss b/packages/hoppscotch-app/assets/scss/themes.scss index a1b025231..f641e8fcb 100644 --- a/packages/hoppscotch-app/assets/scss/themes.scss +++ b/packages/hoppscotch-app/assets/scss/themes.scss @@ -255,6 +255,7 @@ --upper-mobile-raw-tertiary-sticky-fold: 8.188rem; --lower-primary-sticky-fold: 3rem; --lower-secondary-sticky-fold: 5rem; + --lower-tertiary-sticky-fold: 7.05rem; --sidebar-primary-sticky-fold: 2rem; } @@ -270,6 +271,7 @@ --upper-mobile-raw-tertiary-sticky-fold: 8.938rem; --lower-primary-sticky-fold: 3.25rem; --lower-secondary-sticky-fold: 5.5rem; + --lower-tertiary-sticky-fold: 7.8rem; --sidebar-primary-sticky-fold: 2.25rem; } @@ -285,6 +287,7 @@ --upper-mobile-raw-tertiary-sticky-fold: 9.688rem; --lower-primary-sticky-fold: 3.5rem; --lower-secondary-sticky-fold: 6rem; + --lower-tertiary-sticky-fold: 8.55rem; --sidebar-primary-sticky-fold: 2.5rem; } diff --git a/packages/hoppscotch-app/components/lenses/renderers/JSONLensRenderer.vue b/packages/hoppscotch-app/components/lenses/renderers/JSONLensRenderer.vue index 1bf8e9c0c..ffbca8951 100644 --- a/packages/hoppscotch-app/components/lenses/renderers/JSONLensRenderer.vue +++ b/packages/hoppscotch-app/components/lenses/renderers/JSONLensRenderer.vue @@ -1,12 +1,15 @@ - + {{ t("response.body") }} - + + - + + + + + + + + + {{ filterResponseError.error }} + + + + + import * as LJSON from "lossless-json" import * as O from "fp-ts/Option" +import * as E from "fp-ts/Either" import { pipe } from "fp-ts/function" import { computed, ref, reactive } from "@nuxtjs/composition-api" +import { JSONPath } from "jsonpath-plus" import { useCodemirror } from "~/helpers/editor/codemirror" import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse" import jsonParse, { JSONObjectMember, JSONValue } from "~/helpers/jsonParse" @@ -172,9 +225,51 @@ const { downloadIcon, downloadResponse } = useDownloadResponse( responseBodyText ) -const jsonBodyText = computed(() => +const toggleFilter = ref(false) +const filterQueryText = ref("") + +type BodyParseError = + | { type: "JSON_PARSE_FAILED" } + | { type: "JSON_PATH_QUERY_FAILED"; error: Error } + +const responseJsonObject = computed(() => pipe( responseBodyText.value, + E.tryCatchK( + LJSON.parse, + (): BodyParseError => ({ type: "JSON_PARSE_FAILED" }) + ) + ) +) + +const jsonResponseBodyText = computed(() => { + if (filterQueryText.value.length > 0) { + return pipe( + responseJsonObject.value, + E.chain((parsedJSON) => + E.tryCatch( + () => + JSONPath({ + path: filterQueryText.value, + json: parsedJSON, + }) as undefined, + (err): BodyParseError => ({ + type: "JSON_PATH_QUERY_FAILED", + error: err as Error, + }) + ) + ), + E.map(JSON.stringify) + ) + } else { + return E.right(responseBodyText.value) + } +}) + +const jsonBodyText = computed(() => + pipe( + jsonResponseBodyText.value, + E.getOrElse(() => responseBodyText.value), O.tryCatchK(LJSON.parse), O.map((val) => LJSON.stringify(val, undefined, 2)), O.getOrElse(() => responseBodyText.value) @@ -189,6 +284,32 @@ const ast = computed(() => ) ) +const filterResponseError = computed(() => + pipe( + jsonResponseBodyText.value, + E.match( + (e) => { + switch (e.type) { + case "JSON_PATH_QUERY_FAILED": + return { type: "JSON_PATH_QUERY_ERROR", error: e.error.message } + case "JSON_PARSE_FAILED": + return { + type: "JSON_PARSE_FAILED", + error: t("error.json_parsing_failed").toString(), + } + } + }, + (result) => + result === "[]" + ? { + type: "RESPONSE_EMPTY", + error: t("error.no_results_found").toString(), + } + : undefined + ) + ) +) + const outlineOptions = ref(null) const jsonResponse = ref(null) const linewrapEnabled = ref(true) @@ -227,6 +348,11 @@ const outlinePath = computed(() => O.getOrElseW(() => null) ) ) + +const toggleFilterState = () => { + filterQueryText.value = "" + toggleFilter.value = !toggleFilter.value +}