Response.vue 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. <template>
  2. <div
  3. class="flex flex-col flex-1 overflow-auto hide-scrollbar whitespace-nowrap"
  4. >
  5. <div
  6. v-if="responseString === 'loading'"
  7. class="flex flex-col items-center justify-center p-4 text-secondaryLight"
  8. >
  9. <SmartSpinner class="my-4" />
  10. <span class="text-secondaryLight">{{ t("state.loading") }}</span>
  11. </div>
  12. <div v-else-if="responseString" class="flex flex-col flex-1">
  13. <div
  14. class="sticky top-0 z-10 flex items-center justify-between pl-4 border-b bg-primary border-dividerLight"
  15. >
  16. <label class="font-semibold text-secondaryLight">
  17. {{ t("response.title") }}
  18. </label>
  19. <div class="flex">
  20. <ButtonSecondary
  21. v-tippy="{ theme: 'tooltip' }"
  22. :title="t('state.linewrap')"
  23. :class="{ '!text-accent': linewrapEnabled }"
  24. svg="wrap-text"
  25. @click.native.prevent="linewrapEnabled = !linewrapEnabled"
  26. />
  27. <ButtonSecondary
  28. ref="downloadResponse"
  29. v-tippy="{ theme: 'tooltip' }"
  30. :title="t('action.download_file')"
  31. :svg="downloadResponseIcon"
  32. @click.native="downloadResponse"
  33. />
  34. <ButtonSecondary
  35. ref="copyResponseButton"
  36. v-tippy="{ theme: 'tooltip' }"
  37. :title="t('action.copy')"
  38. :svg="copyResponseIcon"
  39. @click.native="copyResponse"
  40. />
  41. </div>
  42. </div>
  43. <div ref="schemaEditor" class="flex flex-col flex-1"></div>
  44. </div>
  45. <div
  46. v-else
  47. class="flex flex-col items-center justify-center p-4 text-secondaryLight"
  48. >
  49. <div class="flex pb-4 my-4 space-x-2">
  50. <div class="flex flex-col items-end text-right space-y-4">
  51. <span class="flex items-center flex-1">
  52. {{ t("shortcut.general.command_menu") }}
  53. </span>
  54. <span class="flex items-center flex-1">
  55. {{ t("shortcut.general.help_menu") }}
  56. </span>
  57. </div>
  58. <div class="flex flex-col space-y-4">
  59. <div class="flex">
  60. <span class="shortcut-key">/</span>
  61. </div>
  62. <div class="flex">
  63. <span class="shortcut-key">?</span>
  64. </div>
  65. </div>
  66. </div>
  67. <ButtonSecondary
  68. :label="`${t('app.documentation')}`"
  69. to="https://docs.hoppscotch.io/features/response"
  70. svg="external-link"
  71. blank
  72. outline
  73. reverse
  74. />
  75. </div>
  76. </div>
  77. </template>
  78. <script setup lang="ts">
  79. import { reactive, ref } from "@nuxtjs/composition-api"
  80. import { useCodemirror } from "~/helpers/editor/codemirror"
  81. import { copyToClipboard } from "~/helpers/utils/clipboard"
  82. import {
  83. useReadonlyStream,
  84. useI18n,
  85. useToast,
  86. } from "~/helpers/utils/composables"
  87. import { gqlResponse$ } from "~/newstore/GQLSession"
  88. const t = useI18n()
  89. const toast = useToast()
  90. const responseString = useReadonlyStream(gqlResponse$, "")
  91. const schemaEditor = ref<any | null>(null)
  92. const linewrapEnabled = ref(true)
  93. useCodemirror(
  94. schemaEditor,
  95. responseString,
  96. reactive({
  97. extendedEditorConfig: {
  98. mode: "application/ld+json",
  99. readOnly: true,
  100. lineWrapping: linewrapEnabled,
  101. },
  102. linter: null,
  103. completer: null,
  104. environmentHighlights: false,
  105. })
  106. )
  107. const downloadResponseIcon = ref("download")
  108. const copyResponseIcon = ref("copy")
  109. const copyResponse = () => {
  110. copyToClipboard(responseString.value!)
  111. copyResponseIcon.value = "check"
  112. toast.success(`${t("state.copied_to_clipboard")}`)
  113. setTimeout(() => (copyResponseIcon.value = "copy"), 1000)
  114. }
  115. const downloadResponse = () => {
  116. const dataToWrite = responseString.value
  117. const file = new Blob([dataToWrite!], { type: "application/json" })
  118. const a = document.createElement("a")
  119. const url = URL.createObjectURL(file)
  120. a.href = url
  121. a.download = `${url.split("/").pop()!.split("#")[0].split("?")[0]}`
  122. document.body.appendChild(a)
  123. a.click()
  124. downloadResponseIcon.value = "check"
  125. toast.success(`${t("state.download_started")}`)
  126. setTimeout(() => {
  127. document.body.removeChild(a)
  128. URL.revokeObjectURL(url)
  129. downloadResponseIcon.value = "download"
  130. }, 1000)
  131. }
  132. </script>