RawLensRenderer.vue 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. <template>
  2. <div class="flex flex-col flex-1">
  3. <div
  4. class="sticky z-10 flex items-center justify-between pl-4 border-b bg-primary border-dividerLight top-lowerSecondaryStickyFold"
  5. >
  6. <label class="font-semibold text-secondaryLight">
  7. {{ t("response.body") }}
  8. </label>
  9. <div class="flex">
  10. <ButtonSecondary
  11. v-if="response.body"
  12. v-tippy="{ theme: 'tooltip' }"
  13. :title="t('state.linewrap')"
  14. :class="{ '!text-accent': linewrapEnabled }"
  15. svg="wrap-text"
  16. @click.native.prevent="linewrapEnabled = !linewrapEnabled"
  17. />
  18. <ButtonSecondary
  19. v-if="response.body"
  20. ref="downloadResponse"
  21. v-tippy="{ theme: 'tooltip' }"
  22. :title="t('action.download_file')"
  23. :svg="downloadIcon"
  24. @click.native="downloadResponse"
  25. />
  26. <ButtonSecondary
  27. v-if="response.body"
  28. ref="copyResponse"
  29. v-tippy="{ theme: 'tooltip' }"
  30. :title="t('action.copy')"
  31. :svg="copyIcon"
  32. @click.native="copyResponse"
  33. />
  34. </div>
  35. </div>
  36. <div ref="rawResponse" class="flex flex-col flex-1"></div>
  37. </div>
  38. </template>
  39. <script setup lang="ts">
  40. import { ref, computed, reactive } from "@nuxtjs/composition-api"
  41. import { flow, pipe } from "fp-ts/function"
  42. import * as S from "fp-ts/string"
  43. import * as RNEA from "fp-ts/ReadonlyNonEmptyArray"
  44. import * as A from "fp-ts/Array"
  45. import * as O from "fp-ts/Option"
  46. import { useCodemirror } from "~/helpers/editor/codemirror"
  47. import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
  48. import { useI18n } from "~/helpers/utils/composables"
  49. import useResponseBody from "~/helpers/lenses/composables/useResponseBody"
  50. import useDownloadResponse from "~/helpers/lenses/composables/useDownloadResponse"
  51. import useCopyResponse from "~/helpers/lenses/composables/useCopyResponse"
  52. import { objFieldMatches } from "~/helpers/functional/object"
  53. const t = useI18n()
  54. const props = defineProps<{
  55. response: HoppRESTResponse
  56. }>()
  57. const { responseBodyText } = useResponseBody(props.response)
  58. const rawResponseBody = computed(() =>
  59. props.response.type === "fail" || props.response.type === "success"
  60. ? props.response.body
  61. : new ArrayBuffer(0)
  62. )
  63. const responseType = computed(() =>
  64. pipe(
  65. props.response,
  66. O.fromPredicate(objFieldMatches("type", ["fail", "success"] as const)),
  67. O.chain(
  68. // Try getting content-type
  69. flow(
  70. (res) => res.headers,
  71. A.findFirst((h) => h.key.toLowerCase() === "content-type"),
  72. O.map(flow((h) => h.value, S.split(";"), RNEA.head, S.toLowerCase))
  73. )
  74. ),
  75. O.getOrElse(() => "text/plain")
  76. )
  77. )
  78. const { downloadIcon, downloadResponse } = useDownloadResponse(
  79. responseType.value,
  80. rawResponseBody
  81. )
  82. const { copyIcon, copyResponse } = useCopyResponse(responseBodyText)
  83. const rawResponse = ref<any | null>(null)
  84. const linewrapEnabled = ref(true)
  85. useCodemirror(
  86. rawResponse,
  87. responseBodyText,
  88. reactive({
  89. extendedEditorConfig: {
  90. mode: "text/plain",
  91. readOnly: true,
  92. lineWrapping: linewrapEnabled,
  93. },
  94. linter: null,
  95. completer: null,
  96. environmentHighlights: true,
  97. })
  98. )
  99. </script>