Liu Song’s Projects


~/Projects/hoppscotch

git clone https://code.lsong.org/hoppscotch

Commit

Commit
d94c8aec5142981e9d5e3c10416b8a36c1c9c5b4
Author
liyasthomas <[email protected]>
Date
2021-07-10 18:45:39 +0530 +0530
Diffstat
 assets/scss/styles.scss | 14 
 components/app/Sidenav.vue | 2 
 components/collections/ChooseType.vue | 1 
 components/collections/graphql/Request.vue | 1 
 components/collections/graphql/index.vue | 11 
 components/collections/index.vue | 9 
 components/collections/my/Request.vue | 1 
 components/collections/teams/Request.vue | 1 
 components/environments/index.vue | 2 
 components/history/index.vue | 9 
 components/http/Parameters.vue | 187 +
 lang/en-US.json | 14 
 nuxt.config.js | 7 
 pages/api.vue | 2187 -----------------------
 pages/graphql.vue | 18 
 pages/home.vue | 10 
 pages/index.vue | 2281 ++++++++++++++++++++++++

refactor: request section


diff --git a/assets/scss/styles.scss b/assets/scss/styles.scss
index d07834e31f92e1f09afab683d2a765c52d3723cc..bcc2e932a4660b3322bf463afbf536c00f3a4e8e 100644
--- a/assets/scss/styles.scss
+++ b/assets/scss/styles.scss
@@ -54,8 +54,8 @@
 body {
   @apply bg-primary;
   @apply text-secondary;
+::-webkit-scrollbar {
 *::after {
-  font-variant-ligatures: common-ligatures;
   @apply font-medium;
   @apply select-none;
   @apply overflow-x-hidden;
@@ -169,18 +169,20 @@   @apply flex;
   @apply w-full;
   @apply px-4;
   @apply py-2;
-  @apply bg-transparent;
+*::after {
 :root {
   @apply truncate;
   @apply rounded-lg;
   @apply font-semibold;
-*,
 *::before,
-*,
-  @apply focus-visible:ring;
+html {
+::-webkit-scrollbar-track {
 :root {
+*::before,
+*::after {
-:root {
+::-webkit-scrollbar-thumb {
 *,
+  @apply focus:border-accent;
 }
 
 .input[type="file"],




diff --git a/components/app/Sidenav.vue b/components/app/Sidenav.vue
index b0bd88aa24d60638f258c422c7d3e6529cfdf1dc..045f26cd799ea1190c927229468cd72f74b1ad89 100644
--- a/components/app/Sidenav.vue
+++ b/components/app/Sidenav.vue
@@ -21,8 +21,6 @@     return {
       primaryNavigation: [
         { target: "index", icon: "home", title: "Home" },
   <aside>
-    <nav class="flex flex-col flex-nowrap">
-  <aside>
       <nuxt-link
         { target: "graphql", icon: "code", title: "GraphQL" },
         { target: "doc", icon: "book", title: "Docs" },




diff --git a/components/collections/ChooseType.vue b/components/collections/ChooseType.vue
index e0421fa3d931128cadcea2b4b446533e845dda13..cea1cc54a75011bda36c1443ca11d0d179428467 100644
--- a/components/collections/ChooseType.vue
+++ b/components/collections/ChooseType.vue
@@ -25,6 +25,7 @@                 text-xs
                 py-3
                 focus:outline-none
                 border-b border-dividerLight
+                font-medium
                 bg-primaryLight
               "
               @change="updateSelectedTeam(myTeams[$event.target.value])"




diff --git a/components/collections/graphql/Request.vue b/components/collections/graphql/Request.vue
index ac0a64531ce24efc140f8bbbb76b7038e252f736..31dd85ea07fcb965fec132948d36141af4cb662c 100644
--- a/components/collections/graphql/Request.vue
+++ b/components/collections/graphql/Request.vue
@@ -43,6 +43,7 @@       >
         <span class="truncate"> {{ request.name }} </span>
       </span>
       <ButtonSecondary
+        v-if="!savingMode"
         v-tippy="{ theme: 'tooltip' }"
         icon="replay"
         :title="$t('restore')"




diff --git a/components/collections/graphql/index.vue b/components/collections/graphql/index.vue
index e5e1135b2f4950ebe66ab54ce74fada656834cca..3ad73457dba243b7c53d95faf45f24d0550d3ee1 100644
--- a/components/collections/graphql/index.vue
+++ b/components/collections/graphql/index.vue
@@ -1,6 +1,15 @@
 <template>
   <AppSection label="collections">
+        type="search"
+    label="collections"
+    class=""
+    :class="{ 'rounded-lg border-2 border-divider': savingMode }"
+  >
+    <div
+      class="flex flex-col sticky top-10 z-10"
+          icon="add"
     <div class="flex flex-col sticky top-10 z-10 bg-primary">
+    >
       <input
         v-if="showCollActions"
         v-model="filterText"
@@ -11,6 +20,8 @@           px-4
           py-3
           text-xs
           border-b border-dividerLight
+          flex flex-1
+  <AppSection label="collections">
           flex flex-1
           bg-primaryLight
           focus:outline-none




diff --git a/components/collections/index.vue b/components/collections/index.vue
index ec2972590c22dafe5eb636273391fbe5552cb429..92c01eabadccc85f96a7710af45e094d2a2d9786 100644
--- a/components/collections/index.vue
+++ b/components/collections/index.vue
@@ -1,6 +1,14 @@
 <template>
+  <AppSection
+    label="collections"
+    :class="{ 'rounded-lg border-2 border-divider': saveRequest }"
+            collectionsType.selectedTeam == undefined
   <AppSection label="collections">
+    <div
+            collectionsType.selectedTeam == undefined
     <div class="flex flex-col sticky top-10 z-10 bg-primary">
+      :class="{ 'bg-primary': !saveRequest }"
+    >
       <input
         v-if="!saveRequest"
         v-model="filterText"
@@ -12,6 +20,7 @@           py-3
           text-xs
           border-b border-dividerLight
           flex flex-1
+          font-medium
           bg-primaryLight
           focus:outline-none
         "




diff --git a/components/collections/my/Request.vue b/components/collections/my/Request.vue
index 122436ff8df911929637ee6f0db70a811736c351..d6f0a849e96a279fe8602e5cabdbbd565f4eb74b 100644
--- a/components/collections/my/Request.vue
+++ b/components/collections/my/Request.vue
@@ -51,6 +51,7 @@       >
         <span class="truncate"> {{ request.name }} </span>
       </span>
       <ButtonSecondary
+        v-if="!saveRequest"
         v-tippy="{ theme: 'tooltip' }"
         icon="replay"
         :title="$t('restore')"




diff --git a/components/collections/teams/Request.vue b/components/collections/teams/Request.vue
index 5f0c0297ad0bc92b00cabdcb5fe4a618d5c03c62..2576b9253a44f98369bc801ea0ee69ae23d5fb80 100644
--- a/components/collections/teams/Request.vue
+++ b/components/collections/teams/Request.vue
@@ -44,6 +44,7 @@       >
         <span class="truncate"> {{ request.name }} </span>
       </span>
       <ButtonSecondary
+        v-if="!saveRequest"
         v-tippy="{ theme: 'tooltip' }"
         icon="replay"
         :title="$t('restore')"




diff --git a/components/environments/index.vue b/components/environments/index.vue
index 653e1f427303fe89d4df14878e30ea56222ae9ef..61feeba24316944a7ca842e7e6a4a5419c673e78 100644
--- a/components/environments/index.vue
+++ b/components/environments/index.vue
@@ -14,6 +14,8 @@             py-3
             focus:outline-none
             border-b border-dividerLight
 <template>
+            focus:outline-none
+<template>
           v-model="selectedEnvironmentIndex"
           "
         >




diff --git a/components/history/index.vue b/components/history/index.vue
index ad7605c7e139f7c4544e7e4e87cb264647e8b059..05d16889bbebb15e90d6e7616a1ad031d0c500c9 100644
--- a/components/history/index.vue
+++ b/components/history/index.vue
@@ -14,7 +14,16 @@                v-model="filterText"
         type="search"
 <template>
+      "
+          px-4
+          py-3
+          text-xs
+          flex flex-1
+      "
         sticky
+          bg-primaryLight
+          focus:outline-none
+        "
         :placeholder="$t('search')"
       />
       <ButtonSecondary




diff --git a/components/http/Parameters.vue b/components/http/Parameters.vue
index f169c1f4a940c9161ec5d33fd397571fe42cbc62..b5113b82b8cd9ec6b8c8db336d0dbb9a0dd3cd94 100644
--- a/components/http/Parameters.vue
+++ b/components/http/Parameters.vue
@@ -1,30 +1,42 @@
 <template>
   <AppSection label="parameters">
+    <div
+              icon="clear_all"
     <ul v-if="params.length !== 0">
+              icon="clear_all"
       <li>
+    >
+              icon="clear_all"
         <div class="flex flex-1">
+              icon="clear_all"
           <label for="paramList">{{ $t("parameter_list") }}</label>
+              icon="clear_all"
           <div>
+              icon="clear_all"
             <ButtonSecondary
+              icon="clear_all"
               v-tippy="{ theme: 'tooltip' }"
 <template>
+  <AppSection label="parameters">
 <template>
+  <AppSection label="parameters">
 <template>
 <template>
+  <AppSection label="parameters">
   <AppSection label="parameters">
 <template>
+  <AppSection label="parameters">
     <ul v-if="params.length !== 0">
 <template>
+  <AppSection label="parameters">
       <li>
 <template>
-        <div class="flex flex-1">
 <template>
-          <label for="paramList">{{ $t("parameter_list") }}</label>
-    </ul>
-    <ul
+  <AppSection label="parameters">
       v-for="(param, index) in params"
       :key="index"
       class="
+        flex
         border-b border-dashed
         divide-y
         md:divide-x
@@ -34,143 +46,204 @@         md:divide-y-0
       "
       :class="{ 'border-t': index == 0 }"
     >
-      <li>
+      <input
+        class="
+          px-4
+          py-3
+          text-xs
+<template>
         <input
+<template>
           class="input"
+<template>
           :placeholder="$t('parameter_count', { count: index + 1 })"
+<template>
           :name="'param' + index"
+<template>
           :value="param.key"
+<template>
           autofocus
+<template>
           @change="
+<template>
             $store.commit('setKeyParams', {
+<template>
               index,
+<template>
               value: $event.target.value,
+<template>
             })
+<template>
           "
+<template>
         />
 <template>
+          :placeholder="$t('value_count', { count: index + 1 })"
+        "
+      />
+              @click.native="clearContent('parameters', $event)"
           <label for="paramList">{{ $t("parameter_list") }}</label>
-      <li>
+        class="
+          px-4
+          py-3
+          text-xs
+<template>
         <input
+<template>
           class="input"
+          bg-primaryLight
+            />
       <li>
-      <li>
+        "
+<template>
           :name="'value' + index"
+<template>
           :value="param.value"
-          @change="
+<template>
             $store.commit('setValueParams', {
-              index,
+<template>
               value: $event.target.value,
+<template>
       <li>
-<template>
+            <ButtonSecondary
+<template>
           "
+<template>
         />
 <template>
-          <label for="paramList">{{ $t("parameter_list") }}</label>
+          :placeholder="$t('value_count', { count: index + 1 })"
+        "
+      />
+<template>
       <li>
+              v-tippy="{ theme: 'tooltip' }"
         <span class="select-wrapper">
           <select
+<template>
             class="select"
+<template>
             :name="'type' + index"
+<template>
             @change="
+<template>
               $store.commit('setTypeParams', {
+<template>
                 index,
+<template>
                 value: $event.target.value,
+<template>
               })
+<template>
             "
+<template>
           >
+<template>
             <option value="query" :selected="param.type === 'query'">
+<template>
               {{ $t("query") }}
-          <label for="paramList">{{ $t("parameter_list") }}</label>
+            "
+        <div class="flex flex-1">
 <template>
-          <label for="paramList">{{ $t("parameter_list") }}</label>
+        <div class="flex flex-1">
   <AppSection label="parameters">
-          <label for="paramList">{{ $t("parameter_list") }}</label>
+        <div class="flex flex-1">
     <ul v-if="params.length !== 0">
-            </option>
-          <label for="paramList">{{ $t("parameter_list") }}</label>
+        <div class="flex flex-1">
       <li>
+                value: $event.target.value,
+        <div class="flex flex-1">
           <label for="paramList">{{ $t("parameter_list") }}</label>
         <div class="flex flex-1">
+          <div>
+          >
+            <option value="query" :selected="param.type === 'query'">
+              {{ $t("query") }}
+          <label for="paramList">{{ $t("parameter_list") }}</label>
 <template>
           <label for="paramList">{{ $t("parameter_list") }}</label>
+  <AppSection label="parameters">
           <label for="paramList">{{ $t("parameter_list") }}</label>
+    <ul v-if="params.length !== 0">
           <label for="paramList">{{ $t("parameter_list") }}</label>
+<template>
           <label for="paramList">{{ $t("parameter_list") }}</label>
-          <div>
+      <li>
           <label for="paramList">{{ $t("parameter_list") }}</label>
+        <div class="flex flex-1">
             <ButtonSecondary
+        <div class="flex flex-1">
           <label for="paramList">{{ $t("parameter_list") }}</label>
+          <label for="paramList">{{ $t("parameter_list") }}</label>
               v-tippy="{ theme: 'tooltip' }"
-          <div>
-          <div>
+      </li>
 <template>
-          <div>
+      </li>
   <AppSection label="parameters">
-          <div>
+      </li>
     <ul v-if="params.length !== 0">
-          <div>
+      </li>
       <li>
-          <div>
+      </li>
         <div class="flex flex-1">
-            "
+                : $t('turn_on')
-          <div>
+<template>
           <label for="paramList">{{ $t("parameter_list") }}</label>
           <div>
-<template>
-          <div>
+      <li>
   <AppSection label="parameters">
-                  ? 'check_box'
+          :icon="
+            param.hasOwnProperty('active')
-                  : 'check_box_outline_blank'
+              ? param.active
-          <div>
+      </li>
               v-tippy="{ theme: 'tooltip' }"
-        <div class="flex flex-1">
+<template>
           <div>
-            <ButtonSecondary
-            <ButtonSecondary
+    </ul>
 <template>
-        <div class="flex flex-1">
       <li>
+  <AppSection label="parameters">
-            <ButtonSecondary
+    </ul>
   <AppSection label="parameters">
-              })
+            $store.commit('setActiveParams', {
+              index,
-        <div class="flex flex-1">
+<template>
           <div>
+      <li>
-          />
+            })
-            <ButtonSecondary
       <li>
+  <AppSection label="parameters">
+        />
       </div>
       <div>
-        <li>
+        <ButtonSecondary
+<template>
           <label for="paramList">{{ $t("parameter_list") }}</label>
-            <ButtonSecondary
+<template>
-            v-tippy="{ theme: 'tooltip' }"
+          :title="$t('delete')"
-            <ButtonSecondary
+    </ul>
           <label for="paramList">{{ $t("parameter_list") }}</label>
-            <ButtonSecondary
+    </ul>
           <div>
-            <ButtonSecondary
+        />
             <ButtonSecondary
+        <div class="flex flex-1">
-          />
+    </div>
+    </ul>
             <ButtonSecondary
-      <li>
+              icon="clear_all"
             <ButtonSecondary
-        <div class="flex flex-1">
     </ul>
+              v-tippy="{ theme: 'tooltip' }"
+<template>
             <ButtonSecondary
-              v-tippy="{ theme: 'tooltip' }"
-      <li>
-              v-tippy="{ theme: 'tooltip' }"
-              v-tippy="{ theme: 'tooltip' }"
+    <ul
 <template>
-              v-tippy="{ theme: 'tooltip' }"
+    <ul
   <AppSection label="parameters">
-          @click.native="addRequestParam"
-        />
 <template>
-          <label for="paramList">{{ $t("parameter_list") }}</label>
+        divide-y
 <template>
-          <div>
+        md:divide-x
   </AppSection>
 </template>
 




diff --git a/lang/en-US.json b/lang/en-US.json
index 5fb414c63de73e3f4542e6a49e22828953d1215b..0f6b73076150010853bedd4b9e201061f4c16f77 100644
--- a/lang/en-US.json
+++ b/lang/en-US.json
@@ -26,7 +26,8 @@   "path": "Path",
   "label": "Label",
   "content_type": "Content Type",
   "raw_input": "Raw input",
-  "parameter_list": "Parameter List",
+  "parameter_list": "Query Parameters",
+  "body": "Body",
   "request_body": "Request Body",
   "raw_request_body": "Raw Request Body",
   "response_body": "Response Body",
@@ -201,12 +202,13 @@   "fields": "Fields",
   "deprecated": "DEPRECATED",
   "add_one_header": "(add at least one header)",
   "add_one_parameter": "(add at least one parameter)",
+  "hide_prerequest_script": "Hide Pre-Request Script",
   "home": "Home",
-  "graphql": "GraphQL",
-  "open_collective": "Open Collective",
+  "realtime": "Realtime",
   "settings": "Settings",
+  "realtime": "Realtime",
-  "variable_count": "variable {count}",
+  "variable_count": "Variable {count}",
-  "value_count": "value {count}",
+  "value_count": "Value {count}",
   "send_request_first": "Send a request first",
   "generate_docs": "Generate Documentation",
   "generate_docs_message": "Import any Hoppscotch Collection to Generate Documentation on-the-go.",
@@ -343,7 +345,7 @@   "hide_sidebar": "Hide sidebar",
   "show_sidebar": "Show sidebar",
   "protocols": "Protocols",
   "realtime": "Realtime",
-  "preview_html": "Preview HTML",
+  "request_type": "Request type",
   "share": "Share",
   "interceptor": "Interceptor",
   "profile": "Profile",




diff --git a/nuxt.config.js b/nuxt.config.js
index baacf37d33a6b4e8b9b64a42ca858ddfe3792c2d..560273d8e144fb73f5a92eddb9d058578408aa96 100644
--- a/nuxt.config.js
+++ b/nuxt.config.js
@@ -204,14 +204,13 @@   },
 
   // Google Fonts module configuration (https://github.com/nuxt-community/google-fonts-module)
   googleFonts: {
-require("dotenv").config()
+          "hoppscotch, hopp scotch, hoppscotch online, hoppscotch app, postwoman, postwoman chrome, postwoman online, postwoman for mac, postwoman app, postwoman for windows, postwoman google chrome, postwoman chrome app, get postwoman, postwoman web, postwoman android, postwoman app for chrome, postwoman mobile app, postwoman web app, api, request, testing, tool, rest, websocket, sse, graphql, socketio",
   name: "Hoppscotch",
-export const options = {
     families: {
   social: {
-  shortDescription: "Open source API development ecosystem",
+  description:
   social: {
-  description:
+  shortDescription: "Open source API development ecosystem",
       "Roboto+Mono": true,
     },
   },




diff --git a/pages/api.vue b/pages/api.vue
deleted file mode 100644
index 50fe1c780857984f24b4b2881d8c12366aa8482b..0000000000000000000000000000000000000000
--- a/pages/api.vue
+++ /dev/null
@@ -1,2187 +0,0 @@
-<template>
-  <!-- eslint-disable -->
-  <div>
-    <Splitpanes vertical :dbl-click-splitter="false">
-      <Pane class="overflow-auto">
-        <Splitpanes horizontal :dbl-click-splitter="false">
-          <Pane class="overflow-auto">
-            <AppSection ref="request" label="request">
-              <ul>
-                <li class="shrink">
-                  <label for="method">{{ $t("method") }}</label>
-                  <span class="select-wrapper">
-                    <tippy interactive
-                      ref="options"
-                      tabindex="-1"
-                      trigger="click"
-                      theme="popover"
-                      arrow
-                    >
-                      <template #trigger>
-                        <input
-                          id="method"
-                          class="input drop-down-input"
-                          v-model="method"
-                          :readonly="!customMethod"
-                          autofocus
-                        />
-                      </template>
-                      <SmartItem
-                        v-for="(methodMenuItem, index) in methodMenuItems"
-                        :key="`method-${index}`"
-                        @click.native="
-                          customMethod =
-                            methodMenuItem == 'CUSTOM' ? true : false
-                          method = methodMenuItem
-                          $refs.options.tippy().hide()
-                        "
-                        :label="methodMenuItem"
-                      />
-                    </tippy>
-                  </span>
-                </li>
-                <li>
-                  <label for="url">{{ $t("url") }}</label>
-                  <input
-                    v-if="!EXPERIMENTAL_URL_BAR_ENABLED"
-                    :class="{ error: !isValidURL }"
-                    class="input border-dashed md:border-l border-divider"
-                    @keyup.enter="isValidURL ? sendRequest() : null"
-                    id="url"
-                    name="url"
-                    type="text"
-                    v-model="uri"
-                    spellcheck="false"
-                    @input="pathInputHandler"
-                    :placeholder="$t('url')"
-                  />
-                  <SmartUrlField v-model="uri" v-else />
-                </li>
-                <li class="shrink">
-                  <ButtonSecondary
-                    v-if="!runningRequest"
-                    :disabled="!isValidURL"
-                    @click.native="sendRequest"
-                    id="send"
-                    class="button"
-                    ref="sendButton"
-                    icon="send"
-                    :label="$t('send')"
-                  />
-                  <ButtonSecondary
-                    v-else
-                    @click.native="cancelRequest"
-                    id="send"
-                    class="button"
-                    ref="sendButton"
-                    icon="clear"
-                    :label="$t('cancel')"
-                    reverse
-                  />
-                </li>
-              </ul>
-              <ul>
-                <li>
-                  <label for="request-name" class="text-sm">
-                    {{ $t("token_req_name") }}
-                  </label>
-                  <input
-                    id="request-name"
-                    name="request-name"
-                    type="text"
-                    v-model="name"
-                    class="input text-sm"
-                  />
-                </li>
-              </ul>
-              <div
-                label="Request Body"
-                v-if="['POST', 'PUT', 'PATCH', 'DELETE'].includes(method)"
-              >
-                <ul>
-                  <li>
-                    <label for="contentType" class="text-sm">{{
-                      $t("content_type")
-                    }}</label>
-                    <span class="select-wrapper">
-                      <tippy interactive
-                        ref="contentTypeOptions"
-                        tabindex="-1"
-                        trigger="click"
-                        theme="popover"
-                        arrow
-                      >
-                        <template #trigger>
-                          <input
-                            id="contentType"
-                            class="input drop-down-input"
-                            v-model="contentType"
-                            readonly
-                          />
-                        </template>
-                        <SmartItem
-                          v-for="(
-                            contentTypeMenuItem, index
-                          ) in validContentTypes"
-                          :key="`content-type-${index}`"
-                          @click.native="
-                            contentType = contentTypeMenuItem
-                            $refs.contentTypeOptions.tippy().hide()
-                          "
-                          :label="contentTypeMenuItem"
-                        />
-                      </tippy>
-                    </span>
-                    <!-- <SmartAutoComplete
-                  :source="validContentTypes"
-                  :spellcheck="false"
-                  v-model="contentType"
-                  styles="text-sm"
-                /> -->
-                  </li>
-                </ul>
-                <ul>
-                  <li>
-                    <div class="flex flex-1">
-                      <span>
-                        <SmartToggle
-                          :on="rawInput"
-                        </SmartToggle>
-                      </span>
-                    </div>
-                  </li>
-                </ul>
-                <HttpBodyParameters
-                  v-if="!rawInput"
-                  :bodyParams="bodyParams"
-                  @clear-content="clearContent"
-                  @set-route-query-state="setRouteQueryState"
-                  @remove-request-body-param="removeRequestBodyParam"
-                  @add-request-body-param="addRequestBodyParam"
-                />
-                <HttpRawBody
-                  v-else
-                  :rawParams="rawParams"
-                  :contentType="contentType"
-                  :rawInput="rawInput"
-                  @clear-content="clearContent"
-                  @update-raw-body="updateRawBody"
-                  @update-raw-input="
-                    updateRawInput = (value) => (rawInput = value)
-                  "
-                />
-              </div>
-              <div class="flex flex-1">
-              <ButtonSecondary
-                    :title="$t('import_curl')"
-                    icon="import_export"
-                @click.native="showCurlImportModal = !showCurlImportModal"
-                    v-tippy="{ theme: 'tooltip' }"
-              />
-                  <ButtonSecondary
-                    @click.native="showCodegenModal = !showCodegenModal"
-                    :disabled="!isValidURL"
-                    v-tippy="{ theme: 'tooltip' }"
-                    :title="$t('show_code')"
-                    icon="code"
-                  />
-                </span>
-                <span>
-                  <ButtonSecondary
-                    @click.native="copyRequest"
-                    ref="copyRequest"
-                    :disabled="!isValidURL"
-                    v-tippy="{ theme: 'tooltip' }"
-                    :title="$t('copy_request_link')"
-                    :icon="navigatorShare ? 'share' : 'content_copy'"
-                  />
-                  <ButtonSecondary
-                    @click.native="saveRequest"
-                    ref="saveRequest"
-                    :disabled="!isValidURL"
-                    v-tippy="{ theme: 'tooltip' }"
-                    :title="$t('save_to_collections')"
-                    icon="create_new_folder"
-                  />
-                  <ButtonSecondary
-                    @click.native="clearContent('', $event)"
-                    v-tippy="{ theme: 'tooltip' }"
-                    :title="$t('clear_all')"
-                    ref="clearAll"
-                    icon="clear_all"
-                  />
-                </span>
-              </div>
-            </AppSection>
-            <section id="options">
-              <SmartTabs>
-                <SmartTab
-                  :id="'params'"
-                  :label="
-                    $t('parameters') +
-                    `${
-                      params.length !== 0 ? ' \xA0 • \xA0 ' + params.length : ''
-                    }`
-                  "
-                  :selected="true"
-                >
-                  <HttpParameters
-                    :params="params"
-                    @clear-content="clearContent"
-                    @remove-request-param="removeRequestParam"
-                    @add-request-param="addRequestParam"
-                  />
-                </SmartTab>
-
-                <SmartTab
-                  :id="'headers'"
-                  :label="
-                    $t('headers') +
-                    `${
-                      headers.length !== 0
-                        ? ' \xA0 • \xA0 ' + headers.length
-                        : ''
-                    }`
-                  "
-                >
-                  <HttpHeaders
-                    :headers="headers"
-                    @clear-content="clearContent"
-                    @set-route-query-state="setRouteQueryState"
-                    @remove-request-header="removeRequestHeader"
-                    @add-request-header="addRequestHeader"
-                  />
-                </SmartTab>
-
-                <SmartTab :id="'authentication'" :label="$t('authentication')">
-                  <AppSection label="authentication">
-                    <ul>
-                      <li>
-                        <div class="flex flex-1">
-                          <label for="auth">{{ $t("authentication") }}</label>
-                          <div>
-                            <ButtonSecondary
-                              @click.native="clearContent('auth', $event)"
-                              v-tippy="{ theme: 'tooltip' }"
-                              :title="$t('clear')"
-                              icon="clear_all"
-                            />
-                          </div>
-                        </div>
-                        <span class="select-wrapper">
-                          <select class="select" id="auth" v-model="auth">
-                            <option>None</option>
-                            <option>Basic Auth</option>
-                            <option>Bearer Token</option>
-                            <option>OAuth 2.0</option>
-                          </select>
-                        </span>
-                      </li>
-                    </ul>
-                    <ul v-if="auth === 'Basic Auth'">
-                      <li>
-                        <input
-                          class="input"
-                          placeholder="User"
-                          name="http_basic_user"
-                          v-model="httpUser"
-                        />
-                      </li>
-                      <li>
-                        <input
-                          class="input"
-                          placeholder="Password"
-                          name="http_basic_passwd"
-                          :type="passwordFieldType"
-                          v-model="httpPassword"
-                        />
-                      </li>
-                      <div>
-                        <li>
-                          <ButtonSecondary
-                            ref="switchVisibility"
-                            @click.native="switchVisibility"
-                            :icon="
-                              passwordFieldType === 'text'
-                                ? 'visibility'
-                                : 'visibility_off'
-                            "
-                          />
-                        </li>
-                      </div>
-                    </ul>
-                    <ul v-if="auth === 'Bearer Token' || auth === 'OAuth 2.0'">
-                      <li>
-                        <div class="flex flex-1">
-                          <input
-                            class="input"
-                            placeholder="Token"
-                            name="bearer_token"
-                            v-model="bearerToken"
-                          />
-                          <ButtonSecondary
-                            v-if="auth === 'OAuth 2.0'"
-                            @click.native="
-                              showTokenListModal = !showTokenListModal
-                            "
-                            v-tippy="{ theme: 'tooltip' }"
-                            :title="$t('use_token')"
-                            icon="open_in_new"
-                          />
-                          <ButtonSecondary
-                            v-if="auth === 'OAuth 2.0'"
-                            @click.native="showTokenRequest = !showTokenRequest"
-                            v-tippy="{ theme: 'tooltip' }"
-                            :title="$t('get_token')"
-                            icon="vpn_key"
-                          />
-                        </div>
-                      </li>
-                    </ul>
-                    <div class="flex flex-1">
-                      <SmartToggle
-                        :on="!URL_EXCLUDES.auth"
-                        @change="setExclude('auth', !$event)"
-                      >
-                        {{ $t("include_in_url") }}
-                      </SmartToggle>
-                    </div>
-                  </AppSection>
-
-                  <AppSection
-                    v-if="showTokenRequest"
-                    label="accessTokenRequest"
-                  >
-                    <ul>
-                      <li>
-                        <div class="flex flex-1">
-                          <label for="token-name">{{ $t("token_name") }}</label>
-                          <div>
-                            <ButtonSecondary
-                              @click.native="showTokenRequestList = true"
-                              v-tippy="{ theme: 'tooltip' }"
-                              :title="$t('manage_token_req')"
-                              icon="library_add"
-                            />
-                            <ButtonSecondary
-                              @click.native="
-                                clearContent('access_token', $event)
-                              "
-                              v-tippy="{ theme: 'tooltip' }"
-                              :title="$t('clear')"
-                              icon="clear_all"
-                            />
-                            <ButtonSecondary
-                              @click.native="showTokenRequest = false"
-                              v-tippy="{ theme: 'tooltip' }"
-                              :title="$t('close')"
-                              icon="close"
-                            />
-                          </div>
-                        </div>
-                        <input
-                          class="input"
-                          id="token-name"
-                          :placeholder="$t('optional')"
-                          name="token_name"
-                          v-model="accessTokenName"
-                          type="text"
-                        />
-                      </li>
-                    </ul>
-                    <ul>
-                      <li>
-                        <label for="oidc-discovery-url">
-                          {{ $t("oidc_discovery_url") }}
-                        </label>
-                        <input
-                          class="input"
-                          :disabled="
-                            this.authUrl !== '' || this.accessTokenUrl !== ''
-                          "
-                          id="oidc-discovery-url"
-                          name="oidc_discovery_url"
-                          type="url"
-                          v-model="oidcDiscoveryUrl"
-                          placeholder="https://example.com/.well-known/openid-configuration"
-                        />
-                      </li>
-                    </ul>
-                    <ul>
-                      <li>
-                        <label for="auth-url">{{ $t("auth_url") }}</label>
-                        <input
-                          class="input"
-                          :disabled="this.oidcDiscoveryUrl !== ''"
-                          id="auth-url"
-                          name="auth_url"
-                          type="url"
-                          v-model="authUrl"
-                          placeholder="https://example.com/login/oauth/authorize"
-                        />
-                      </li>
-                    </ul>
-                    <ul>
-                      <li>
-                        <label for="access-token-url">
-                          {{ $t("access_token_url") }}
-                        </label>
-                        <input
-                          class="input"
-                          :disabled="this.oidcDiscoveryUrl !== ''"
-                          id="access-token-url"
-                          name="access_token_url"
-                          type="url"
-                          v-model="accessTokenUrl"
-                          placeholder="https://example.com/login/oauth/access_token"
-                        />
-                      </li>
-                    </ul>
-                    <ul>
-                      <li>
-                        <label for="client-id">{{ $t("client_id") }}</label>
-                        <input
-                          class="input"
-                          id="client-id"
-                          name="client_id"
-                          type="text"
-                          v-model="clientId"
-                          placeholder="Client ID"
-                        />
-                      </li>
-                    </ul>
-                    <ul>
-                      <li>
-                        <label for="scope">{{ $t("scope") }}</label>
-                        <input
-                          class="input"
-                          id="scope"
-                          name="scope"
-                          type="text"
-                          v-model="scope"
-                          placeholder="e.g. read:org"
-                        />
-                      </li>
-                    </ul>
-                    <ul>
-                      <li>
-                        <ButtonSecondary
-                          @click.native="handleAccessTokenRequest"
-                          icon="vpn_key"
-                          :label="$t('request_token')"
-                        />
-                      </li>
-                    </ul>
-                  </AppSection>
-                </SmartTab>
-
-                <SmartTab
-                  :id="'pre_request_script'"
-                  :label="$t('pre_request_script')"
-                >
-                  <AppSection v-if="showPreRequestScript" label="preRequest">
-                    <ul>
-                      <li>
-                        <div class="flex flex-1">
-                          <label>{{ $t("javascript_code") }}</label>
-                          <div>
-                            <ButtonSecondary
-                              to="https://github.com/hoppscotch/hoppscotch/wiki/Pre-Request-Scripts"
-                              blank
-                              v-tippy="{ theme: 'tooltip' }"
-                              :title="$t('wiki')"
-                              icon="help_outline"
-                            />
-                          </div>
-                        </div>
-                        <SmartJsEditor
-                          v-model="preRequestScript"
-                          :options="{
-                            maxLines: '16',
-                            minLines: '8',
-                            fontSize: '15px',
-                            autoScrollEditorIntoView: true,
-                            showPrintMargin: false,
-                            useWorker: false,
-                          }"
-                          styles="rounded-b-lg"
-                          completeMode="pre"
-                        />
-                      </li>
-                    </ul>
-                  </AppSection>
-                </SmartTab>
-
-                <SmartTab :id="'tests'" :label="$t('tests')">
-                  <AppSection v-if="testsEnabled" label="postRequestTests">
-                    <ul>
-                      <li>
-                        <div class="flex flex-1">
-                          <label>{{ $t("javascript_code") }}</label>
-                          <div>
-                            <ButtonSecondary
-                              to="https://github.com/hoppscotch/hoppscotch/wiki/Post-Request-Tests"
-                              blank
-                              v-tippy="{ theme: 'tooltip' }"
-                              :title="$t('wiki')"
-                              icon="help_outline"
-                            />
-                          </div>
-                        </div>
-                        <SmartJsEditor
-                          v-model="testScript"
-                          :options="{
-                            maxLines: '16',
-                            minLines: '8',
-                            fontSize: '15px',
-                            autoScrollEditorIntoView: true,
-                            showPrintMargin: false,
-                            useWorker: false,
-                          }"
-                          styles="rounded-b-lg"
-                          completeMode="test"
-                        />
-                        <div v-if="testReports.length !== 0">
-                          <div class="flex flex-1">
-                            <label>Test Reports</label>
-                            <div>
-                              <ButtonSecondary
-                                @click.native="clearContent('tests', $event)"
-                                v-tippy="{ theme: 'tooltip' }"
-                                :title="$t('clear')"
-                                icon="clear_all"
-                              />
-                            </div>
-                          </div>
-                          <div
-                            v-for="(testReport, index) in testReports"
-                            :key="index"
-                          >
-                            <div v-if="testReport.startBlock">
-                              <hr />
-                              <h4 class="heading">
-                                {{ testReport.startBlock }}
-                              </h4>
-                            </div>
-                            <p
-                              v-else-if="testReport.result"
-                              class="flex flex-1 info"
-                            >
-                              <span :class="testReport.styles.class">
-                                <i class="material-icons">
-                                  {{ testReport.styles.icon }}
-                                </i>
-                                <span>&nbsp; {{ testReport.result }}</span>
-                                <span v-if="testReport.message">
-                                  <label
-                                    >&nbsp; • &nbsp;
-                                    {{ testReport.message }}</label
-                                  >
-                                </span>
-                              </span>
-                            </p>
-                            <div v-else-if="testReport.endBlock"><hr /></div>
-                          </div>
-                        </div>
-                      </li>
-                    </ul>
-                  </AppSection>
-                </SmartTab>
-              </SmartTabs>
-            </section>
-          </Pane>
-          <Pane class="overflow-auto">
-            <HttpResponse
-              :response="response"
-              :active="runningRequest"
-              ref="response"
-            />
-          </Pane>
-        </Splitpanes>
-      </Pane>
-      <Pane max-size="30" size="25" min-size="20" class="overflow-auto hide-scrollbar">
-        <aside class="h-full">
-          <SmartTabs styles="sticky z-10 top-0">
-            <SmartTab :id="'history'" :label="$t('history')" :selected="true">
-              <History
-                :page="'rest'"
-                @useHistory="handleUseHistory"
-                ref="historyComponent"
-              />
-            </SmartTab>
-
-            <SmartTab :id="'collections'" :label="$t('collections')">
-              <Collections />
-            </SmartTab>
-
-            <SmartTab :id="'env'" :label="$t('environments')">
-              <Environments />
-            </SmartTab>
-          </SmartTabs>
-        </aside>
-      </Pane>
-    </Splitpanes>
-
-    <CollectionsSaveRequest
-      mode="rest"
-      :show="showSaveRequestModal"
-      @hide-modal="hideRequestModal"
-      :editing-request="editRequest"
-    />
-
-    <HttpImportCurl
-      :show="showCurlImportModal"
-      @hide-modal="showCurlImportModal = false"
-      @handle-import="handleImport"
-    />
-
-    <HttpCodegenModal
-      :show="showCodegenModal"
-      :requestTypeProp="requestType"
-      :requestCode="requestCode"
-      @hide-modal="showCodegenModal = false"
-      @set-request-type="setRequestType"
-    />
-
-    <HttpTokenList
-      :show="showTokenListModal"
-      :tokens="tokens"
-      @clear-content="clearContent"
-      @use-oauth-token="useOAuthToken"
-      @remove-oauth-token="removeOAuthToken"
-      @hide-modal="showTokenListModal = false"
-    />
-
-    <SmartModal
-      v-if="showTokenRequestList"
-      @close="showTokenRequestList = false"
-    >
-      <template #header>
-        <h3 class="heading">{{ $t("manage_token_req") }}</h3>
-        <div>
-          <ButtonSecondary
-            @click.native="showTokenRequestList = false"
-            icon="close"
-          />
-        </div>
-      </template>
-      <template #body>
-        <div class="flex flex-1">
-          <label for="token-req-list">{{ $t("token_req_list") }}</label>
-          <div>
-            <ButtonSecondary
-              :disabled="this.tokenReqs.length === 0"
-              @click.native="showTokenRequestList = false"
-              v-tippy="{ theme: 'tooltip' }"
-              :title="$t('use_token_req')"
-              icon="input"
-            />
-            <ButtonSecondary
-              :disabled="this.tokenReqs.length === 0"
-              @click.native="removeOAuthTokenReq"
-              v-tippy="{ theme: 'tooltip' }"
-              :title="$t('delete')"
-              icon="delete"
-            />
-          </div>
-        </div>
-        <ul>
-          <li>
-            <span class="select-wrapper">
-              <select
-                id="token-req-list"
-                class="select"
-                v-model="tokenReqSelect"
-                :disabled="this.tokenReqs.length === 0"
-                @change="tokenReqChange($event)"
-              >
-                <option
-                  v-for="(req, index) in tokenReqs"
-                  :key="index"
-                  :value="req.name"
-                >
-                  {{ req.name }}
-                </option>
-              </select>
-            </span>
-          </li>
-        </ul>
-        <label for="token-req-name">{{ $t("token_req_name") }}</label>
-        <input class="input" v-model="tokenReqName" />
-        <label for="token-req-details">
-          {{ $t("token_req_details") }}
-        </label>
-        <textarea
-          id="token-req-details"
-          class="textarea"
-          readonly
-          rows="7"
-          v-model="tokenReqDetails"
-        ></textarea>
-      </template>
-      <template #footer>
-        <span></span>
-        <span>
-          <ButtonPrimary @click.native="addOAuthTokenReq" />
-          {{ $t("save_token_req") }}
-        </span>
-      </template>
-    </SmartModal>
-  </div>
-</template>
-
-<script>
-/* eslint-disable */
-import { Splitpanes, Pane } from "splitpanes"
-import "splitpanes/dist/splitpanes.css"
-
-import url from "url"
-import querystring from "querystring"
-import parseCurlCommand from "~/helpers/curlparser"
-import getEnvironmentVariablesFromScript from "~/helpers/preRequest"
-import runTestScriptWithVariables from "~/helpers/postwomanTesting"
-import parseTemplateString from "~/helpers/templating"
-import { tokenRequest, oauthRedirect } from "~/helpers/oauth"
-import { cancelRunningRequest, sendNetworkRequest } from "~/helpers/network"
-import {
-  hasPathParams,
-  addPathParamsToVariables,
-  getQueryParams,
-} from "~/helpers/requestParams"
-import { parseUrlAndPath } from "~/helpers/utils/uri"
-import { httpValid } from "~/helpers/utils/valid"
-import {
-  knownContentTypes,
-  isJSONContentType,
-} from "~/helpers/utils/contenttypes"
-import { generateCodeWithGenerator } from "~/helpers/codegen/codegen"
-import { getSettingSubject, applySetting } from "~/newstore/settings"
-import { addRESTHistoryEntry } from "~/newstore/history"
-import clone from "lodash/clone"
-
-export default {
-  components: { Splitpanes, Pane },
-
-  data() {
-    return {
-      showCurlImportModal: false,
-      showPreRequestScript: true,
-      testsEnabled: true,
-      testScript: "// pw.expect('variable').toBe('value');",
-      preRequestScript: "// pw.env.set('variable', 'value');",
-      testReports: [],
-      copyButton: '<i class="material-icons">content_copy</i>',
-      downloadButton: '<i class="material-icons">save_alt</i>',
-      doneButton: '<i class="material-icons">done</i>',
-      showCodegenModal: false,
-      response: {
-        status: "",
-        headers: "",
-        body: "",
-        duration: 0,
-        size: 0,
-      },
-      validContentTypes: knownContentTypes,
-      paramsWatchEnabled: true,
-      showTokenListModal: false,
-      showTokenRequest: false,
-      showTokenRequestList: false,
-      showSaveRequestModal: false,
-      editRequest: {},
-      customMethod: false,
-      files: [],
-      filenames: "",
-      navigatorShare: navigator.share,
-      runningRequest: false,
-      currentMethodIndex: 0,
-      methodMenuItems: [
-        "GET",
-        "HEAD",
-        "POST",
-        "PUT",
-        "DELETE",
-        "CONNECT",
-        "OPTIONS",
-        "TRACE",
-        "PATCH",
-        "CUSTOM",
-      ],
-    }
-  },
-  subscriptions() {
-    return {
-      SCROLL_INTO_ENABLED: getSettingSubject("SCROLL_INTO_ENABLED"),
-      PROXY_ENABLED: getSettingSubject("PROXY_ENABLED"),
-      URL_EXCLUDES: getSettingSubject("URL_EXCLUDES"),
-      EXPERIMENTAL_URL_BAR_ENABLED: getSettingSubject(
-        "EXPERIMENTAL_URL_BAR_ENABLED"
-      ),
-    }
-  },
-  watch: {
-    canListParameters: {
-      immediate: true,
-      handler(canListParameters) {
-        if (canListParameters) {
-          this.$nextTick(() => {
-            this.rawInput = Boolean(this.rawParams && this.rawParams !== "{}")
-          })
-        } else {
-          this.rawInput = true
-        }
-      },
-    },
-    contentType(contentType, oldContentType) {
-      const getDefaultParams = (contentType) => {
-        if (isJSONContentType(contentType)) return "{}"
-        switch (contentType) {
-          case "application/xml":
-            return "<?xml version='1.0' encoding='utf-8'?>"
-          case "text/html":
-            return "<!doctype html>"
-        }
-        return ""
-      }
-      if (
-        !this.rawParams ||
-        this.rawParams === getDefaultParams(oldContentType)
-      ) {
-        this.rawParams = getDefaultParams(contentType)
-      }
-      this.setRouteQueryState()
-    },
-    params: {
-      handler(newValue) {
-        if (!this.paramsWatchEnabled) {
-          this.paramsWatchEnabled = true
-          return
-        }
-        let path = this.path
-        let queryString = getQueryParams(newValue)
-          .map(({ key, value }) => `${key.trim()}=${value.trim()}`)
-          .join("&")
-        queryString = queryString === "" ? "" : `?${encodeURI(queryString)}`
-        if (path.includes("?")) {
-          path = path.slice(0, path.indexOf("?")) + queryString
-        } else {
-          path = path + queryString
-        }
-        this.path = path
-        this.setRouteQueryState()
-      },
-      deep: true,
-    },
-    selectedRequest(newValue) {
-      // @TODO: Convert all variables to single request variable
-      if (!newValue) return
-      this.uri = newValue.url + newValue.path
-      this.url = newValue.url
-      this.path = newValue.path
-      this.method = newValue.method
-      this.auth = newValue.auth
-      this.httpUser = newValue.httpUser
-      this.httpPassword = newValue.httpPassword
-      this.passwordFieldType = newValue.passwordFieldType
-      this.bearerToken = newValue.bearerToken
-      this.headers = newValue.headers
-      this.params = newValue.params
-      this.bodyParams = newValue.bodyParams
-      this.rawParams = newValue.rawParams
-      this.rawInput = newValue.rawInput
-      this.contentType = newValue.contentType
-      this.requestType = newValue.requestType
-      if (newValue.preRequestScript) {
-        this.showPreRequestScript = true
-        this.preRequestScript = newValue.preRequestScript
-      }
-      if (newValue.testScript) {
-        this.testsEnabled = true
-        this.testScript = newValue.testScript
-      }
-      this.name = newValue.name
-    },
-    method() {
-      this.contentType = ["POST", "PUT", "PATCH", "DELETE"].includes(
-        this.method
-      )
-        ? this.contentType
-        : "application/json"
-    },
-    preRequestScript(val, oldVal) {
-      this.uri = this.uri
-    },
-  },
-  computed: {
-    /**
-     * Check content types that can be automatically
-     * serialized by postwoman.
-     */
-    canListParameters() {
-      return (
-        this.contentType === "application/x-www-form-urlencoded" ||
-        this.contentType === "multipart/form-data" ||
-        isJSONContentType(this.contentType)
-      )
-    },
-    uri: {
-      get() {
-        return this.$store.state.request.uri
-          ? this.$store.state.request.uri
-          : this.url + this.path
-      },
-      set(value) {
-        this.$store.commit("setState", { value, attribute: "uri" })
-        let url = value
-        if (
-          (this.preRequestScript && this.showPreRequestScript) ||
-          hasPathParams(this.params)
-        ) {
-          let environmentVariables = getEnvironmentVariablesFromScript(
-            this.preRequestScript
-          )
-          environmentVariables = addPathParamsToVariables(
-            this.params,
-            environmentVariables
-          )
-          url = parseTemplateString(value, environmentVariables)
-        }
-        let result = parseUrlAndPath(url)
-        this.url = result.url
-        this.path = result.path
-      },
-    },
-    url: {
-      get() {
-        return this.$store.state.request.url
-      },
-      set(value) {
-        this.$store.commit("setState", { value, attribute: "url" })
-      },
-    },
-    method: {
-      get() {
-        return this.$store.state.request.method
-      },
-      set(value) {
-        this.$store.commit("setState", { value, attribute: "method" })
-      },
-    },
-    path: {
-      get() {
-        return this.$store.state.request.path
-      },
-      set(value) {
-        this.$store.commit("setState", { value, attribute: "path" })
-      },
-    },
-    name: {
-      get() {
-        return this.$store.state.request.name
-      },
-      set(value) {
-        this.$store.commit("setState", { value, attribute: "name" })
-      },
-    },
-    auth: {
-      get() {
-        return this.$store.state.request.auth
-      },
-      set(value) {
-        this.$store.commit("setState", { value, attribute: "auth" })
-      },
-    },
-    httpUser: {
-      get() {
-        return this.$store.state.request.httpUser
-      },
-      set(value) {
-        this.$store.commit("setState", { value, attribute: "httpUser" })
-      },
-    },
-    httpPassword: {
-      get() {
-        return this.$store.state.request.httpPassword
-      },
-      set(value) {
-        this.$store.commit("setState", { value, attribute: "httpPassword" })
-      },
-    },
-    bearerToken: {
-      get() {
-        return this.$store.state.request.bearerToken
-      },
-      set(value) {
-        this.$store.commit("setState", { value, attribute: "bearerToken" })
-      },
-    },
-    tokens: {
-      get() {
-        return this.$store.state.oauth2.tokens
-      },
-      set(value) {
-        this.$store.commit("setOAuth2", { value, attribute: "tokens" })
-      },
-    },
-    tokenReqs: {
-      get() {
-        return this.$store.state.oauth2.tokenReqs
-      },
-      set(value) {
-        this.$store.commit("setOAuth2", { value, attribute: "tokenReqs" })
-      },
-    },
-    tokenReqSelect: {
-      get() {
-        return this.$store.state.oauth2.tokenReqSelect
-      },
-      set(value) {
-        this.$store.commit("setOAuth2", { value, attribute: "tokenReqSelect" })
-      },
-    },
-    tokenReqName: {
-      get() {
-        return this.$store.state.oauth2.tokenReqName
-      },
-      set(value) {
-        this.$store.commit("setOAuth2", { value, attribute: "tokenReqName" })
-      },
-    },
-    accessTokenName: {
-      get() {
-        return this.$store.state.oauth2.accessTokenName
-      },
-      set(value) {
-        this.$store.commit("setOAuth2", {
-          value,
-          attribute: "accessTokenName",
-        })
-      },
-    },
-    oidcDiscoveryUrl: {
-      get() {
-        return this.$store.state.oauth2.oidcDiscoveryUrl
-      },
-      set(value) {
-        this.$store.commit("setOAuth2", {
-          value,
-          attribute: "oidcDiscoveryUrl",
-        })
-      },
-    },
-    authUrl: {
-      get() {
-        return this.$store.state.oauth2.authUrl
-      },
-      set(value) {
-        this.$store.commit("setOAuth2", { value, attribute: "authUrl" })
-      },
-    },
-    accessTokenUrl: {
-      get() {
-        return this.$store.state.oauth2.accessTokenUrl
-      },
-      set(value) {
-        this.$store.commit("setOAuth2", { value, attribute: "accessTokenUrl" })
-      },
-    },
-    clientId: {
-      get() {
-        return this.$store.state.oauth2.clientId
-      },
-      set(value) {
-        this.$store.commit("setOAuth2", { value, attribute: "clientId" })
-      },
-    },
-    scope: {
-      get() {
-        return this.$store.state.oauth2.scope
-      },
-      set(value) {
-        this.$store.commit("setOAuth2", { value, attribute: "scope" })
-      },
-    },
-    state: {
-      get() {
-        return this.$store.state.oauth2.state
-      },
-      set(value) {
-        this.$store.commit("setOAuth2", { value, attribute: "state" })
-      },
-    },
-    headers: {
-      get() {
-        return this.$store.state.request.headers
-      },
-      set(value) {
-        this.$store.commit("setState", { value, attribute: "headers" })
-      },
-    },
-    params: {
-      get() {
-        return this.$store.state.request.params
-      },
-      set(value) {
-        this.$store.commit("setState", { value, attribute: "params" })
-      },
-    },
-    bodyParams: {
-      get() {
-        return this.$store.state.request.bodyParams
-      },
-      set(value) {
-        this.$store.commit("setState", { value, attribute: "bodyParams" })
-      },
-    },
-    rawParams: {
-      get() {
-        return this.$store.state.request.rawParams
-      },
-      set(value) {
-        this.$store.commit("setState", { value, attribute: "rawParams" })
-        // Convert the rawParams to bodyParams format
-        try {
-          const valueObj = JSON.parse(value)
-          const params = Object.keys(valueObj).map((key) => {
-            if (typeof valueObj[key] !== "function") {
-              return {
-                active: true,
-                key,
-                value: valueObj[key],
-              }
-            }
-          })
-          this.$store.commit("setBodyParams", { params })
-        } catch {}
-      },
-    },
-    rawInput: {
-      get() {
-        return this.$store.state.request.rawInput
-      },
-      set(value) {
-        this.$store.commit("setState", { value, attribute: "rawInput" })
-      },
-    },
-    requestType: {
-      get() {
-        return this.$store.state.request.requestType
-      },
-      set(value) {
-        this.$store.commit("setState", { value, attribute: "requestType" })
-      },
-    },
-    contentType: {
-      get() {
-        return this.$store.state.request.contentType
-      },
-      set(value) {
-        this.$store.commit("setState", { value, attribute: "contentType" })
-      },
-    },
-    passwordFieldType: {
-      get() {
-        return this.$store.state.request.passwordFieldType
-      },
-      set(value) {
-        this.$store.commit("setState", {
-          value,
-          attribute: "passwordFieldType",
-        })
-      },
-    },
-    selectedRequest() {
-      return this.$store.state.postwoman.selectedRequest
-    },
-    requestName() {
-      return this.name
-    },
-    isValidURL() {
-      // if showPreRequestScript, we cannot determine if a URL is valid because the full string is not known ahead of time
-      return this.showPreRequestScript || httpValid(this.url)
-    },
-    hasRequestBody() {
-      return ["POST", "PUT", "PATCH", "DELETE"].includes(this.method)
-    },
-    pathName() {
-      return this.path.match(/^([^?]*)\??/)[1]
-    },
-    rawRequestBody() {
-      const { bodyParams, contentType } = this
-      if (isJSONContentType(contentType)) {
-        try {
-          const obj = JSON.parse(
-            `{${bodyParams
-              .filter((item) =>
-                item.hasOwnProperty("active") ? item.active == true : true
-              )
-              .filter(({ key }) => !!key)
-              .map(({ key, value }) => `"${key}": "${value}"`)
-              .join()}}`
-          )
-          return JSON.stringify(obj, null, 2)
-        } catch (ex) {
-          console.log(ex)
-          this.$toast.clear()
-          this.$toast.error(
-            "Parameter value must be a string, switch to Raw input for other formats",
-            {
-              icon: "error",
-            }
-          )
-          return "invalid"
-        }
-      } else {
-        return bodyParams
-          .filter((item) =>
-            item.hasOwnProperty("active") ? item.active == true : true
-          )
-          .filter(({ key }) => !!key)
-          .map(
-            ({ key, value }) =>
-              `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
-          )
-          .join("&")
-      }
-    },
-    queryString() {
-      const result = getQueryParams(this.params)
-        .map(
-          ({ key, value }) =>
-            `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
-        )
-        .join("&")
-      return result === "" ? "" : `?${result}`
-    },
-    requestCode() {
-      let headers = []
-      if (this.preRequestScript || hasPathParams(this.params)) {
-        let environmentVariables = getEnvironmentVariablesFromScript(
-          this.preRequestScript
-        )
-        environmentVariables = addPathParamsToVariables(
-          this.params,
-          environmentVariables
-        )
-        for (let k of this.headers.filter((item) =>
-          item.hasOwnProperty("active") ? item.active == true : true
-        )) {
-          const kParsed = parseTemplateString(k.key, environmentVariables)
-          const valParsed = parseTemplateString(k.value, environmentVariables)
-          headers.push({ key: kParsed, value: valParsed })
-        }
-      }
-
-      return generateCodeWithGenerator(this.requestType, {
-        auth: this.auth,
-        method: this.method,
-        url: this.url,
-        pathName: this.pathName,
-        queryString: this.queryString,
-        httpUser: this.httpUser,
-        httpPassword: this.httpPassword,
-        bearerToken: this.bearerToken,
-        headers,
-        rawInput: this.rawInput,
-        rawParams: this.rawParams,
-        rawRequestBody: this.rawRequestBody,
-        contentType: this.contentType,
-      })
-    },
-    tokenReqDetails() {
-      const details = {
-        oidcDiscoveryUrl: this.oidcDiscoveryUrl,
-        authUrl: this.authUrl,
-        accessTokenUrl: this.accessTokenUrl,
-        clientId: this.clientId,
-        scope: this.scope,
-      }
-      return JSON.stringify(details, null, 2)
-    },
-  },
-  methods: {
-    scrollInto(view) {
-      this.$refs[view].$el.scrollIntoView({
-        behavior: "smooth",
-      })
-    },
-    handleUseHistory(entry) {
-      this.name = entry.name
-      this.method = entry.method
-      this.uri = entry.url + entry.path
-      this.url = entry.url
-      this.path = entry.path
-      this.showPreRequestScript = entry.usesPreScripts
-      this.preRequestScript = entry.preRequestScript
-      this.auth = entry.auth
-      this.httpUser = entry.httpUser
-      this.httpPassword = entry.httpPassword
-      this.bearerToken = entry.bearerToken
-      this.headers = entry.headers
-      this.params = entry.params
-      this.bodyParams = entry.bodyParams
-      this.rawParams = entry.rawParams
-      this.rawInput = entry.rawInput
-      this.contentType = entry.contentType
-      this.requestType = entry.requestType
-      this.testScript = entry.testScript
-      this.testsEnabled = entry.usesPostScripts
-      if (this.SCROLL_INTO_ENABLED) this.scrollInto("request")
-    },
-    async makeRequest(auth, headers, requestBody, preRequestScript) {
-      const requestOptions = {
-        method: this.method,
-        url: this.url + this.pathName + this.queryString,
-        auth,
-        headers,
-        data: requestBody,
-        credentials: true,
-      }
-
-      if (preRequestScript || hasPathParams(this.params)) {
-        let environmentVariables =
-          getEnvironmentVariablesFromScript(preRequestScript)
-        environmentVariables = addPathParamsToVariables(
-          this.params,
-          environmentVariables
-        )
-        requestOptions.url = parseTemplateString(
-          requestOptions.url,
-          environmentVariables
-        )
-        if (!(requestOptions.data instanceof FormData)) {
-          // TODO: Parse env variables for form data too
-          requestOptions.data = parseTemplateString(
-            requestOptions.data,
-            environmentVariables
-          )
-        }
-        for (let k in requestOptions.headers) {
-          const kParsed = parseTemplateString(k, environmentVariables)
-          const valParsed = parseTemplateString(
-            requestOptions.headers[k],
-            environmentVariables
-          )
-          delete requestOptions.headers[k]
-          requestOptions.headers[kParsed] = valParsed
-        }
-      }
-      if (typeof requestOptions.data === "string") {
-        requestOptions.data = parseTemplateString(requestOptions.data)
-      }
-      return await sendNetworkRequest(requestOptions)
-    },
-    cancelRequest() {
-      cancelRunningRequest()
-    },
-    async sendRequest() {
-      this.$toast.clear()
-      if (this.SCROLL_INTO_ENABLED) this.scrollInto("response")
-      if (!this.isValidURL) {
-        this.$toast.error(this.$t("url_invalid_format"), {
-          icon: "error",
-        })
-        return
-      }
-      // Start showing the loading bar as soon as possible.
-      // The nuxt axios module will hide it when the request is made.
-      this.$nuxt.$loading.start()
-      this.response = {
-        duration: 0,
-        size: 0,
-        status: this.$t("fetching"),
-        body: this.$t("loading"),
-      }
-      const auth =
-        this.auth === "Basic Auth"
-          ? {
-              username: this.httpUser,
-              password: this.httpPassword,
-            }
-          : null
-      let headers = {}
-      let headersObject = {}
-      Object.keys(headers).forEach((id) => {
-        if (headers[id].key) headersObject[headers[id].key] = headers[id].value
-      })
-      headers = headersObject
-      // If the request has a body, we want to ensure Content-Type is sent.
-      let requestBody
-      if (this.hasRequestBody) {
-        requestBody = this.rawInput ? this.rawParams : this.rawRequestBody
-        Object.assign(headers, {
-          "Content-Type": `${this.contentType}; charset=utf-8`,
-        })
-      }
-      requestBody = requestBody ? requestBody.toString() : null
-      if (this.contentType === "multipart/form-data") {
-        const formData = new FormData()
-        for (const bodyParam of this.bodyParams.filter((item) =>
-          item.hasOwnProperty("active") ? item.active == true : true
-        )) {
-          if (bodyParam?.value?.[0] instanceof File) {
-            for (const file of bodyParam.value) {
-              formData.append(bodyParam.key, file)
-            }
-          } else {
-            formData.append(bodyParam.key, bodyParam.value)
-          }
-        }
-        requestBody = formData
-      }
-      // If the request uses a token for auth, we want to make sure it's sent here.
-      if (this.auth === "Bearer Token" || this.auth === "OAuth 2.0")
-        headers["Authorization"] = `Bearer ${this.bearerToken}`
-      headers = Object.assign(
-        // Clone the app headers object first, we don't want to
-        // mutate it with the request headers added by default.
-        Object.assign(
-          {},
-          this.headers.filter((item) =>
-            item.hasOwnProperty("active") ? item.active == true : true
-          )
-        )
-        // We make our temporary headers object the source so
-        // that you can override the added headers if you
-        // specify them.
-        // headers
-      )
-      Object.keys(headers).forEach((id) => {
-        if (headers[id].key) headersObject[headers[id].key] = headers[id].value
-      })
-      headers = headersObject
-      const startTime = new Date().getTime()
-      try {
-        this.runningRequest = true
-        const payload = await this.makeRequest(
-          auth,
-          headers,
-          requestBody,
-          this.showPreRequestScript && this.preRequestScript
-        )
-        this.runningRequest = false
-        const duration = new Date().getTime() - startTime
-        this.response.duration = duration
-        this.response.size = payload.headers["content-length"]
-        ;(() => {
-          this.response.status = payload.status
-          this.response.headers = payload.headers
-          // We don't need to bother parsing JSON, axios already handles it for us!
-          this.response.body = payload.data
-          // Addition of an entry to the history component.
-          const entry = {
-            name: this.requestName,
-            status: this.response.status,
-            date: new Date().toLocaleDateString(),
-            time: new Date().toLocaleTimeString(),
-            updatedOn: new Date(),
-            method: this.method,
-            url: this.url,
-            path: this.path,
-            usesPreScripts: this.showPreRequestScript,
-            preRequestScript: this.preRequestScript,
-            duration,
-            star: false,
-            auth: this.auth,
-            httpUser: this.httpUser,
-            httpPassword: this.httpPassword,
-            bearerToken: this.bearerToken,
-            headers: this.headers,
-            params: this.params,
-            bodyParams: this.bodyParams,
-            rawParams: this.rawParams,
-            rawInput: this.rawInput,
-            contentType: this.contentType,
-            requestType: this.requestType,
-            testScript: this.testScript,
-            usesPostScripts: this.testsEnabled,
-          }
-
-          if (
-            (this.preRequestScript && this.showPreRequestScript) ||
-            hasPathParams(this.params)
-          ) {
-            let environmentVariables = getEnvironmentVariablesFromScript(
-              this.preRequestScript
-            )
-            environmentVariables = addPathParamsToVariables(
-              this.params,
-              environmentVariables
-            )
-            entry.path = parseTemplateString(entry.path, environmentVariables)
-            entry.url = parseTemplateString(entry.url, environmentVariables)
-          }
-
-          addRESTHistoryEntry(entry)
-        })()
-      } catch (error) {
-        this.runningRequest = false
-        // If the error is caused by cancellation, do nothing
-        if (error === "cancellation") {
-          this.response.status = this.$t("cancelled")
-          this.response.body = this.$t("cancelled")
-        } else {
-          console.log(error)
-          const duration = new Date().getTime() - startTime
-          this.response.duration = duration
-          this.response.size = Buffer.byteLength(JSON.stringify(error))
-          if (error.response) {
-            this.response.headers = error.response.headers
-            this.response.status = error.response.status
-            this.response.body = error.response.data
-            // Addition of an entry to the history component.
-            const entry = {
-              name: this.requestName,
-              status: this.response.status,
-              date: new Date().toLocaleDateString(),
-              time: new Date().toLocaleTimeString(),
-              updatedOn: new Date(),
-              method: this.method,
-              url: this.url,
-              path: this.path,
-              usesPreScripts: this.showPreRequestScript,
-              preRequestScript: this.preRequestScript,
-              star: false,
-              auth: this.auth,
-              httpUser: this.httpUser,
-              httpPassword: this.httpPassword,
-              bearerToken: this.bearerToken,
-              headers: this.headers,
-              params: this.params,
-              bodyParams: this.bodyParams,
-              rawParams: this.rawParams,
-              rawInput: this.rawInput,
-              contentType: this.contentType,
-              requestType: this.requestType,
-              testScript: this.testScript,
-              usesPostScripts: this.testsEnabled,
-            }
-
-            if (
-              (this.preRequestScript && this.showPreRequestScript) ||
-              hasPathParams(this.params)
-            ) {
-              let environmentVariables = getEnvironmentVariablesFromScript(
-                this.preRequestScript
-              )
-              environmentVariables = addPathParamsToVariables(
-                this.params,
-                environmentVariables
-              )
-              entry.path = parseTemplateString(entry.path, environmentVariables)
-              entry.url = parseTemplateString(entry.url, environmentVariables)
-            }
-
-            addRESTHistoryEntry(entry)
-            return
-          } else {
-            this.response.status = error.message
-            this.response.body = `${error}. ${this.$t("check_console_details")}`
-            this.$toast.error(`${error} ${this.$t("f12_details")}`, {
-              icon: "error",
-            })
-            if (!this.PROXY_ENABLED) {
-              this.$toast.info(this.$t("enable_proxy"), {
-                icon: "help",
-                duration: 8000,
-                action: {
-                  text: this.$t("yes"),
-                  onClick: (e, toastObject) => {
-                    this.$router.push({ path: "/settings" })
-                  },
-                },
-              })
-            }
-          }
-        }
-      }
-      // tests
-      const syntheticResponse = {
-        status: this.response.status,
-        body: this.response.body,
-        headers: this.response.headers,
-      }
-
-      // Parse JSON body
-      if (
-        syntheticResponse.headers["content-type"] &&
-        isJSONContentType(syntheticResponse.headers["content-type"])
-      ) {
-        try {
-          syntheticResponse.body = JSON.parse(
-            new TextDecoder("utf-8").decode(
-              new Uint8Array(syntheticResponse.body)
-            )
-          )
-        } catch (_e) {}
-      }
-
-      const { testResults } = runTestScriptWithVariables(this.testScript, {
-        response: syntheticResponse,
-      })
-      this.testReports = testResults
-    },
-    getQueryStringFromPath() {
-      const pathParsed = url.parse(this.uri)
-      return pathParsed.query ? pathParsed.query : ""
-    },
-    queryStringToArray(queryString) {
-      const queryParsed = querystring.parse(queryString)
-      return Object.keys(queryParsed).map((key) => ({
-        key,
-        value: queryParsed[key],
-        active: true,
-      }))
-    },
-    pathInputHandler() {
-      if (this.uri.includes("?")) {
-        const queryString = this.getQueryStringFromPath()
-        let environmentVariables = getEnvironmentVariablesFromScript(
-          this.preRequestScript
-        )
-        environmentVariables = addPathParamsToVariables(
-          this.params,
-          environmentVariables
-        )
-        const params = this.queryStringToArray(queryString)
-        let parsedParams = []
-        for (let k of params.filter((item) =>
-          item.hasOwnProperty("active") ? item.active == true : true
-        )) {
-          const kParsed = parseTemplateString(k.key, environmentVariables)
-          const valParsed = parseTemplateString(k.value, environmentVariables)
-          parsedParams.push({ key: kParsed, value: valParsed, active: true })
-        }
-        this.paramsWatchEnabled = false
-        this.params = parsedParams
-      }
-    },
-    addRequestHeader() {
-      this.$store.commit("addHeaders", {
-        key: "",
-        value: "",
-        active: true,
-      })
-      return false
-    },
-    removeRequestHeader(index) {
-      // .slice() gives us an entirely new array rather than giving us just the reference
-      const oldHeaders = this.headers.slice()
-      this.$store.commit("removeHeaders", index)
-      this.$toast.error(this.$t("deleted"), {
-        icon: "delete",
-        action: {
-          text: this.$t("undo"),
-          onClick: (e, toastObject) => {
-            this.headers = oldHeaders
-            toastObject.remove()
-          },
-        },
-      })
-    },
-    addRequestParam() {
-      this.$store.commit("addParams", {
-        key: "",
-        value: "",
-        type: "query",
-        active: true,
-      })
-      return false
-    },
-    removeRequestParam(index) {
-      // .slice() gives us an entirely new array rather than giving us just the reference
-      const oldParams = this.params.slice()
-      this.$store.commit("removeParams", index)
-      this.$toast.error(this.$t("deleted"), {
-        icon: "delete",
-        action: {
-          text: this.$t("undo"),
-          onClick: (e, toastObject) => {
-            this.params = oldParams
-            toastObject.remove()
-          },
-        },
-      })
-    },
-    addRequestBodyParam() {
-      this.$store.commit("addBodyParams", { key: "", value: "", active: true })
-      return false
-    },
-    removeRequestBodyParam(index) {
-      // .slice() gives us an entirely new array rather than giving us just the reference
-      const oldBodyParams = this.bodyParams.slice()
-      this.$store.commit("removeBodyParams", index)
-      this.$toast.error(this.$t("deleted"), {
-        icon: "delete",
-        action: {
-          text: this.$t("undo"),
-          onClick: (e, toastObject) => {
-            this.bodyParams = oldBodyParams
-            toastObject.remove()
-          },
-        },
-      })
-    },
-    copyRequest() {
-      if (navigator.share) {
-        const time = new Date().toLocaleTimeString()
-        const date = new Date().toLocaleDateString()
-        navigator
-          .share({
-            title: "Hoppscotch",
-            text: `Hoppscotch • Open source API development ecosystem at ${time} on ${date}`,
-            url: window.location.href,
-          })
-          .then(() => {})
-          .catch(() => {})
-      } else {
-        const dummy = document.createElement("input")
-        document.body.appendChild(dummy)
-        dummy.value = window.location.href
-        dummy.select()
-        document.execCommand("copy")
-        document.body.removeChild(dummy)
-        this.$refs.copyRequest.innerHTML = this.doneButton
-        this.$toast.info(this.$t("copied_to_clipboard"), {
-          icon: "done",
-        })
-        setTimeout(
-          () => (this.$refs.copyRequest.innerHTML = this.copyButton),
-          1000
-        )
-      }
-    },
-    setRouteQueryState() {
-      const flat = (key) => (this[key] !== "" ? `${key}=${this[key]}&` : "")
-      const deep = (key) => {
-        const haveItems = [...this[key]].length
-        if (haveItems && this[key]["value"] !== "") {
-          // Exclude files fro  query params
-          const filesRemoved = this[key].filter(
-            (item) => !(item?.value?.[0] instanceof File)
-          )
-          return `${key}=${JSON.stringify(filesRemoved)}&`
-        }
-        return ""
-      }
-      let flats = [
-        "method",
-        "url",
-        "path",
-        !this.URL_EXCLUDES.auth ? "auth" : null,
-        !this.URL_EXCLUDES.httpUser ? "httpUser" : null,
-        !this.URL_EXCLUDES.httpPassword ? "httpPassword" : null,
-        !this.URL_EXCLUDES.bearerToken ? "bearerToken" : null,
-        "contentType",
-      ]
-        .filter((item) => item !== null)
-        .map((item) => flat(item))
-      const deeps = ["headers", "params"].map((item) => deep(item))
-      const bodyParams = this.rawInput
-        ? [flat("rawParams")]
-        : [deep("bodyParams")]
-      history.replaceState(
-        window.location.href,
-        "",
-        `${this.$router.options.base}?${encodeURI(
-          flats.concat(deeps, bodyParams).join("").slice(0, -1)
-        )}`
-      )
-    },
-    setRouteQueries(queries) {
-      if (typeof queries !== "object")
-        throw new Error("Route query parameters must be a Object")
-      for (const key in queries) {
-        if (["headers", "params", "bodyParams"].includes(key))
-          this[key] = JSON.parse(decodeURI(encodeURI(queries[key])))
-        if (key === "rawParams") {
-          this.rawInput = true
-          this.rawParams = queries["rawParams"]
-        } else if (typeof this[key] === "string") {
-          this[key] = queries[key]
-        }
-      }
-    },
-    // observeRequestButton() {
-    //   const requestElement = this.$refs.request
-    //   const sendButtonElement = this.$refs.sendButton
-    //   const observer = new IntersectionObserver(
-    //     (entries, observer) => {
-    //       entries.forEach(({ isIntersecting }) => {
-    //         if (isIntersecting) sendButtonElement.classList.remove("show")
-    //         // The button should float when it is no longer visible on screen.
-    //         // This is done by adding the show class to the button.
-    //         else sendButtonElement.classList.add("show")
-    //       })
-    //     },
-    //     {
-    //       rootMargin: "0px",
-    //       threshold: [0],
-    //     }
-    //   )
-    //   observer.observe(requestElement)
-    // },
-    handleImport() {
-      const { value: text } = document.getElementById("import-curl")
-      try {
-        const parsedCurl = parseCurlCommand(text)
-        const { origin, pathname } = new URL(
-          parsedCurl.url.replace(/"/g, "").replace(/'/g, "")
-        )
-        this.url = origin
-        this.path = pathname
-        this.uri = this.url + this.path
-        this.headers = []
-        if (parsedCurl.query) {
-          for (const key of Object.keys(parsedCurl.query)) {
-            this.$store.commit("addParams", {
-              key,
-              value: parsedCurl.query[key],
-              type: "query",
-              active: true,
-            })
-          }
-        }
-        if (parsedCurl.headers) {
-          for (const key of Object.keys(parsedCurl.headers)) {
-            this.$store.commit("addHeaders", {
-              key,
-              value: parsedCurl.headers[key],
-            })
-          }
-        }
-        this.method = parsedCurl.method.toUpperCase()
-        if (parsedCurl["data"]) {
-          this.rawInput = true
-          this.rawParams = parsedCurl["data"]
-        }
-        this.showCurlImportModal = false
-      } catch (error) {
-        this.showCurlImportModal = false
-        this.$toast.error(this.$t("curl_invalid_format"), {
-          icon: "error",
-        })
-      }
-    },
-    switchVisibility() {
-      this.passwordFieldType =
-        this.passwordFieldType === "password" ? "text" : "password"
-    },
-    clearContent(name, { target }) {
-      switch (name) {
-        case "bodyParams":
-          this.bodyParams = []
-          this.files = []
-          break
-        case "rawParams":
-          this.rawParams = "{}"
-          break
-        case "parameters":
-          this.params = []
-          break
-        case "auth":
-          this.auth = "None"
-          this.httpUser = ""
-          this.httpPassword = ""
-          this.bearerToken = ""
-          this.showTokenRequest = false
-          this.tokens = []
-          this.tokenReqs = []
-          break
-        case "access_token":
-          this.accessTokenName = ""
-          this.oidcDiscoveryUrl = ""
-          this.authUrl = ""
-          this.accessTokenUrl = ""
-          this.clientId = ""
-          this.scope = ""
-          break
-        case "headers":
-          this.headers = []
-          break
-        case "tests":
-          this.testReports = []
-          break
-        case "tokens":
-          this.tokens = []
-          break
-        default:
-          this.method = "GET"
-          this.url = "https://httpbin.org"
-          this.path = "/get"
-          this.uri = this.url + this.path
-          this.name = "Untitled request"
-          this.bodyParams = []
-          this.rawParams = "{}"
-          this.files = []
-          this.params = []
-          this.auth = "None"
-          this.httpUser = ""
-          this.httpPassword = ""
-          this.bearerToken = ""
-          this.showTokenRequest = false
-          this.tokens = []
-          this.tokenReqs = []
-          this.accessTokenName = ""
-          this.oidcDiscoveryUrl = ""
-          this.authUrl = ""
-          this.accessTokenUrl = ""
-          this.clientId = ""
-          this.scope = ""
-          this.headers = []
-          this.testReports = []
-      }
-      target.innerHTML = this.doneButton
-      this.$toast.info(this.$t("cleared"), {
-        icon: "clear_all",
-      })
-      setTimeout(
-        () => (target.innerHTML = '<i class="material-icons">clear_all</i>'),
-        1000
-      )
-    },
-    saveRequest() {
-      let urlAndPath = parseUrlAndPath(this.uri)
-      this.editRequest = {
-        url: decodeURI(urlAndPath.url),
-        path: decodeURI(urlAndPath.path),
-        method: this.method,
-        auth: this.auth,
-        httpUser: this.httpUser,
-        httpPassword: this.httpPassword,
-        passwordFieldType: this.passwordFieldType,
-        bearerToken: this.bearerToken,
-        headers: this.headers,
-        params: this.params,
-        bodyParams: this.bodyParams,
-        rawParams: this.rawParams,
-        rawInput: this.rawInput,
-        contentType: this.contentType,
-        requestType: this.requestType,
-        preRequestScript:
-          this.showPreRequestScript == true ? this.preRequestScript : null,
-        testScript: this.testsEnabled == true ? this.testScript : null,
-        name: this.requestName,
-      }
-      this.showSaveRequestModal = true
-    },
-    hideRequestModal() {
-      this.showSaveRequestModal = false
-      this.editRequest = {}
-    },
-    setExclude(excludedField, excluded) {
-      const update = clone(this.URL_EXCLUDES)
-
-      if (excludedField === "auth") {
-        update.auth = excluded
-        update.httpUser = excluded
-        update.httpPassword = excluded
-        update.bearerToken = excluded
-      } else {
-        update[excludedField] = excluded
-      }
-
-      applySetting("URL_EXCLUDES", update)
-
-      this.setRouteQueryState()
-    },
-    updateRawBody(rawParams) {
-      this.rawParams = rawParams
-    },
-    async handleAccessTokenRequest() {
-      if (
-        this.oidcDiscoveryUrl === "" &&
-        (this.authUrl === "" || this.accessTokenUrl === "")
-      ) {
-        this.$toast.error(this.$t("complete_config_urls"), {
-          icon: "error",
-        })
-        return
-      }
-      try {
-        const tokenReqParams = {
-          grantType: "code",
-          oidcDiscoveryUrl: this.oidcDiscoveryUrl,
-          authUrl: this.authUrl,
-          accessTokenUrl: this.accessTokenUrl,
-          clientId: this.clientId,
-          scope: this.scope,
-        }
-        await tokenRequest(tokenReqParams)
-      } catch (e) {
-        this.$toast.error(e, {
-          icon: "code",
-        })
-      }
-    },
-    async oauthRedirectReq() {
-      const tokenInfo = await oauthRedirect()
-      if (Object.prototype.hasOwnProperty.call(tokenInfo, "access_token")) {
-        this.bearerToken = tokenInfo.access_token
-        this.addOAuthToken({
-          name: this.accessTokenName,
-          value: tokenInfo.access_token,
-        })
-      }
-    },
-    addOAuthToken({ name, value }) {
-      this.$store.commit("addOAuthToken", {
-        name,
-        value,
-      })
-      return false
-    },
-    removeOAuthToken(index) {
-      const oldTokens = this.tokens.slice()
-      this.$store.commit("removeOAuthToken", index)
-      this.$toast.error(this.$t("deleted"), {
-        icon: "delete",
-        action: {
-          text: this.$t("undo"),
-          onClick: (e, toastObject) => {
-            this.tokens = oldTokens
-            toastObject.remove()
-          },
-        },
-      })
-    },
-    useOAuthToken(value) {
-      this.bearerToken = value
-      this.showTokenListModal = false
-    },
-    addOAuthTokenReq() {
-      try {
-        const name = this.tokenReqName
-        const details = JSON.parse(this.tokenReqDetails)
-        this.$store.commit("addOAuthTokenReq", {
-          name,
-          details,
-        })
-        this.$toast.info(this.$t("token_request_saved"))
-        this.showTokenRequestList = false
-      } catch (e) {
-        this.$toast.error(e, {
-          icon: "code",
-        })
-      }
-    },
-    removeOAuthTokenReq(index) {
-      const oldTokenReqs = this.tokenReqs.slice()
-      const targetReqIndex = this.tokenReqs.findIndex(
-        ({ name }) => name === this.tokenReqName
-      )
-      if (targetReqIndex < 0) return
-      this.$store.commit("removeOAuthTokenReq", targetReqIndex)
-      this.$toast.error(this.$t("deleted"), {
-        icon: "delete",
-        action: {
-          text: this.$t("undo"),
-          onClick: (e, toastObject) => {
-            this.tokenReqs = oldTokenReqs
-            toastObject.remove()
-          },
-        },
-      })
-    },
-    tokenReqChange({ target }) {
-      const { details, name } = this.tokenReqs.find(
-        ({ name }) => name === target.value
-      )
-      const { oidcDiscoveryUrl, authUrl, accessTokenUrl, clientId, scope } =
-        details
-      this.tokenReqName = name
-      this.oidcDiscoveryUrl = oidcDiscoveryUrl
-      this.authUrl = authUrl
-      this.accessTokenUrl = accessTokenUrl
-      this.clientId = clientId
-      this.scope = scope
-    },
-    setRequestType(val) {
-      this.requestType = val
-    },
-  },
-  async mounted() {
-    // this.observeRequestButton()
-    this._keyListener = function (e) {
-      if (e.key === "g" && (e.ctrlKey || e.metaKey)) {
-        e.preventDefault()
-        if (!this.runningRequest) {
-          this.sendRequest()
-        } else {
-          this.cancelRequest()
-        }
-      }
-      if (e.key === "s" && (e.ctrlKey || e.metaKey)) {
-        e.preventDefault()
-        this.saveRequest()
-      }
-      if (e.key === "k" && (e.ctrlKey || e.metaKey)) {
-        e.preventDefault()
-        this.copyRequest()
-      }
-      if (e.key === "i" && (e.ctrlKey || e.metaKey)) {
-        e.preventDefault()
-        this.$refs.clearAll.click()
-      }
-      if ((e.key === "g" || e.key === "G") && e.altKey) {
-        this.method = "GET"
-      }
-      if ((e.key === "h" || e.key === "H") && e.altKey) {
-        this.method = "HEAD"
-      }
-      if ((e.key === "p" || e.key === "P") && e.altKey) {
-        this.method = "POST"
-      }
-      if ((e.key === "u" || e.key === "U") && e.altKey) {
-        this.method = "PUT"
-      }
-      if ((e.key === "x" || e.key === "X") && e.altKey) {
-        this.method = "DELETE"
-      }
-      if (e.key == "ArrowUp" && e.altKey && this.currentMethodIndex > 0) {
-        this.method =
-          this.methodMenuItems[
-            --this.currentMethodIndex % this.methodMenuItems.length
-          ]
-      } else if (
-        e.key == "ArrowDown" &&
-        e.altKey &&
-        this.currentMethodIndex < 9
-      ) {
-        this.method =
-          this.methodMenuItems[
-            ++this.currentMethodIndex % this.methodMenuItems.length
-          ]
-      }
-    }
-    document.addEventListener("keydown", this._keyListener.bind(this))
-    await this.oauthRedirectReq()
-  },
-  created() {
-    if (Object.keys(this.$route.query).length)
-      this.setRouteQueries(this.$route.query)
-    this.$watch(
-      (vm) => [
-        vm.name,
-        vm.method,
-        vm.url,
-        vm.auth,
-        vm.path,
-        vm.httpUser,
-        vm.httpPassword,
-        vm.bearerToken,
-        vm.headers,
-        vm.params,
-        vm.bodyParams,
-        vm.contentType,
-        vm.rawParams,
-      ],
-      (val) => {
-        this.setRouteQueryState()
-      }
-    )
-  },
-  beforeDestroy() {
-    document.removeEventListener("keydown", this._keyListener)
-  },
-}
-</script>




diff --git a/pages/graphql.vue b/pages/graphql.vue
index c8447daef7356b27e618f0e43e1e447274538319..e7e6aa3f8e84909b800041130f4d4d1ff6d79833 100644
--- a/pages/graphql.vue
+++ b/pages/graphql.vue
@@ -343,6 +343,7 @@                       px-4
                       py-3
                       text-xs
                       flex flex-1
+                      font-medium
                       bg-primaryLight
                       focus:outline-none
                     "
@@ -420,19 +421,32 @@                       />
                     </SmartTab>
                   </div>
                 </SmartTabs>
+            <AppSection label="endpoint">
   <div>
-                            value: header.hasOwnProperty('active')
+<template>
                   v-if="
                     queryFields.length === 0 &&
                     mutationFields.length === 0 &&
                     subscriptionFields.length === 0 &&
                     graphqlTypes.length === 0
                   "
+                  class="
+                    flex
+                    items-center
+                    text-secondaryLight
+                    flex-col
+                    p-4
+                    justify-center
+                  "
                 >
+                  <i class="material-icons opacity-50 pb-2">description</i>
+                  <span class="text-xs">
+            <AppSection label="endpoint">
                       @click.native="onPollSchemaClick"
+                    <input
 <template>
     <Splitpanes vertical :dbl-click-splitter="false">
-  <div>
+    <Splitpanes vertical :dbl-click-splitter="false">
               </AppSection>
             </SmartTab>
 




diff --git a/pages/home.vue b/pages/home.vue
new file mode 100644
index 0000000000000000000000000000000000000000..9d8b63a9f39386642504c5b8942251a2df08d168
--- /dev/null
+++ b/pages/home.vue
@@ -0,0 +1,10 @@
+<template>
+  <div class="flex flex-col space-y-16">
+    <LandingHero />
+    <LandingStats />
+    <LandingUsers />
+    <LandingFeatures />
+    <LandingCTA />
+    <LandingFooter />
+  </div>
+</template>




diff --git a/pages/index.vue b/pages/index.vue
index 9d8b63a9f39386642504c5b8942251a2df08d168..0022ef8cfaaab5429a2458487676d7a473f14697 100644
--- a/pages/index.vue
+++ b/pages/index.vue
@@ -1,10 +1,2291 @@
 <template>
+  <!-- eslint-disable -->
+<template>
   <div class="flex flex-col space-y-16">
+<template>
     <LandingHero />
+<template>
     <LandingStats />
+<template>
     <LandingUsers />
+<template>
     <LandingFeatures />
+<template>
     <LandingCTA />
+<template>
     <LandingFooter />
+<template>
   </div>
+                  <tippy
+                    interactive
+                    ref="options"
+                    tabindex="-1"
+                    trigger="click"
+                    theme="popover"
+                    arrow
+                  >
+                    <template #trigger>
+                      <input
+                        id="method"
+                        class="
+                          flex
+                          rounded-l-lg
+                          bg-primaryLight
+                          font-mono
+                          w-32
+                          px-4
+                          py-2
+                          truncate
+                          font-semibold
+                          border border-divider
+                          transition
+                          focus:outline-none focus:border-accent
+                        "
+                        v-model="method"
+                        :readonly="!customMethod"
+                        autofocus
+                      />
+                    </template>
+                    <SmartItem
+                      v-for="(methodMenuItem, index) in methodMenuItems"
+                      :key="`method-${index}`"
+                      @click.native="
+                        customMethod = methodMenuItem == 'CUSTOM' ? true : false
+                        method = methodMenuItem
+                        $refs.options.tippy().hide()
+                      "
+                      :label="methodMenuItem"
+                    />
+                  </tippy>
+                </span>
+              </div>
+              <div class="flex-1 inline-flex">
+                <input
+                  v-if="!EXPERIMENTAL_URL_BAR_ENABLED"
+                  :class="{ error: !isValidURL }"
+                  class="
+                    w-full
+                    font-mono font-semibold
+                    truncate
+                    px-4
+                    py-2
+                    border border-divider
+                    bg-primaryLight
+                    transition
+                    focus:outline-none focus:border-accent
+                  "
+                  @keyup.enter="isValidURL ? sendRequest() : null"
+                  id="url"
+                  name="url"
+                  type="text"
+                  v-model="uri"
+                  spellcheck="false"
+                  @input="pathInputHandler"
+                  :placeholder="$t('url')"
+                />
+                <SmartUrlField v-model="uri" v-else />
+              </div>
+              <div class="flex">
+                <span
+                  id="send"
+                  :disabled="!isValidURL"
+                  @click="sendRequest"
+                  v-if="!runningRequest"
+                  class="
+                    px-4
+                    py-2
+                    border border-accent
+                    font-mono
+                    flex
+                    items-center
+                    justify-center
+                    truncate
+                    font-semibold
+                    bg-accent
+                    text-white
+                  "
+                >
+                  {{ $t("send") }}
+                </span>
+                <span
+                  id="cancel"
+                  @click="cancelRequest"
 </template>
+    <LandingFeatures />
+                  class="
+                    px-4
+                    py-2
+                    border border-accent
+                    font-mono
+                    flex
+                    items-center
+                    justify-center
+                    truncate
+                    font-semibold
+                    bg-accent
+                    text-white
+                  "
+                >
+                  {{ $t("cancel") }}
+                </span>
+                <tippy
+                  ref="sendOptions"
+                  interactive
+                  tabindex="-1"
+                  trigger="click"
+                  theme="popover"
+                  arrow
+                >
+                  <template #trigger>
+                    <span
+                      class="
+                        px-1
+                        py-2
+                        border border-accent
+                        font-mono
+                        flex
+                        items-center
+                        justify-center
+                        truncate
+                        font-semibold
+                        bg-accent
+                        text-white
+                        rounded-r-lg
+                      "
+                    >
+                      <i class="material-icons">keyboard_arrow_down</i>
+                    </span>
+                  </template>
+                  <SmartItem
+                    :label="$t('import_curl')"
+                    icon="import_export"
+                    @click.native="
+                      showCurlImportModal = !showCurlImportModal
+                      $refs.sendOptions.tippy().hide()
+                    "
+                  />
+                  <SmartItem
+                    @click.native="
+                      showCodegenModal = !showCodegenModal
+                      $refs.sendOptions.tippy().hide()
+                    "
+                    :disabled="!isValidURL"
+                    :label="$t('show_code')"
+                    icon="code"
+                  />
+                  <SmartItem
+                    @click.native="
+                      clearContent('', $event)
+                      $refs.sendOptions.tippy().hide()
+                    "
+                    :label="$t('clear_all')"
+                    ref="clearAll"
+                    icon="clear_all"
+                  />
+                </tippy>
+                <span
+                  class="
+                    ml-4
+                    px-4
+                    py-2
+                    border border-divider
+                    font-mono
+                    flex
+                    items-center
+                    justify-center
+                    truncate
+                    font-semibold
+                    rounded-l-lg
+                  "
+                >
+                  Save
+                </span>
+                <tippy
+                  ref="saveOptions"
+                  interactive
+                  tabindex="-1"
+                  trigger="click"
+                  theme="popover"
+                  arrow
+                >
+                  <template #trigger>
+                    <span
+                      class="
+                        px-1
+                        py-2
+                        border border-divider
+                        font-mono
+                        flex
+                        items-center
+                        justify-center
+                        truncate
+                        font-semibold
+                        rounded-r-lg
+                      "
+                    >
+                      <i class="material-icons">keyboard_arrow_down</i>
+                    </span>
+                  </template>
+                  <SmartItem :description="$t('token_req_name')" />
+                  <input
+                    id="request-name"
+                    name="request-name"
+                    type="text"
+                    v-model="name"
+                    class="input text-sm"
+                  />
+                  <SmartItem
+                    @click.native="
+                      copyRequest
+                      $refs.saveOptions.tippy().hide()
+                    "
+                    ref="copyRequest"
+                    :disabled="!isValidURL"
+                    :label="$t('copy_request_link')"
+                    :icon="navigatorShare ? 'share' : 'content_copy'"
+                  />
+                  <SmartItem
+                    @click.native="
+                      saveRequest
+                      $refs.saveOptions.tippy().hide()
+                    "
+                    ref="saveRequest"
+                    :disabled="!isValidURL"
+                    :label="$t('save_to_collections')"
+                    icon="create_new_folder"
+                  />
+                </tippy>
+              </div>
+            </div>
+            <SmartTabs styles="sticky top-62px z-10">
+              <SmartTab
+                :id="'params'"
+                :label="
+                  $t('parameters') +
+                  `${
+                    params.length !== 0 ? ' \xA0 • \xA0 ' + params.length : ''
+                  }`
+                "
+                :selected="true"
+              >
+                <HttpParameters
+                  :params="params"
+                  @clear-content="clearContent"
+                  @remove-request-param="removeRequestParam"
+                  @add-request-param="addRequestParam"
+                />
+              </SmartTab>
+
+              <SmartTab
+                :id="'bodyParams'"
+                :label="
+                  $t('body') +
+                  `${
+                    bodyParams.length !== 0
+                      ? ' \xA0 • \xA0 ' + bodyParams.length
+                      : ''
+                  }`
+                "
+              >
+                <ul>
+                  <li>
+                    <label for="contentType" class="text-sm">{{
+                      $t("content_type")
+                    }}</label>
+                    <span class="select-wrapper">
+                      <tippy
+                        interactive
+                        ref="contentTypeOptions"
+                        tabindex="-1"
+                        trigger="click"
+                        theme="popover"
+                        arrow
+                      >
+                        <template #trigger>
+                          <input
+                            id="contentType"
+                            class="input"
+                            v-model="contentType"
+                            readonly
+                          />
+                        </template>
+                        <SmartItem
+                          v-for="(
+                            contentTypeMenuItem, index
+                          ) in validContentTypes"
+                          :key="`content-type-${index}`"
+                          @click.native="
+                            contentType = contentTypeMenuItem
+                            $refs.contentTypeOptions.tippy().hide()
+                          "
+                          :label="contentTypeMenuItem"
+                        />
+                      </tippy>
+                    </span>
+                    <!-- <SmartAutoComplete
+                  :source="validContentTypes"
+                  :spellcheck="false"
+                  v-model="contentType"
+                  styles="text-sm"
+                /> -->
+                  </li>
+                </ul>
+                <ul>
+                  <li>
+                    <div class="flex flex-1">
+                      <span>
+                        <SmartToggle :on="rawInput" />
+                      </span>
+                    </div>
+                  </li>
+                </ul>
+                <HttpBodyParameters
+                  v-if="!rawInput"
+                  :bodyParams="bodyParams"
+                  @clear-content="clearContent"
+                  @set-route-query-state="setRouteQueryState"
+                  @remove-request-body-param="removeRequestBodyParam"
+                  @add-request-body-param="addRequestBodyParam"
+                />
+                <HttpRawBody
+                  v-else
+                  :rawParams="rawParams"
+                  :contentType="contentType"
+                  :rawInput="rawInput"
+                  @clear-content="clearContent"
+                  @update-raw-body="updateRawBody"
+                  @update-raw-input="
+                    updateRawInput = (value) => (rawInput = value)
+                  "
+                />
+              </SmartTab>
+
+              <SmartTab
+                :id="'headers'"
+                :label="
+                  $t('headers') +
+                  `${
+                    headers.length !== 0 ? ' \xA0 • \xA0 ' + headers.length : ''
+                  }`
+                "
+              >
+                <HttpHeaders
+                  :headers="headers"
+                  @clear-content="clearContent"
+                  @set-route-query-state="setRouteQueryState"
+                  @remove-request-header="removeRequestHeader"
+                  @add-request-header="addRequestHeader"
+                />
+              </SmartTab>
+
+              <SmartTab :id="'authentication'" :label="$t('authentication')">
+                <AppSection label="authentication">
+                  <ul>
+                    <li>
+                      <div class="flex flex-1">
+                        <label for="auth">{{ $t("authentication") }}</label>
+                        <div>
+                          <ButtonSecondary
+                            @click.native="clearContent('auth', $event)"
+                            v-tippy="{ theme: 'tooltip' }"
+                            :title="$t('clear')"
+                            icon="clear_all"
+                          />
+                        </div>
+                      </div>
+                      <span class="select-wrapper">
+                        <select class="select" id="auth" v-model="auth">
+                          <option>None</option>
+                          <option>Basic Auth</option>
+                          <option>Bearer Token</option>
+                          <option>OAuth 2.0</option>
+                        </select>
+                      </span>
+                    </li>
+                  </ul>
+                  <ul v-if="auth === 'Basic Auth'">
+                    <li>
+                      <input
+                        class="input"
+                        placeholder="User"
+                        name="http_basic_user"
+                        v-model="httpUser"
+                      />
+                    </li>
+                    <li>
+                      <input
+                        class="input"
+                        placeholder="Password"
+                        name="http_basic_passwd"
+                        :type="passwordFieldType"
+                        v-model="httpPassword"
+                      />
+                    </li>
+                    <div>
+                      <li>
+                        <ButtonSecondary
+                          ref="switchVisibility"
+                          @click.native="switchVisibility"
+                          :icon="
+                            passwordFieldType === 'text'
+                              ? 'visibility'
+                              : 'visibility_off'
+                          "
+                        />
+                      </li>
+                    </div>
+                  </ul>
+                  <ul v-if="auth === 'Bearer Token' || auth === 'OAuth 2.0'">
+                    <li>
+                      <div class="flex flex-1">
+                        <input
+                          class="input"
+                          placeholder="Token"
+                          name="bearer_token"
+                          v-model="bearerToken"
+                        />
+                        <ButtonSecondary
+                          v-if="auth === 'OAuth 2.0'"
+                          @click.native="
+                            showTokenListModal = !showTokenListModal
+                          "
+                          v-tippy="{ theme: 'tooltip' }"
+                          :title="$t('use_token')"
+                          icon="open_in_new"
+                        />
+                        <ButtonSecondary
+                          v-if="auth === 'OAuth 2.0'"
+                          @click.native="showTokenRequest = !showTokenRequest"
+                          v-tippy="{ theme: 'tooltip' }"
+                          :title="$t('get_token')"
+                          icon="vpn_key"
+                        />
+                      </div>
+                    </li>
+                  </ul>
+                  <div class="flex flex-1">
+                    <SmartToggle
+                      :on="!URL_EXCLUDES.auth"
+                      @change="setExclude('auth', !$event)"
+                    >
+                      {{ $t("include_in_url") }}
+                    </SmartToggle>
+                  </div>
+                </AppSection>
+
+                <AppSection v-if="showTokenRequest" label="accessTokenRequest">
+                  <ul>
+                    <li>
+                      <div class="flex flex-1">
+                        <label for="token-name">{{ $t("token_name") }}</label>
+                        <div>
+                          <ButtonSecondary
+                            @click.native="showTokenRequestList = true"
+                            v-tippy="{ theme: 'tooltip' }"
+                            :title="$t('manage_token_req')"
+                            icon="library_add"
+                          />
+                          <ButtonSecondary
+                            @click.native="clearContent('access_token', $event)"
+                            v-tippy="{ theme: 'tooltip' }"
+                            :title="$t('clear')"
+                            icon="clear_all"
+                          />
+                          <ButtonSecondary
+                            @click.native="showTokenRequest = false"
+                            v-tippy="{ theme: 'tooltip' }"
+                            :title="$t('close')"
+                            icon="close"
+                          />
+                        </div>
+                      </div>
+                      <input
+                        class="input"
+                        id="token-name"
+                        :placeholder="$t('optional')"
+                        name="token_name"
+                        v-model="accessTokenName"
+                        type="text"
+                      />
+                    </li>
+                  </ul>
+                  <ul>
+                    <li>
+                      <label for="oidc-discovery-url">
+                        {{ $t("oidc_discovery_url") }}
+                      </label>
+                      <input
+                        class="input"
+                        :disabled="
+                          this.authUrl !== '' || this.accessTokenUrl !== ''
+                        "
+                        id="oidc-discovery-url"
+                        name="oidc_discovery_url"
+                        type="url"
+                        v-model="oidcDiscoveryUrl"
+                        placeholder="https://example.com/.well-known/openid-configuration"
+                      />
+                    </li>
+                  </ul>
+                  <ul>
+                    <li>
+                      <label for="auth-url">{{ $t("auth_url") }}</label>
+                      <input
+                        class="input"
+                        :disabled="this.oidcDiscoveryUrl !== ''"
+                        id="auth-url"
+                        name="auth_url"
+                        type="url"
+                        v-model="authUrl"
+                        placeholder="https://example.com/login/oauth/authorize"
+                      />
+                    </li>
+                  </ul>
+                  <ul>
+                    <li>
+                      <label for="access-token-url">
+                        {{ $t("access_token_url") }}
+                      </label>
+                      <input
+                        class="input"
+                        :disabled="this.oidcDiscoveryUrl !== ''"
+                        id="access-token-url"
+                        name="access_token_url"
+                        type="url"
+                        v-model="accessTokenUrl"
+                        placeholder="https://example.com/login/oauth/access_token"
+                      />
+                    </li>
+                  </ul>
+                  <ul>
+                    <li>
+                      <label for="client-id">{{ $t("client_id") }}</label>
+                      <input
+                        class="input"
+                        id="client-id"
+                        name="client_id"
+                        type="text"
+                        v-model="clientId"
+                        placeholder="Client ID"
+                      />
+                    </li>
+                  </ul>
+                  <ul>
+                    <li>
+                      <label for="scope">{{ $t("scope") }}</label>
+                      <input
+                        class="input"
+                        id="scope"
+                        name="scope"
+                        type="text"
+                        v-model="scope"
+                        placeholder="e.g. read:org"
+                      />
+                    </li>
+                  </ul>
+                  <ul>
+                    <li>
+                      <ButtonSecondary
+                        @click.native="handleAccessTokenRequest"
+                        icon="vpn_key"
+                        :label="$t('request_token')"
+                      />
+                    </li>
+                  </ul>
+                </AppSection>
+              </SmartTab>
+
+              <SmartTab
+                :id="'pre_request_script'"
+                :label="$t('pre_request_script')"
+              >
+                <AppSection v-if="showPreRequestScript" label="preRequest">
+                  <ul>
+                    <li>
+                      <div class="flex flex-1">
+                        <label>{{ $t("javascript_code") }}</label>
+                        <div>
+                          <ButtonSecondary
+                            to="https://github.com/hoppscotch/hoppscotch/wiki/Pre-Request-Scripts"
+                            blank
+                            v-tippy="{ theme: 'tooltip' }"
+                            :title="$t('wiki')"
+                            icon="help_outline"
+                          />
+                        </div>
+                      </div>
+                      <SmartJsEditor
+                        v-model="preRequestScript"
+                        :options="{
+                          maxLines: '16',
+                          minLines: '8',
+                          fontSize: '15px',
+                          autoScrollEditorIntoView: true,
+                          showPrintMargin: false,
+                          useWorker: false,
+                        }"
+                        styles="rounded-b-lg"
+                        completeMode="pre"
+                      />
+                    </li>
+                  </ul>
+                </AppSection>
+              </SmartTab>
+
+              <SmartTab :id="'tests'" :label="$t('tests')">
+                <AppSection v-if="testsEnabled" label="postRequestTests">
+                  <ul>
+                    <li>
+                      <div class="flex flex-1">
+                        <label>{{ $t("javascript_code") }}</label>
+                        <div>
+                          <ButtonSecondary
+                            to="https://github.com/hoppscotch/hoppscotch/wiki/Post-Request-Tests"
+                            blank
+                            v-tippy="{ theme: 'tooltip' }"
+                            :title="$t('wiki')"
+                            icon="help_outline"
+                          />
+                        </div>
+                      </div>
+                      <SmartJsEditor
+                        v-model="testScript"
+                        :options="{
+                          maxLines: '16',
+                          minLines: '8',
+                          fontSize: '15px',
+                          autoScrollEditorIntoView: true,
+                          showPrintMargin: false,
+                          useWorker: false,
+                        }"
+                        styles="rounded-b-lg"
+                        completeMode="test"
+                      />
+                      <div v-if="testReports.length !== 0">
+                        <div class="flex flex-1">
+                          <label>Test Reports</label>
+                          <div>
+                            <ButtonSecondary
+                              @click.native="clearContent('tests', $event)"
+                              v-tippy="{ theme: 'tooltip' }"
+                              :title="$t('clear')"
+                              icon="clear_all"
+                            />
+                          </div>
+                        </div>
+                        <div
+                          v-for="(testReport, index) in testReports"
+                          :key="index"
+                        >
+                          <div v-if="testReport.startBlock">
+                            <hr />
+                            <h4 class="heading">
+                              {{ testReport.startBlock }}
+                            </h4>
+                          </div>
+                          <p
+                            v-else-if="testReport.result"
+                            class="flex flex-1 info"
+                          >
+                            <span :class="testReport.styles.class">
+                              <i class="material-icons">
+                                {{ testReport.styles.icon }}
+                              </i>
+                              <span>&nbsp; {{ testReport.result }}</span>
+                              <span v-if="testReport.message">
+                                <label
+                                  >&nbsp; • &nbsp;
+                                  {{ testReport.message }}</label
+                                >
+                              </span>
+                            </span>
+                          </p>
+                          <div v-else-if="testReport.endBlock"><hr /></div>
+                        </div>
+                      </div>
+                    </li>
+                  </ul>
+                </AppSection>
+              </SmartTab>
+            </SmartTabs>
+          </Pane>
+          <Pane class="overflow-auto">
+            <HttpResponse
+              :response="response"
+              :active="runningRequest"
+              ref="response"
+            />
+          </Pane>
+        </Splitpanes>
+      </Pane>
+      <Pane
+        max-size="30"
+        size="25"
+        min-size="20"
+        class="overflow-auto hide-scrollbar"
+      >
+        <aside class="h-full">
+          <SmartTabs styles="sticky z-10 top-0">
+            <SmartTab :id="'history'" :label="$t('history')" :selected="true">
+              <History
+                :page="'rest'"
+                @useHistory="handleUseHistory"
+                ref="historyComponent"
+              />
+            </SmartTab>
+
+            <SmartTab :id="'collections'" :label="$t('collections')">
+              <Collections />
+            </SmartTab>
+
+            <SmartTab :id="'env'" :label="$t('environments')">
+              <Environments />
+            </SmartTab>
+          </SmartTabs>
+        </aside>
+      </Pane>
+    </Splitpanes>
+
+    <CollectionsSaveRequest
+      mode="rest"
+      :show="showSaveRequestModal"
+      @hide-modal="hideRequestModal"
+      :editing-request="editRequest"
+    />
+
+    <HttpImportCurl
+      :show="showCurlImportModal"
+      @hide-modal="showCurlImportModal = false"
+      @handle-import="handleImport"
+    />
+
+    <HttpCodegenModal
+      :show="showCodegenModal"
+      :requestTypeProp="requestType"
+      :requestCode="requestCode"
+      @hide-modal="showCodegenModal = false"
+      @set-request-type="setRequestType"
+    />
+
+    <HttpTokenList
+      :show="showTokenListModal"
+      :tokens="tokens"
+      @clear-content="clearContent"
+      @use-oauth-token="useOAuthToken"
+      @remove-oauth-token="removeOAuthToken"
+      @hide-modal="showTokenListModal = false"
+    />
+
+    <SmartModal
+      v-if="showTokenRequestList"
+      @close="showTokenRequestList = false"
+    >
+      <template #header>
+        <h3 class="heading">{{ $t("manage_token_req") }}</h3>
+        <div>
+          <ButtonSecondary
+            @click.native="showTokenRequestList = false"
+            icon="close"
+          />
+        </div>
+      </template>
+      <template #body>
+        <div class="flex flex-1">
+          <label for="token-req-list">{{ $t("token_req_list") }}</label>
+          <div>
+            <ButtonSecondary
+              :disabled="this.tokenReqs.length === 0"
+              @click.native="showTokenRequestList = false"
+              v-tippy="{ theme: 'tooltip' }"
+              :title="$t('use_token_req')"
+              icon="input"
+            />
+            <ButtonSecondary
+              :disabled="this.tokenReqs.length === 0"
+              @click.native="removeOAuthTokenReq"
+              v-tippy="{ theme: 'tooltip' }"
+              :title="$t('delete')"
+              icon="delete"
+            />
+          </div>
+        </div>
+        <ul>
+          <li>
+            <span class="select-wrapper">
+              <select
+                id="token-req-list"
+                class="select"
+                v-model="tokenReqSelect"
+                :disabled="this.tokenReqs.length === 0"
+                @change="tokenReqChange($event)"
+              >
+                <option
+                  v-for="(req, index) in tokenReqs"
+                  :key="index"
+                  :value="req.name"
+                >
+                  {{ req.name }}
+                </option>
+              </select>
+            </span>
+          </li>
+        </ul>
+        <label for="token-req-name">{{ $t("token_req_name") }}</label>
+        <input class="input" v-model="tokenReqName" />
+        <label for="token-req-details">
+          {{ $t("token_req_details") }}
+        </label>
+        <textarea
+          id="token-req-details"
+          class="textarea"
+          readonly
+          rows="7"
+          v-model="tokenReqDetails"
+        ></textarea>
+      </template>
+      <template #footer>
+        <span></span>
+        <span>
+          <ButtonPrimary @click.native="addOAuthTokenReq" />
+          {{ $t("save_token_req") }}
+        </span>
+      </template>
+    </SmartModal>
+  </div>
+</template>
+
+<script>
+/* eslint-disable */
+import { Splitpanes, Pane } from "splitpanes"
+import "splitpanes/dist/splitpanes.css"
+
+import url from "url"
+import querystring from "querystring"
+import parseCurlCommand from "~/helpers/curlparser"
+import getEnvironmentVariablesFromScript from "~/helpers/preRequest"
+import runTestScriptWithVariables from "~/helpers/postwomanTesting"
+import parseTemplateString from "~/helpers/templating"
+import { tokenRequest, oauthRedirect } from "~/helpers/oauth"
+import { cancelRunningRequest, sendNetworkRequest } from "~/helpers/network"
+import {
+  hasPathParams,
+  addPathParamsToVariables,
+  getQueryParams,
+} from "~/helpers/requestParams"
+import { parseUrlAndPath } from "~/helpers/utils/uri"
+import { httpValid } from "~/helpers/utils/valid"
+import {
+  knownContentTypes,
+  isJSONContentType,
+} from "~/helpers/utils/contenttypes"
+import { generateCodeWithGenerator } from "~/helpers/codegen/codegen"
+import { getSettingSubject, applySetting } from "~/newstore/settings"
+import { addRESTHistoryEntry } from "~/newstore/history"
+import clone from "lodash/clone"
+
+export default {
+  components: { Splitpanes, Pane },
+
+  data() {
+    return {
+      showCurlImportModal: false,
+      showPreRequestScript: true,
+      testsEnabled: true,
+      testScript: "// pw.expect('variable').toBe('value');",
+      preRequestScript: "// pw.env.set('variable', 'value');",
+      testReports: [],
+      copyButton: '<i class="material-icons">content_copy</i>',
+      downloadButton: '<i class="material-icons">save_alt</i>',
+      doneButton: '<i class="material-icons">done</i>',
+      showCodegenModal: false,
+      response: {
+        status: "",
+        headers: "",
+        body: "",
+        duration: 0,
+        size: 0,
+      },
+      validContentTypes: knownContentTypes,
+      paramsWatchEnabled: true,
+      showTokenListModal: false,
+      showTokenRequest: false,
+      showTokenRequestList: false,
+      showSaveRequestModal: false,
+      editRequest: {},
+      customMethod: false,
+      files: [],
+      filenames: "",
+      navigatorShare: navigator.share,
+      runningRequest: false,
+      currentMethodIndex: 0,
+      methodMenuItems: [
+        "GET",
+        "HEAD",
+        "POST",
+        "PUT",
+        "DELETE",
+        "CONNECT",
+        "OPTIONS",
+        "TRACE",
+        "PATCH",
+        "CUSTOM",
+      ],
+    }
+  },
+  subscriptions() {
+    return {
+      SCROLL_INTO_ENABLED: getSettingSubject("SCROLL_INTO_ENABLED"),
+      PROXY_ENABLED: getSettingSubject("PROXY_ENABLED"),
+      URL_EXCLUDES: getSettingSubject("URL_EXCLUDES"),
+      EXPERIMENTAL_URL_BAR_ENABLED: getSettingSubject(
+        "EXPERIMENTAL_URL_BAR_ENABLED"
+      ),
+    }
+  },
+  watch: {
+    canListParameters: {
+      immediate: true,
+      handler(canListParameters) {
+        if (canListParameters) {
+          this.$nextTick(() => {
+            this.rawInput = Boolean(this.rawParams && this.rawParams !== "{}")
+          })
+        } else {
+          this.rawInput = true
+        }
+      },
+    },
+    contentType(contentType, oldContentType) {
+      const getDefaultParams = (contentType) => {
+        if (isJSONContentType(contentType)) return "{}"
+        switch (contentType) {
+          case "application/xml":
+            return "<?xml version='1.0' encoding='utf-8'?>"
+          case "text/html":
+            return "<!doctype html>"
+        }
+        return ""
+      }
+      if (
+        !this.rawParams ||
+        this.rawParams === getDefaultParams(oldContentType)
+      ) {
+        this.rawParams = getDefaultParams(contentType)
+      }
+      this.setRouteQueryState()
+    },
+    params: {
+      handler(newValue) {
+        if (!this.paramsWatchEnabled) {
+          this.paramsWatchEnabled = true
+          return
+        }
+        let path = this.path
+        let queryString = getQueryParams(newValue)
+          .map(({ key, value }) => `${key.trim()}=${value.trim()}`)
+          .join("&")
+        queryString = queryString === "" ? "" : `?${encodeURI(queryString)}`
+        if (path.includes("?")) {
+          path = path.slice(0, path.indexOf("?")) + queryString
+        } else {
+          path = path + queryString
+        }
+        this.path = path
+        this.setRouteQueryState()
+      },
+      deep: true,
+    },
+    selectedRequest(newValue) {
+      // @TODO: Convert all variables to single request variable
+      if (!newValue) return
+      this.uri = newValue.url + newValue.path
+      this.url = newValue.url
+      this.path = newValue.path
+      this.method = newValue.method
+      this.auth = newValue.auth
+      this.httpUser = newValue.httpUser
+      this.httpPassword = newValue.httpPassword
+      this.passwordFieldType = newValue.passwordFieldType
+      this.bearerToken = newValue.bearerToken
+      this.headers = newValue.headers
+      this.params = newValue.params
+      this.bodyParams = newValue.bodyParams
+      this.rawParams = newValue.rawParams
+      this.rawInput = newValue.rawInput
+      this.contentType = newValue.contentType
+      this.requestType = newValue.requestType
+      if (newValue.preRequestScript) {
+        this.showPreRequestScript = true
+        this.preRequestScript = newValue.preRequestScript
+      }
+      if (newValue.testScript) {
+        this.testsEnabled = true
+        this.testScript = newValue.testScript
+      }
+      this.name = newValue.name
+    },
+    method() {
+      this.contentType = ["POST", "PUT", "PATCH", "DELETE"].includes(
+        this.method
+      )
+        ? this.contentType
+        : "application/json"
+    },
+    preRequestScript(val, oldVal) {
+      this.uri = this.uri
+    },
+  },
+  computed: {
+    /**
+     * Check content types that can be automatically
+     * serialized by postwoman.
+     */
+    canListParameters() {
+      return (
+        this.contentType === "application/x-www-form-urlencoded" ||
+        this.contentType === "multipart/form-data" ||
+        isJSONContentType(this.contentType)
+      )
+    },
+    uri: {
+      get() {
+        return this.$store.state.request.uri
+          ? this.$store.state.request.uri
+          : this.url + this.path
+      },
+      set(value) {
+        this.$store.commit("setState", { value, attribute: "uri" })
+        let url = value
+        if (
+          (this.preRequestScript && this.showPreRequestScript) ||
+          hasPathParams(this.params)
+        ) {
+          let environmentVariables = getEnvironmentVariablesFromScript(
+            this.preRequestScript
+          )
+          environmentVariables = addPathParamsToVariables(
+            this.params,
+            environmentVariables
+          )
+          url = parseTemplateString(value, environmentVariables)
+        }
+        let result = parseUrlAndPath(url)
+        this.url = result.url
+        this.path = result.path
+      },
+    },
+    url: {
+      get() {
+        return this.$store.state.request.url
+      },
+      set(value) {
+        this.$store.commit("setState", { value, attribute: "url" })
+      },
+    },
+    method: {
+      get() {
+        return this.$store.state.request.method
+      },
+      set(value) {
+        this.$store.commit("setState", { value, attribute: "method" })
+      },
+    },
+    path: {
+      get() {
+        return this.$store.state.request.path
+      },
+      set(value) {
+        this.$store.commit("setState", { value, attribute: "path" })
+      },
+    },
+    name: {
+      get() {
+        return this.$store.state.request.name
+      },
+      set(value) {
+        this.$store.commit("setState", { value, attribute: "name" })
+      },
+    },
+    auth: {
+      get() {
+        return this.$store.state.request.auth
+      },
+      set(value) {
+        this.$store.commit("setState", { value, attribute: "auth" })
+      },
+    },
+    httpUser: {
+      get() {
+        return this.$store.state.request.httpUser
+      },
+      set(value) {
+        this.$store.commit("setState", { value, attribute: "httpUser" })
+      },
+    },
+    httpPassword: {
+      get() {
+        return this.$store.state.request.httpPassword
+      },
+      set(value) {
+        this.$store.commit("setState", { value, attribute: "httpPassword" })
+      },
+    },
+    bearerToken: {
+      get() {
+        return this.$store.state.request.bearerToken
+      },
+      set(value) {
+        this.$store.commit("setState", { value, attribute: "bearerToken" })
+      },
+    },
+    tokens: {
+      get() {
+        return this.$store.state.oauth2.tokens
+      },
+      set(value) {
+        this.$store.commit("setOAuth2", { value, attribute: "tokens" })
+      },
+    },
+    tokenReqs: {
+      get() {
+        return this.$store.state.oauth2.tokenReqs
+      },
+      set(value) {
+        this.$store.commit("setOAuth2", { value, attribute: "tokenReqs" })
+      },
+    },
+    tokenReqSelect: {
+      get() {
+        return this.$store.state.oauth2.tokenReqSelect
+      },
+      set(value) {
+        this.$store.commit("setOAuth2", { value, attribute: "tokenReqSelect" })
+      },
+    },
+    tokenReqName: {
+      get() {
+        return this.$store.state.oauth2.tokenReqName
+      },
+      set(value) {
+        this.$store.commit("setOAuth2", { value, attribute: "tokenReqName" })
+      },
+    },
+    accessTokenName: {
+      get() {
+        return this.$store.state.oauth2.accessTokenName
+      },
+      set(value) {
+        this.$store.commit("setOAuth2", {
+          value,
+          attribute: "accessTokenName",
+        })
+      },
+    },
+    oidcDiscoveryUrl: {
+      get() {
+        return this.$store.state.oauth2.oidcDiscoveryUrl
+      },
+      set(value) {
+        this.$store.commit("setOAuth2", {
+          value,
+          attribute: "oidcDiscoveryUrl",
+        })
+      },
+    },
+    authUrl: {
+      get() {
+        return this.$store.state.oauth2.authUrl
+      },
+      set(value) {
+        this.$store.commit("setOAuth2", { value, attribute: "authUrl" })
+      },
+    },
+    accessTokenUrl: {
+      get() {
+        return this.$store.state.oauth2.accessTokenUrl
+      },
+      set(value) {
+        this.$store.commit("setOAuth2", { value, attribute: "accessTokenUrl" })
+      },
+    },
+    clientId: {
+      get() {
+        return this.$store.state.oauth2.clientId
+      },
+      set(value) {
+        this.$store.commit("setOAuth2", { value, attribute: "clientId" })
+      },
+    },
+    scope: {
+      get() {
+        return this.$store.state.oauth2.scope
+      },
+      set(value) {
+        this.$store.commit("setOAuth2", { value, attribute: "scope" })
+      },
+    },
+    state: {
+      get() {
+        return this.$store.state.oauth2.state
+      },
+      set(value) {
+        this.$store.commit("setOAuth2", { value, attribute: "state" })
+      },
+    },
+    headers: {
+      get() {
+        return this.$store.state.request.headers
+      },
+      set(value) {
+        this.$store.commit("setState", { value, attribute: "headers" })
+      },
+    },
+    params: {
+      get() {
+        return this.$store.state.request.params
+      },
+      set(value) {
+        this.$store.commit("setState", { value, attribute: "params" })
+      },
+    },
+    bodyParams: {
+      get() {
+        return this.$store.state.request.bodyParams
+      },
+      set(value) {
+        this.$store.commit("setState", { value, attribute: "bodyParams" })
+      },
+    },
+    rawParams: {
+      get() {
+        return this.$store.state.request.rawParams
+      },
+      set(value) {
+        this.$store.commit("setState", { value, attribute: "rawParams" })
+        // Convert the rawParams to bodyParams format
+        try {
+          const valueObj = JSON.parse(value)
+          const params = Object.keys(valueObj).map((key) => {
+            if (typeof valueObj[key] !== "function") {
+              return {
+                active: true,
+                key,
+                value: valueObj[key],
+              }
+            }
+          })
+          this.$store.commit("setBodyParams", { params })
+        } catch {}
+      },
+    },
+    rawInput: {
+      get() {
+        return this.$store.state.request.rawInput
+      },
+      set(value) {
+        this.$store.commit("setState", { value, attribute: "rawInput" })
+      },
+    },
+    requestType: {
+      get() {
+        return this.$store.state.request.requestType
+      },
+      set(value) {
+        this.$store.commit("setState", { value, attribute: "requestType" })
+      },
+    },
+    contentType: {
+      get() {
+        return this.$store.state.request.contentType
+      },
+      set(value) {
+        this.$store.commit("setState", { value, attribute: "contentType" })
+      },
+    },
+    passwordFieldType: {
+      get() {
+        return this.$store.state.request.passwordFieldType
+      },
+      set(value) {
+        this.$store.commit("setState", {
+          value,
+          attribute: "passwordFieldType",
+        })
+      },
+    },
+    selectedRequest() {
+      return this.$store.state.postwoman.selectedRequest
+    },
+    requestName() {
+      return this.name
+    },
+    isValidURL() {
+      // if showPreRequestScript, we cannot determine if a URL is valid because the full string is not known ahead of time
+      return this.showPreRequestScript || httpValid(this.url)
+    },
+    hasRequestBody() {
+      return ["POST", "PUT", "PATCH", "DELETE"].includes(this.method)
+    },
+    pathName() {
+      return this.path.match(/^([^?]*)\??/)[1]
+    },
+    rawRequestBody() {
+      const { bodyParams, contentType } = this
+      if (isJSONContentType(contentType)) {
+        try {
+          const obj = JSON.parse(
+            `{${bodyParams
+              .filter((item) =>
+                item.hasOwnProperty("active") ? item.active == true : true
+              )
+              .filter(({ key }) => !!key)
+              .map(({ key, value }) => `"${key}": "${value}"`)
+              .join()}}`
+          )
+          return JSON.stringify(obj, null, 2)
+        } catch (ex) {
+          console.log(ex)
+          this.$toast.clear()
+          this.$toast.error(
+            "Parameter value must be a string, switch to Raw input for other formats",
+            {
+              icon: "error",
+            }
+          )
+          return "invalid"
+        }
+      } else {
+        return bodyParams
+          .filter((item) =>
+            item.hasOwnProperty("active") ? item.active == true : true
+          )
+          .filter(({ key }) => !!key)
+          .map(
+            ({ key, value }) =>
+              `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
+          )
+          .join("&")
+      }
+    },
+    queryString() {
+      const result = getQueryParams(this.params)
+        .map(
+          ({ key, value }) =>
+            `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
+        )
+        .join("&")
+      return result === "" ? "" : `?${result}`
+    },
+    requestCode() {
+      let headers = []
+      if (this.preRequestScript || hasPathParams(this.params)) {
+        let environmentVariables = getEnvironmentVariablesFromScript(
+          this.preRequestScript
+        )
+        environmentVariables = addPathParamsToVariables(
+          this.params,
+          environmentVariables
+        )
+        for (let k of this.headers.filter((item) =>
+          item.hasOwnProperty("active") ? item.active == true : true
+        )) {
+          const kParsed = parseTemplateString(k.key, environmentVariables)
+          const valParsed = parseTemplateString(k.value, environmentVariables)
+          headers.push({ key: kParsed, value: valParsed })
+        }
+      }
+
+      return generateCodeWithGenerator(this.requestType, {
+        auth: this.auth,
+        method: this.method,
+        url: this.url,
+        pathName: this.pathName,
+        queryString: this.queryString,
+        httpUser: this.httpUser,
+        httpPassword: this.httpPassword,
+        bearerToken: this.bearerToken,
+        headers,
+        rawInput: this.rawInput,
+        rawParams: this.rawParams,
+        rawRequestBody: this.rawRequestBody,
+        contentType: this.contentType,
+      })
+    },
+    tokenReqDetails() {
+      const details = {
+        oidcDiscoveryUrl: this.oidcDiscoveryUrl,
+        authUrl: this.authUrl,
+        accessTokenUrl: this.accessTokenUrl,
+        clientId: this.clientId,
+        scope: this.scope,
+      }
+      return JSON.stringify(details, null, 2)
+    },
+  },
+  methods: {
+    scrollInto(view) {
+      this.$refs[view].$el.scrollIntoView({
+        behavior: "smooth",
+      })
+    },
+    handleUseHistory(entry) {
+      this.name = entry.name
+      this.method = entry.method
+      this.uri = entry.url + entry.path
+      this.url = entry.url
+      this.path = entry.path
+      this.showPreRequestScript = entry.usesPreScripts
+      this.preRequestScript = entry.preRequestScript
+      this.auth = entry.auth
+      this.httpUser = entry.httpUser
+      this.httpPassword = entry.httpPassword
+      this.bearerToken = entry.bearerToken
+      this.headers = entry.headers
+      this.params = entry.params
+      this.bodyParams = entry.bodyParams
+      this.rawParams = entry.rawParams
+      this.rawInput = entry.rawInput
+      this.contentType = entry.contentType
+      this.requestType = entry.requestType
+      this.testScript = entry.testScript
+      this.testsEnabled = entry.usesPostScripts
+      if (this.SCROLL_INTO_ENABLED) this.scrollInto("request")
+    },
+    async makeRequest(auth, headers, requestBody, preRequestScript) {
+      const requestOptions = {
+        method: this.method,
+        url: this.url + this.pathName + this.queryString,
+        auth,
+        headers,
+        data: requestBody,
+        credentials: true,
+      }
+
+      if (preRequestScript || hasPathParams(this.params)) {
+        let environmentVariables =
+          getEnvironmentVariablesFromScript(preRequestScript)
+        environmentVariables = addPathParamsToVariables(
+          this.params,
+          environmentVariables
+        )
+        requestOptions.url = parseTemplateString(
+          requestOptions.url,
+          environmentVariables
+        )
+        if (!(requestOptions.data instanceof FormData)) {
+          // TODO: Parse env variables for form data too
+          requestOptions.data = parseTemplateString(
+            requestOptions.data,
+            environmentVariables
+          )
+        }
+        for (let k in requestOptions.headers) {
+          const kParsed = parseTemplateString(k, environmentVariables)
+          const valParsed = parseTemplateString(
+            requestOptions.headers[k],
+            environmentVariables
+          )
+          delete requestOptions.headers[k]
+          requestOptions.headers[kParsed] = valParsed
+        }
+      }
+      if (typeof requestOptions.data === "string") {
+        requestOptions.data = parseTemplateString(requestOptions.data)
+      }
+      return await sendNetworkRequest(requestOptions)
+    },
+    cancelRequest() {
+      cancelRunningRequest()
+    },
+    async sendRequest() {
+      this.$toast.clear()
+      if (this.SCROLL_INTO_ENABLED) this.scrollInto("response")
+      if (!this.isValidURL) {
+        this.$toast.error(this.$t("url_invalid_format"), {
+          icon: "error",
+        })
+        return
+      }
+      // Start showing the loading bar as soon as possible.
+      // The nuxt axios module will hide it when the request is made.
+      this.$nuxt.$loading.start()
+      this.response = {
+        duration: 0,
+        size: 0,
+        status: this.$t("fetching"),
+        body: this.$t("loading"),
+      }
+      const auth =
+        this.auth === "Basic Auth"
+          ? {
+              username: this.httpUser,
+              password: this.httpPassword,
+            }
+          : null
+      let headers = {}
+      let headersObject = {}
+      Object.keys(headers).forEach((id) => {
+        if (headers[id].key) headersObject[headers[id].key] = headers[id].value
+      })
+      headers = headersObject
+      // If the request has a body, we want to ensure Content-Type is sent.
+      let requestBody
+      if (this.hasRequestBody) {
+        requestBody = this.rawInput ? this.rawParams : this.rawRequestBody
+        Object.assign(headers, {
+          "Content-Type": `${this.contentType}; charset=utf-8`,
+        })
+      }
+      requestBody = requestBody ? requestBody.toString() : null
+      if (this.contentType === "multipart/form-data") {
+        const formData = new FormData()
+        for (const bodyParam of this.bodyParams.filter((item) =>
+          item.hasOwnProperty("active") ? item.active == true : true
+        )) {
+          if (bodyParam?.value?.[0] instanceof File) {
+            for (const file of bodyParam.value) {
+              formData.append(bodyParam.key, file)
+            }
+          } else {
+            formData.append(bodyParam.key, bodyParam.value)
+          }
+        }
+        requestBody = formData
+      }
+      // If the request uses a token for auth, we want to make sure it's sent here.
+      if (this.auth === "Bearer Token" || this.auth === "OAuth 2.0")
+        headers["Authorization"] = `Bearer ${this.bearerToken}`
+      headers = Object.assign(
+        // Clone the app headers object first, we don't want to
+        // mutate it with the request headers added by default.
+        Object.assign(
+          {},
+          this.headers.filter((item) =>
+            item.hasOwnProperty("active") ? item.active == true : true
+          )
+        )
+        // We make our temporary headers object the source so
+        // that you can override the added headers if you
+        // specify them.
+        // headers
+      )
+      Object.keys(headers).forEach((id) => {
+        if (headers[id].key) headersObject[headers[id].key] = headers[id].value
+      })
+      headers = headersObject
+      const startTime = new Date().getTime()
+      try {
+        this.runningRequest = true
+        const payload = await this.makeRequest(
+          auth,
+          headers,
+          requestBody,
+          this.showPreRequestScript && this.preRequestScript
+        )
+        this.runningRequest = false
+        const duration = new Date().getTime() - startTime
+        this.response.duration = duration
+        this.response.size = payload.headers["content-length"]
+        ;(() => {
+          this.response.status = payload.status
+          this.response.headers = payload.headers
+          // We don't need to bother parsing JSON, axios already handles it for us!
+          this.response.body = payload.data
+          // Addition of an entry to the history component.
+          const entry = {
+            name: this.requestName,
+            status: this.response.status,
+            date: new Date().toLocaleDateString(),
+            time: new Date().toLocaleTimeString(),
+            updatedOn: new Date(),
+            method: this.method,
+            url: this.url,
+            path: this.path,
+            usesPreScripts: this.showPreRequestScript,
+            preRequestScript: this.preRequestScript,
+            duration,
+            star: false,
+            auth: this.auth,
+            httpUser: this.httpUser,
+            httpPassword: this.httpPassword,
+            bearerToken: this.bearerToken,
+            headers: this.headers,
+            params: this.params,
+            bodyParams: this.bodyParams,
+            rawParams: this.rawParams,
+            rawInput: this.rawInput,
+            contentType: this.contentType,
+            requestType: this.requestType,
+            testScript: this.testScript,
+            usesPostScripts: this.testsEnabled,
+          }
+
+          if (
+            (this.preRequestScript && this.showPreRequestScript) ||
+            hasPathParams(this.params)
+          ) {
+            let environmentVariables = getEnvironmentVariablesFromScript(
+              this.preRequestScript
+            )
+            environmentVariables = addPathParamsToVariables(
+              this.params,
+              environmentVariables
+            )
+            entry.path = parseTemplateString(entry.path, environmentVariables)
+            entry.url = parseTemplateString(entry.url, environmentVariables)
+          }
+
+          addRESTHistoryEntry(entry)
+        })()
+      } catch (error) {
+        this.runningRequest = false
+        // If the error is caused by cancellation, do nothing
+        if (error === "cancellation") {
+          this.response.status = this.$t("cancelled")
+          this.response.body = this.$t("cancelled")
+        } else {
+          console.log(error)
+          const duration = new Date().getTime() - startTime
+          this.response.duration = duration
+          this.response.size = Buffer.byteLength(JSON.stringify(error))
+          if (error.response) {
+            this.response.headers = error.response.headers
+            this.response.status = error.response.status
+            this.response.body = error.response.data
+            // Addition of an entry to the history component.
+            const entry = {
+              name: this.requestName,
+              status: this.response.status,
+              date: new Date().toLocaleDateString(),
+              time: new Date().toLocaleTimeString(),
+              updatedOn: new Date(),
+              method: this.method,
+              url: this.url,
+              path: this.path,
+              usesPreScripts: this.showPreRequestScript,
+              preRequestScript: this.preRequestScript,
+              star: false,
+              auth: this.auth,
+              httpUser: this.httpUser,
+              httpPassword: this.httpPassword,
+              bearerToken: this.bearerToken,
+              headers: this.headers,
+              params: this.params,
+              bodyParams: this.bodyParams,
+              rawParams: this.rawParams,
+              rawInput: this.rawInput,
+              contentType: this.contentType,
+              requestType: this.requestType,
+              testScript: this.testScript,
+              usesPostScripts: this.testsEnabled,
+            }
+
+            if (
+              (this.preRequestScript && this.showPreRequestScript) ||
+              hasPathParams(this.params)
+            ) {
+              let environmentVariables = getEnvironmentVariablesFromScript(
+                this.preRequestScript
+              )
+              environmentVariables = addPathParamsToVariables(
+                this.params,
+                environmentVariables
+              )
+              entry.path = parseTemplateString(entry.path, environmentVariables)
+              entry.url = parseTemplateString(entry.url, environmentVariables)
+            }
+
+            addRESTHistoryEntry(entry)
+            return
+          } else {
+            this.response.status = error.message
+            this.response.body = `${error}. ${this.$t("check_console_details")}`
+            this.$toast.error(`${error} ${this.$t("f12_details")}`, {
+              icon: "error",
+            })
+            if (!this.PROXY_ENABLED) {
+              this.$toast.info(this.$t("enable_proxy"), {
+                icon: "help",
+                duration: 8000,
+                action: {
+                  text: this.$t("yes"),
+                  onClick: (e, toastObject) => {
+                    this.$router.push({ path: "/settings" })
+                  },
+                },
+              })
+            }
+          }
+        }
+      }
+      // tests
+      const syntheticResponse = {
+        status: this.response.status,
+        body: this.response.body,
+        headers: this.response.headers,
+      }
+
+      // Parse JSON body
+      if (
+        syntheticResponse.headers["content-type"] &&
+        isJSONContentType(syntheticResponse.headers["content-type"])
+      ) {
+        try {
+          syntheticResponse.body = JSON.parse(
+            new TextDecoder("utf-8").decode(
+              new Uint8Array(syntheticResponse.body)
+            )
+          )
+        } catch (_e) {}
+      }
+
+      const { testResults } = runTestScriptWithVariables(this.testScript, {
+        response: syntheticResponse,
+      })
+      this.testReports = testResults
+    },
+    getQueryStringFromPath() {
+      const pathParsed = url.parse(this.uri)
+      return pathParsed.query ? pathParsed.query : ""
+    },
+    queryStringToArray(queryString) {
+      const queryParsed = querystring.parse(queryString)
+      return Object.keys(queryParsed).map((key) => ({
+        key,
+        value: queryParsed[key],
+        active: true,
+      }))
+    },
+    pathInputHandler() {
+      if (this.uri.includes("?")) {
+        const queryString = this.getQueryStringFromPath()
+        let environmentVariables = getEnvironmentVariablesFromScript(
+          this.preRequestScript
+        )
+        environmentVariables = addPathParamsToVariables(
+          this.params,
+          environmentVariables
+        )
+        const params = this.queryStringToArray(queryString)
+        let parsedParams = []
+        for (let k of params.filter((item) =>
+          item.hasOwnProperty("active") ? item.active == true : true
+        )) {
+          const kParsed = parseTemplateString(k.key, environmentVariables)
+          const valParsed = parseTemplateString(k.value, environmentVariables)
+          parsedParams.push({ key: kParsed, value: valParsed, active: true })
+        }
+        this.paramsWatchEnabled = false
+        this.params = parsedParams
+      }
+    },
+    addRequestHeader() {
+      this.$store.commit("addHeaders", {
+        key: "",
+        value: "",
+        active: true,
+      })
+      return false
+    },
+    removeRequestHeader(index) {
+      // .slice() gives us an entirely new array rather than giving us just the reference
+      const oldHeaders = this.headers.slice()
+      this.$store.commit("removeHeaders", index)
+      this.$toast.error(this.$t("deleted"), {
+        icon: "delete",
+        action: {
+          text: this.$t("undo"),
+          onClick: (e, toastObject) => {
+            this.headers = oldHeaders
+            toastObject.remove()
+          },
+        },
+      })
+    },
+    addRequestParam() {
+      this.$store.commit("addParams", {
+        key: "",
+        value: "",
+        type: "query",
+        active: true,
+      })
+      return false
+    },
+    removeRequestParam(index) {
+      // .slice() gives us an entirely new array rather than giving us just the reference
+      const oldParams = this.params.slice()
+      this.$store.commit("removeParams", index)
+      this.$toast.error(this.$t("deleted"), {
+        icon: "delete",
+        action: {
+          text: this.$t("undo"),
+          onClick: (e, toastObject) => {
+            this.params = oldParams
+            toastObject.remove()
+          },
+        },
+      })
+    },
+    addRequestBodyParam() {
+      this.$store.commit("addBodyParams", { key: "", value: "", active: true })
+      return false
+    },
+    removeRequestBodyParam(index) {
+      // .slice() gives us an entirely new array rather than giving us just the reference
+      const oldBodyParams = this.bodyParams.slice()
+      this.$store.commit("removeBodyParams", index)
+      this.$toast.error(this.$t("deleted"), {
+        icon: "delete",
+        action: {
+          text: this.$t("undo"),
+          onClick: (e, toastObject) => {
+            this.bodyParams = oldBodyParams
+            toastObject.remove()
+          },
+        },
+      })
+    },
+    copyRequest() {
+      if (navigator.share) {
+        const time = new Date().toLocaleTimeString()
+        const date = new Date().toLocaleDateString()
+        navigator
+          .share({
+            title: "Hoppscotch",
+            text: `Hoppscotch • Open source API development ecosystem at ${time} on ${date}`,
+            url: window.location.href,
+          })
+          .then(() => {})
+          .catch(() => {})
+      } else {
+        const dummy = document.createElement("input")
+        document.body.appendChild(dummy)
+        dummy.value = window.location.href
+        dummy.select()
+        document.execCommand("copy")
+        document.body.removeChild(dummy)
+        this.$refs.copyRequest.innerHTML = this.doneButton
+        this.$toast.info(this.$t("copied_to_clipboard"), {
+          icon: "done",
+        })
+        setTimeout(
+          () => (this.$refs.copyRequest.innerHTML = this.copyButton),
+          1000
+        )
+      }
+    },
+    setRouteQueryState() {
+      const flat = (key) => (this[key] !== "" ? `${key}=${this[key]}&` : "")
+      const deep = (key) => {
+        const haveItems = [...this[key]].length
+        if (haveItems && this[key]["value"] !== "") {
+          // Exclude files fro  query params
+          const filesRemoved = this[key].filter(
+            (item) => !(item?.value?.[0] instanceof File)
+          )
+          return `${key}=${JSON.stringify(filesRemoved)}&`
+        }
+        return ""
+      }
+      let flats = [
+        "method",
+        "url",
+        "path",
+        !this.URL_EXCLUDES.auth ? "auth" : null,
+        !this.URL_EXCLUDES.httpUser ? "httpUser" : null,
+        !this.URL_EXCLUDES.httpPassword ? "httpPassword" : null,
+        !this.URL_EXCLUDES.bearerToken ? "bearerToken" : null,
+        "contentType",
+      ]
+        .filter((item) => item !== null)
+        .map((item) => flat(item))
+      const deeps = ["headers", "params"].map((item) => deep(item))
+      const bodyParams = this.rawInput
+        ? [flat("rawParams")]
+        : [deep("bodyParams")]
+      history.replaceState(
+        window.location.href,
+        "",
+        `${this.$router.options.base}?${encodeURI(
+          flats.concat(deeps, bodyParams).join("").slice(0, -1)
+        )}`
+      )
+    },
+    setRouteQueries(queries) {
+      if (typeof queries !== "object")
+        throw new Error("Route query parameters must be a Object")
+      for (const key in queries) {
+        if (["headers", "params", "bodyParams"].includes(key))
+          this[key] = JSON.parse(decodeURI(encodeURI(queries[key])))
+        if (key === "rawParams") {
+          this.rawInput = true
+          this.rawParams = queries["rawParams"]
+        } else if (typeof this[key] === "string") {
+          this[key] = queries[key]
+        }
+      }
+    },
+    handleImport() {
+      const { value: text } = document.getElementById("import-curl")
+      try {
+        const parsedCurl = parseCurlCommand(text)
+        const { origin, pathname } = new URL(
+          parsedCurl.url.replace(/"/g, "").replace(/'/g, "")
+        )
+        this.url = origin
+        this.path = pathname
+        this.uri = this.url + this.path
+        this.headers = []
+        if (parsedCurl.query) {
+          for (const key of Object.keys(parsedCurl.query)) {
+            this.$store.commit("addParams", {
+              key,
+              value: parsedCurl.query[key],
+              type: "query",
+              active: true,
+            })
+          }
+        }
+        if (parsedCurl.headers) {
+          for (const key of Object.keys(parsedCurl.headers)) {
+            this.$store.commit("addHeaders", {
+              key,
+              value: parsedCurl.headers[key],
+            })
+          }
+        }
+        this.method = parsedCurl.method.toUpperCase()
+        if (parsedCurl["data"]) {
+          this.rawInput = true
+          this.rawParams = parsedCurl["data"]
+        }
+        this.showCurlImportModal = false
+      } catch (error) {
+        this.showCurlImportModal = false
+        this.$toast.error(this.$t("curl_invalid_format"), {
+          icon: "error",
+        })
+      }
+    },
+    switchVisibility() {
+      this.passwordFieldType =
+        this.passwordFieldType === "password" ? "text" : "password"
+    },
+    clearContent(name, { target }) {
+      switch (name) {
+        case "bodyParams":
+          this.bodyParams = []
+          this.files = []
+          break
+        case "rawParams":
+          this.rawParams = "{}"
+          break
+        case "parameters":
+          this.params = []
+          break
+        case "auth":
+          this.auth = "None"
+          this.httpUser = ""
+          this.httpPassword = ""
+          this.bearerToken = ""
+          this.showTokenRequest = false
+          this.tokens = []
+          this.tokenReqs = []
+          break
+        case "access_token":
+          this.accessTokenName = ""
+          this.oidcDiscoveryUrl = ""
+          this.authUrl = ""
+          this.accessTokenUrl = ""
+          this.clientId = ""
+          this.scope = ""
+          break
+        case "headers":
+          this.headers = []
+          break
+        case "tests":
+          this.testReports = []
+          break
+        case "tokens":
+          this.tokens = []
+          break
+        default:
+          this.method = "GET"
+          this.url = "https://httpbin.org"
+          this.path = "/get"
+          this.uri = this.url + this.path
+          this.name = "Untitled request"
+          this.bodyParams = []
+          this.rawParams = "{}"
+          this.files = []
+          this.params = []
+          this.auth = "None"
+          this.httpUser = ""
+          this.httpPassword = ""
+          this.bearerToken = ""
+          this.showTokenRequest = false
+          this.tokens = []
+          this.tokenReqs = []
+          this.accessTokenName = ""
+          this.oidcDiscoveryUrl = ""
+          this.authUrl = ""
+          this.accessTokenUrl = ""
+          this.clientId = ""
+          this.scope = ""
+          this.headers = []
+          this.testReports = []
+      }
+      target.innerHTML = this.doneButton
+      this.$toast.info(this.$t("cleared"), {
+        icon: "clear_all",
+      })
+      setTimeout(
+        () => (target.innerHTML = '<i class="material-icons">clear_all</i>'),
+        1000
+      )
+    },
+    saveRequest() {
+      let urlAndPath = parseUrlAndPath(this.uri)
+      this.editRequest = {
+        url: decodeURI(urlAndPath.url),
+        path: decodeURI(urlAndPath.path),
+        method: this.method,
+        auth: this.auth,
+        httpUser: this.httpUser,
+        httpPassword: this.httpPassword,
+        passwordFieldType: this.passwordFieldType,
+        bearerToken: this.bearerToken,
+        headers: this.headers,
+        params: this.params,
+        bodyParams: this.bodyParams,
+        rawParams: this.rawParams,
+        rawInput: this.rawInput,
+        contentType: this.contentType,
+        requestType: this.requestType,
+        preRequestScript:
+          this.showPreRequestScript == true ? this.preRequestScript : null,
+        testScript: this.testsEnabled == true ? this.testScript : null,
+        name: this.requestName,
+      }
+      this.showSaveRequestModal = true
+    },
+    hideRequestModal() {
+      this.showSaveRequestModal = false
+      this.editRequest = {}
+    },
+    setExclude(excludedField, excluded) {
+      const update = clone(this.URL_EXCLUDES)
+
+      if (excludedField === "auth") {
+        update.auth = excluded
+        update.httpUser = excluded
+        update.httpPassword = excluded
+        update.bearerToken = excluded
+      } else {
+        update[excludedField] = excluded
+      }
+
+      applySetting("URL_EXCLUDES", update)
+
+      this.setRouteQueryState()
+    },
+    updateRawBody(rawParams) {
+      this.rawParams = rawParams
+    },
+    async handleAccessTokenRequest() {
+      if (
+        this.oidcDiscoveryUrl === "" &&
+        (this.authUrl === "" || this.accessTokenUrl === "")
+      ) {
+        this.$toast.error(this.$t("complete_config_urls"), {
+          icon: "error",
+        })
+        return
+      }
+      try {
+        const tokenReqParams = {
+          grantType: "code",
+          oidcDiscoveryUrl: this.oidcDiscoveryUrl,
+          authUrl: this.authUrl,
+          accessTokenUrl: this.accessTokenUrl,
+          clientId: this.clientId,
+          scope: this.scope,
+        }
+        await tokenRequest(tokenReqParams)
+      } catch (e) {
+        this.$toast.error(e, {
+          icon: "code",
+        })
+      }
+    },
+    async oauthRedirectReq() {
+      const tokenInfo = await oauthRedirect()
+      if (Object.prototype.hasOwnProperty.call(tokenInfo, "access_token")) {
+        this.bearerToken = tokenInfo.access_token
+        this.addOAuthToken({
+          name: this.accessTokenName,
+          value: tokenInfo.access_token,
+        })
+      }
+    },
+    addOAuthToken({ name, value }) {
+      this.$store.commit("addOAuthToken", {
+        name,
+        value,
+      })
+      return false
+    },
+    removeOAuthToken(index) {
+      const oldTokens = this.tokens.slice()
+      this.$store.commit("removeOAuthToken", index)
+      this.$toast.error(this.$t("deleted"), {
+        icon: "delete",
+        action: {
+          text: this.$t("undo"),
+          onClick: (e, toastObject) => {
+            this.tokens = oldTokens
+            toastObject.remove()
+          },
+        },
+      })
+    },
+    useOAuthToken(value) {
+      this.bearerToken = value
+      this.showTokenListModal = false
+    },
+    addOAuthTokenReq() {
+      try {
+        const name = this.tokenReqName
+        const details = JSON.parse(this.tokenReqDetails)
+        this.$store.commit("addOAuthTokenReq", {
+          name,
+          details,
+        })
+        this.$toast.info(this.$t("token_request_saved"))
+        this.showTokenRequestList = false
+      } catch (e) {
+        this.$toast.error(e, {
+          icon: "code",
+        })
+      }
+    },
+    removeOAuthTokenReq(index) {
+      const oldTokenReqs = this.tokenReqs.slice()
+      const targetReqIndex = this.tokenReqs.findIndex(
+        ({ name }) => name === this.tokenReqName
+      )
+      if (targetReqIndex < 0) return
+      this.$store.commit("removeOAuthTokenReq", targetReqIndex)
+      this.$toast.error(this.$t("deleted"), {
+        icon: "delete",
+        action: {
+          text: this.$t("undo"),
+          onClick: (e, toastObject) => {
+            this.tokenReqs = oldTokenReqs
+            toastObject.remove()
+          },
+        },
+      })
+    },
+    tokenReqChange({ target }) {
+      const { details, name } = this.tokenReqs.find(
+        ({ name }) => name === target.value
+      )
+      const { oidcDiscoveryUrl, authUrl, accessTokenUrl, clientId, scope } =
+        details
+      this.tokenReqName = name
+      this.oidcDiscoveryUrl = oidcDiscoveryUrl
+      this.authUrl = authUrl
+      this.accessTokenUrl = accessTokenUrl
+      this.clientId = clientId
+      this.scope = scope
+    },
+    setRequestType(val) {
+      this.requestType = val
+    },
+  },
+  async mounted() {
+    this._keyListener = function (e) {
+      if (e.key === "g" && (e.ctrlKey || e.metaKey)) {
+        e.preventDefault()
+        if (!this.runningRequest) {
+          this.sendRequest()
+        } else {
+          this.cancelRequest()
+        }
+      }
+      if (e.key === "s" && (e.ctrlKey || e.metaKey)) {
+        e.preventDefault()
+        this.saveRequest()
+      }
+      if (e.key === "k" && (e.ctrlKey || e.metaKey)) {
+        e.preventDefault()
+        this.copyRequest()
+      }
+      if (e.key === "i" && (e.ctrlKey || e.metaKey)) {
+        e.preventDefault()
+        this.$refs.clearAll.click()
+      }
+      if ((e.key === "g" || e.key === "G") && e.altKey) {
+        this.method = "GET"
+      }
+      if ((e.key === "h" || e.key === "H") && e.altKey) {
+        this.method = "HEAD"
+      }
+      if ((e.key === "p" || e.key === "P") && e.altKey) {
+        this.method = "POST"
+      }
+      if ((e.key === "u" || e.key === "U") && e.altKey) {
+        this.method = "PUT"
+      }
+      if ((e.key === "x" || e.key === "X") && e.altKey) {
+        this.method = "DELETE"
+      }
+      if (e.key == "ArrowUp" && e.altKey && this.currentMethodIndex > 0) {
+        this.method =
+          this.methodMenuItems[
+            --this.currentMethodIndex % this.methodMenuItems.length
+          ]
+      } else if (
+        e.key == "ArrowDown" &&
+        e.altKey &&
+        this.currentMethodIndex < 9
+      ) {
+        this.method =
+          this.methodMenuItems[
+            ++this.currentMethodIndex % this.methodMenuItems.length
+          ]
+      }
+    }
+    document.addEventListener("keydown", this._keyListener.bind(this))
+    await this.oauthRedirectReq()
+  },
+  created() {
+    if (Object.keys(this.$route.query).length)
+      this.setRouteQueries(this.$route.query)
+    this.$watch(
+      (vm) => [
+        vm.name,
+        vm.method,
+        vm.url,
+        vm.auth,
+        vm.path,
+        vm.httpUser,
+        vm.httpPassword,
+        vm.bearerToken,
+        vm.headers,
+        vm.params,
+        vm.bodyParams,
+        vm.contentType,
+        vm.rawParams,
+      ],
+      (val) => {
+        this.setRouteQueryState()
+      }
+    )
+  },
+  beforeDestroy() {
+    document.removeEventListener("keydown", this._keyListener)
+  },
+}
+</script>