Parameters.vue 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. <template>
  2. <AppSection label="parameters">
  3. <div
  4. class="bg-primary border-b border-dividerLight flex flex-1 top-upperSecondaryStickyFold pl-4 z-10 sticky items-center justify-between"
  5. >
  6. <label class="font-semibold text-secondaryLight">
  7. {{ t("request.parameter_list") }}
  8. </label>
  9. <div class="flex">
  10. <ButtonSecondary
  11. v-tippy="{ theme: 'tooltip' }"
  12. to="https://docs.hoppscotch.io/features/parameters"
  13. blank
  14. :title="t('app.wiki')"
  15. svg="help-circle"
  16. />
  17. <ButtonSecondary
  18. v-tippy="{ theme: 'tooltip' }"
  19. :title="t('action.clear_all')"
  20. svg="trash-2"
  21. @click.native="clearContent()"
  22. />
  23. <ButtonSecondary
  24. v-tippy="{ theme: 'tooltip' }"
  25. :title="t('state.bulk_mode')"
  26. svg="edit"
  27. :class="{ '!text-accent': bulkMode }"
  28. @click.native="bulkMode = !bulkMode"
  29. />
  30. <ButtonSecondary
  31. v-tippy="{ theme: 'tooltip' }"
  32. :title="t('add.new')"
  33. svg="plus"
  34. :disabled="bulkMode"
  35. @click.native="addParam"
  36. />
  37. </div>
  38. </div>
  39. <div v-if="bulkMode" ref="bulkEditor"></div>
  40. <div v-else>
  41. <div
  42. v-for="(param, index) in params$"
  43. :key="`param-${index}`"
  44. class="divide-dividerLight divide-x border-b border-dividerLight flex"
  45. >
  46. <SmartEnvInput
  47. v-model="param.key"
  48. :placeholder="`${t('count.parameter', { count: index + 1 })}`"
  49. styles="
  50. bg-transparent
  51. flex
  52. flex-1
  53. py-1
  54. px-4
  55. "
  56. @change="
  57. updateParam(index, {
  58. key: $event,
  59. value: param.value,
  60. active: param.active,
  61. })
  62. "
  63. />
  64. <SmartEnvInput
  65. v-model="param.value"
  66. :placeholder="`${t('count.value', { count: index + 1 })}`"
  67. styles="
  68. bg-transparent
  69. flex
  70. flex-1
  71. py-1
  72. px-4
  73. "
  74. @change="
  75. updateParam(index, {
  76. key: param.key,
  77. value: $event,
  78. active: param.active,
  79. })
  80. "
  81. />
  82. <span>
  83. <ButtonSecondary
  84. v-tippy="{ theme: 'tooltip' }"
  85. :title="
  86. param.hasOwnProperty('active')
  87. ? param.active
  88. ? t('action.turn_off')
  89. : t('action.turn_on')
  90. : t('action.turn_off')
  91. "
  92. :svg="
  93. param.hasOwnProperty('active')
  94. ? param.active
  95. ? 'check-circle'
  96. : 'circle'
  97. : 'check-circle'
  98. "
  99. color="green"
  100. @click.native="
  101. updateParam(index, {
  102. key: param.key,
  103. value: param.value,
  104. active: param.hasOwnProperty('active') ? !param.active : false,
  105. })
  106. "
  107. />
  108. </span>
  109. <span>
  110. <ButtonSecondary
  111. v-tippy="{ theme: 'tooltip' }"
  112. :title="t('action.remove')"
  113. svg="trash"
  114. color="red"
  115. @click.native="deleteParam(index)"
  116. />
  117. </span>
  118. </div>
  119. <div
  120. v-if="params$.length === 0"
  121. class="flex flex-col text-secondaryLight p-4 items-center justify-center"
  122. >
  123. <img
  124. :src="`/images/states/${$colorMode.value}/add_files.svg`"
  125. loading="lazy"
  126. class="flex-col object-contain object-center h-16 my-4 w-16 inline-flex"
  127. :alt="`${t('empty.parameters')}`"
  128. />
  129. <span class="text-center pb-4">
  130. {{ t("empty.parameters") }}
  131. </span>
  132. <ButtonSecondary
  133. :label="`${t('add.new')}`"
  134. svg="plus"
  135. filled
  136. class="mb-4"
  137. @click.native="addParam"
  138. />
  139. </div>
  140. </div>
  141. </AppSection>
  142. </template>
  143. <script setup lang="ts">
  144. import { ref, watch, onBeforeUpdate } from "@nuxtjs/composition-api"
  145. import { HoppRESTParam } from "@hoppscotch/data"
  146. import { useCodemirror } from "~/helpers/editor/codemirror"
  147. import {
  148. useReadonlyStream,
  149. useI18n,
  150. useToast,
  151. } from "~/helpers/utils/composables"
  152. import {
  153. restParams$,
  154. addRESTParam,
  155. updateRESTParam,
  156. deleteRESTParam,
  157. deleteAllRESTParams,
  158. setRESTParams,
  159. } from "~/newstore/RESTSession"
  160. const t = useI18n()
  161. const toast = useToast()
  162. const bulkMode = ref(false)
  163. const bulkParams = ref("")
  164. watch(bulkParams, () => {
  165. try {
  166. const transformation = bulkParams.value.split("\n").map((item) => ({
  167. key: item.substring(0, item.indexOf(":")).trim().replace(/^\/\//, ""),
  168. value: item.substring(item.indexOf(":") + 1).trim(),
  169. active: !item.trim().startsWith("//"),
  170. }))
  171. setRESTParams(transformation as HoppRESTParam[])
  172. } catch (e) {
  173. toast.error(`${t("error.something_went_wrong")}`)
  174. console.error(e)
  175. }
  176. })
  177. const bulkEditor = ref<any | null>(null)
  178. useCodemirror(bulkEditor, bulkParams, {
  179. extendedEditorConfig: {
  180. mode: "text/x-yaml",
  181. placeholder: `${t("state.bulk_mode_placeholder")}`,
  182. },
  183. linter: null,
  184. completer: null,
  185. })
  186. const params$ = useReadonlyStream(restParams$, [])
  187. watch(
  188. params$,
  189. (newValue) => {
  190. if (!bulkMode.value)
  191. if (
  192. (newValue[newValue.length - 1]?.key !== "" ||
  193. newValue[newValue.length - 1]?.value !== "") &&
  194. newValue.length
  195. )
  196. addParam()
  197. },
  198. { deep: true }
  199. )
  200. onBeforeUpdate(() => editBulkParamsLine(-1, null))
  201. const editBulkParamsLine = (index: number, item?: HoppRESTParam | null) => {
  202. const params = params$.value
  203. bulkParams.value = params
  204. .reduce((all, param, pIndex) => {
  205. const current =
  206. index === pIndex && item != null
  207. ? `${item.active ? "" : "//"}${item.key}: ${item.value}`
  208. : `${param.active ? "" : "//"}${param.key}: ${param.value}`
  209. return [...all, current]
  210. }, [])
  211. .join("\n")
  212. }
  213. const clearBulkEditor = () => {
  214. bulkParams.value = ""
  215. }
  216. const addParam = () => {
  217. const empty = { key: "", value: "", active: true }
  218. const index = params$.value.length
  219. addRESTParam(empty)
  220. editBulkParamsLine(index, empty)
  221. }
  222. const updateParam = (index: number, item: HoppRESTParam) => {
  223. updateRESTParam(index, item)
  224. editBulkParamsLine(index, item)
  225. }
  226. const deleteParam = (index: number) => {
  227. const parametersBeforeDeletion = params$.value
  228. deleteRESTParam(index)
  229. editBulkParamsLine(index, null)
  230. const deletedItem = parametersBeforeDeletion[index]
  231. if (deletedItem.key || deletedItem.value) {
  232. toast.success(`${t("state.deleted")}`, {
  233. action: [
  234. {
  235. text: `${t("action.undo")}`,
  236. onClick: (_, toastObject) => {
  237. setRESTParams(parametersBeforeDeletion as HoppRESTParam[])
  238. editBulkParamsLine(index, deletedItem)
  239. toastObject.goAway(0)
  240. },
  241. },
  242. ],
  243. })
  244. }
  245. }
  246. const clearContent = () => {
  247. deleteAllRESTParams()
  248. clearBulkEditor()
  249. }
  250. </script>