Response.vue 4.0 KB

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