Browse Source

chore: add computed header for graphql

nivedin 1 year ago
parent
commit
369d01a399
1 changed files with 151 additions and 1 deletions
  1. 151 1
      packages/hoppscotch-common/src/components/graphql/Headers.vue

+ 151 - 1
packages/hoppscotch-common/src/components/graphql/Headers.vue

@@ -156,6 +156,65 @@
         </div>
       </template>
     </draggable>
+
+    <draggable
+      v-model="computedHeaders"
+      item-key="id"
+      animation="250"
+      handle=".draggable-handle"
+      draggable=".draggable-content"
+      ghost-class="cursor-move"
+      chosen-class="bg-primaryLight"
+      drag-class="cursor-grabbing"
+    >
+      <template #item="{ element: header, index }">
+        <div
+          class="draggable-content group flex divide-x divide-dividerLight border-b border-dividerLight"
+        >
+          <span>
+            <HoppButtonSecondary
+              :icon="IconLock"
+              class="cursor-auto bg-divider text-secondaryLight opacity-25"
+              tabindex="-1"
+            />
+          </span>
+          <SmartEnvInput
+            v-model="header.header.key"
+            :placeholder="`${t('count.value', { count: index + 1 })}`"
+            readonly
+          />
+          <SmartEnvInput
+            :model-value="mask(header)"
+            :placeholder="`${t('count.value', { count: index + 1 })}`"
+            readonly
+          />
+          <span>
+            <HoppButtonSecondary
+              v-if="header.source === 'auth'"
+              v-tippy="{ theme: 'tooltip' }"
+              :title="t(masking ? 'state.show' : 'state.hide')"
+              :icon="masking ? IconEye : IconEyeOff"
+              @click="toggleMask()"
+            />
+            <HoppButtonSecondary
+              v-else
+              v-tippy="{ theme: 'tooltip' }"
+              :icon="IconArrowUpRight"
+              :title="t('request.go_to_authorization_tab')"
+              class="cursor-auto text-primary hover:text-primary"
+            />
+          </span>
+          <span>
+            <HoppButtonSecondary
+              v-tippy="{ theme: 'tooltip' }"
+              :icon="IconArrowUpRight"
+              :title="t('request.go_to_authorization_tab')"
+            />
+          </span>
+        </div>
+      </template>
+    </draggable>
+
     <HoppSmartPlaceholder
       v-if="workingHeaders.length === 0"
       :src="`/images/states/${colorMode.value}/add_category.svg`"
@@ -184,7 +243,12 @@ import IconCheckCircle from "~icons/lucide/check-circle"
 import IconTrash from "~icons/lucide/trash"
 import IconCircle from "~icons/lucide/circle"
 import IconWrapText from "~icons/lucide/wrap-text"
-import { reactive, ref, watch } from "vue"
+import IconArrowUpRight from "~icons/lucide/arrow-up-right"
+import IconLock from "~icons/lucide/lock"
+import IconEye from "~icons/lucide/eye"
+import IconEyeOff from "~icons/lucide/eye-off"
+
+import { computed, reactive, ref, watch } from "vue"
 import * as E from "fp-ts/Either"
 import * as O from "fp-ts/Option"
 import * as A from "fp-ts/Array"
@@ -206,6 +270,7 @@ import { commonHeaders } from "~/helpers/headers"
 import { useCodemirror } from "@composables/codemirror"
 import { objRemoveKey } from "~/helpers/functional/object"
 import { useVModel } from "@vueuse/core"
+import { HoppGQLHeader } from "~/helpers/graphql"
 
 const colorMode = useColorMode()
 const t = useI18n()
@@ -321,6 +386,7 @@ watch(workingHeaders, (newWorkingHeaders) => {
     )
   )
 
+  console.log("not-equal", workingHeaders.value)
   if (!isEqual(request.value.headers, fixedHeaders)) {
     request.value.headers = cloneDeep(fixedHeaders)
   }
@@ -429,4 +495,88 @@ const clearContent = () => {
 
   bulkHeaders.value = ""
 }
+
+const getComputedAuthHeaders = (
+  req?: HoppGQLRequest,
+  auth?: HoppGQLRequest["auth"]
+) => {
+  const request = auth ? { auth: auth ?? { authActive: false } } : req
+  // If Authorization header is also being user-defined, that takes priority
+  if (req && req.headers.find((h) => h.key.toLowerCase() === "authorization"))
+    return []
+
+  if (!request) return []
+
+  if (!request.auth || !request.auth.authActive) return []
+
+  const headers: HoppGQLHeader[] = []
+
+  // TODO: Support a better b64 implementation than btoa ?
+  if (request.auth.authType === "basic") {
+    const username = request.auth.username
+    const password = request.auth.password
+
+    headers.push({
+      active: true,
+      key: "Authorization",
+      value: `Basic ${btoa(`${username}:${password}`)}`,
+    })
+  } else if (
+    request.auth.authType === "bearer" ||
+    request.auth.authType === "oauth-2"
+  ) {
+    headers.push({
+      active: true,
+      key: "Authorization",
+      value: `Bearer ${request.auth.token}`,
+    })
+  } else if (request.auth.authType === "api-key") {
+    const { key, value, addTo } = request.auth
+
+    if (addTo === "Headers") {
+      headers.push({
+        active: true,
+        key,
+        value,
+      })
+    }
+  }
+
+  return headers
+}
+
+const getComputedHeaders = (req: HoppGQLRequest) => {
+  return [
+    ...getComputedAuthHeaders(req).map((header) => ({
+      source: "auth" as const,
+      header,
+    })),
+  ]
+}
+
+const computedHeaders = computed(() =>
+  getComputedHeaders(request.value).map((header, index) => ({
+    id: `header-${index}`,
+    ...header,
+  }))
+)
+
+const masking = ref(true)
+
+const toggleMask = () => {
+  masking.value = !masking.value
+}
+
+const mask = (header: any) => {
+  if (header.source === "auth" && masking.value)
+    return header.header.value.replace(/\S/gi, "*")
+  return header.header.value
+}
+
+// const changeTab = (tab: ComputedHeader["source"]) => {
+//   if (tab === "auth") emit("change-tab", "authorization")
+//   else emit("change-tab", "bodyParams")
+// }
+
+console.log("compoyed-header", computedHeaders.value)
 </script>