feat: rest revamp (#2918)

Co-authored-by: Liyas Thomas <liyascthomas@gmail.com>
Co-authored-by: Nivedin <53208152+nivedin@users.noreply.github.com>
Co-authored-by: Andrew Bastin <andrewbastin.k@gmail.com>
This commit is contained in:
Anwarul Islam
2023-03-31 01:15:42 +06:00
committed by GitHub
parent dbb45e7253
commit defece95fc
63 changed files with 2262 additions and 1924 deletions

View File

@@ -17,10 +17,10 @@
<input
id="method"
class="flex px-4 py-2 font-semibold transition rounded-l cursor-pointer text-secondaryDark w-26 bg-primaryLight"
:value="newMethod"
:value="tab.document.request.method"
:readonly="!isCustomMethod"
:placeholder="`${t('request.method')}`"
@input="onSelectMethod($event.target.value)"
@input="onSelectMethod($event)"
/>
</span>
<template #content="{ hide }">
@@ -36,7 +36,7 @@
:label="method"
@click="
() => {
onSelectMethod(method)
updateMethod(method)
hide()
}
"
@@ -50,7 +50,7 @@
class="flex flex-1 overflow-auto transition border-l rounded-r border-divider bg-primaryLight whitespace-nowrap"
>
<SmartEnvInput
v-model="newEndpoint"
v-model="tab.document.request.endpoint"
:placeholder="`${t('request.url')}`"
@enter="newSendRequest()"
@paste="onPasteUrl($event)"
@@ -161,12 +161,11 @@
ref="saveTippyActions"
class="flex flex-col focus:outline-none"
tabindex="0"
@keyup.s="saveRequestAction.$el.click()"
@keyup.escape="hide()"
>
<input
id="request-name"
v-model="requestName"
v-model="tab.document.request.name"
:placeholder="`${t('request.name')}`"
name="request-name"
type="text"
@@ -195,7 +194,6 @@
ref="saveRequestAction"
:label="`${t('request.save_as')}`"
:icon="IconFolderPlus"
:shortcut="['S']"
@click="
() => {
showSaveRequestModal = true
@@ -227,55 +225,40 @@
</template>
<script setup lang="ts">
import IconShare2 from "~icons/lucide/share-2"
import IconCopy from "~icons/lucide/copy"
import IconCheck from "~icons/lucide/check"
import IconFileCode from "~icons/lucide/file-code"
import IconCode2 from "~icons/lucide/code-2"
import IconRotateCCW from "~icons/lucide/rotate-ccw"
import IconSave from "~icons/lucide/save"
import IconChevronDown from "~icons/lucide/chevron-down"
import IconLink2 from "~icons/lucide/link-2"
import IconFolderPlus from "~icons/lucide/folder-plus"
import { computed, ref, watch } from "vue"
import { isLeft, isRight } from "fp-ts/lib/Either"
import * as E from "fp-ts/Either"
import { cloneDeep } from "lodash-es"
import { refAutoReset } from "@vueuse/core"
import {
updateRESTResponse,
restEndpoint$,
setRESTEndpoint,
restMethod$,
updateRESTMethod,
resetRESTRequest,
useRESTRequestName,
getRESTSaveContext,
getRESTRequest,
restRequest$,
setRESTSaveContext,
} from "~/newstore/RESTSession"
import { editRESTRequest } from "~/newstore/collections"
import { runRESTRequest$ } from "~/helpers/RequestRunner"
import {
useStream,
useStreamSubscriber,
useReadonlyStream,
} from "@composables/stream"
import { useI18n } from "@composables/i18n"
import { useToast } from "@composables/toast"
import { useSetting } from "@composables/settings"
import { startPageProgress, completePageProgress } from "@modules/loadingbar"
import { useStreamSubscriber } from "@composables/stream"
import { useToast } from "@composables/toast"
import { completePageProgress, startPageProgress } from "@modules/loadingbar"
import { refAutoReset, useVModel } from "@vueuse/core"
import * as E from "fp-ts/Either"
import { isLeft, isRight } from "fp-ts/lib/Either"
import { computed, ref, watch } from "vue"
import { defineActionHandler } from "~/helpers/actions"
import { copyToClipboard } from "~/helpers/utils/clipboard"
import { createShortcode } from "~/helpers/backend/mutations/Shortcode"
import { runMutation } from "~/helpers/backend/GQLClient"
import { UpdateRequestDocument } from "~/helpers/backend/graphql"
import { createShortcode } from "~/helpers/backend/mutations/Shortcode"
import { getPlatformSpecialKey as getSpecialKey } from "~/helpers/platformutils"
import {
cancelRunningExtensionRequest,
hasExtensionInstalled,
} from "~/helpers/strategies/ExtensionStrategy"
import { runRESTRequest$ } from "~/helpers/RequestRunner"
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
import { copyToClipboard } from "~/helpers/utils/clipboard"
import { editRESTRequest } from "~/newstore/collections"
import IconCheck from "~icons/lucide/check"
import IconChevronDown from "~icons/lucide/chevron-down"
import IconCode2 from "~icons/lucide/code-2"
import IconCopy from "~icons/lucide/copy"
import IconFileCode from "~icons/lucide/file-code"
import IconFolderPlus from "~icons/lucide/folder-plus"
import IconLink2 from "~icons/lucide/link-2"
import IconRotateCCW from "~icons/lucide/rotate-ccw"
import IconSave from "~icons/lucide/save"
import IconShare2 from "~icons/lucide/share-2"
import { HoppRESTTab } from "~/helpers/rest/tab"
import { getDefaultRESTRequest } from "~/helpers/rest/default"
const t = useI18n()
@@ -296,9 +279,19 @@ const toast = useToast()
const { subscribeToStream } = useStreamSubscriber()
const newEndpoint = useStream(restEndpoint$, "", setRESTEndpoint)
const props = defineProps<{ modelValue: HoppRESTTab }>()
const emit = defineEmits(["update:modelValue"])
const tab = useVModel(props, "modelValue", emit)
const newEndpoint = computed(() => {
return tab.value.document.request.endpoint
})
const newMethod = computed(() => {
return tab.value.document.request.method
})
const curlText = ref("")
const newMethod = useStream(restMethod$, "", updateRESTMethod)
const loading = ref(false)
@@ -327,6 +320,30 @@ watch(loading, () => {
}
})
// TODO: make this oAuthURL() work
// function oAuthURL() {
// const auth = useReadonlyStream(props.request.auth$, {
// authType: "none",
// authActive: true,
// })
// const oauth2Token = pluckRef(auth as Ref<HoppRESTAuthOAuth2>, "token")
// onBeforeMount(async () => {
// try {
// const tokenInfo = await oauthRedirect()
// if (Object.prototype.hasOwnProperty.call(tokenInfo, "access_token")) {
// if (typeof tokenInfo === "object") {
// oauth2Token.value = tokenInfo.access_token
// }
// }
// // eslint-disable-next-line no-empty
// } catch (_) {}
// })
// }
const newSendRequest = async () => {
if (newEndpoint.value === "" || /^\s+$/.test(newEndpoint.value)) {
toast.error(`${t("empty.endpoint")}`)
@@ -335,10 +352,14 @@ const newSendRequest = async () => {
ensureMethodInEndpoint()
console.log("Sending request", newEndpoint.value)
loading.value = true
// Double calling is because the function returns a TaskEither than should be executed
const streamResult = await runRESTRequest$()()
const streamResult = await runRESTRequest$(tab)()
console.log("Stream result", streamResult)
if (isRight(streamResult)) {
subscribeToStream(
@@ -380,9 +401,11 @@ const ensureMethodInEndpoint = () => {
) {
const domain = newEndpoint.value.split(/[/:#?]+/)[0]
if (domain === "localhost" || /([0-9]+\.)*[0-9]/.test(domain)) {
setRESTEndpoint("http://" + newEndpoint.value)
tab.value.document.request.endpoint =
"http://" + tab.value.document.request.endpoint
} else {
setRESTEndpoint("https://" + newEndpoint.value)
tab.value.document.request.endpoint =
"https://" + tab.value.document.request.endpoint
}
}
}
@@ -395,7 +418,7 @@ const onPasteUrl = (e: { pastedValue: string; prevValue: string }) => {
if (isCURL(pastedData)) {
showCurlImportModal.value = true
curlText.value = pastedData
newEndpoint.value = e.prevValue
tab.value.document.request.endpoint = e.prevValue
}
}
@@ -412,15 +435,21 @@ const cancelRequest = () => {
}
const updateMethod = (method: string) => {
updateRESTMethod(method)
tab.value.document.request.method = method
}
const onSelectMethod = (method: string) => {
updateMethod(method)
const onSelectMethod = (e: Event | any) => {
// type any because of value property not being recognized by TS in the event.target object. It is a valid property though.
updateMethod(e.value)
}
const clearContent = () => {
resetRESTRequest()
tab.value.document.request = getDefaultRESTRequest()
}
const updateRESTResponse = (response: HoppRESTResponse | null) => {
tab.value.response = response
console.log("Updating response", response)
}
const copyLinkIcon = refAutoReset<
@@ -440,20 +469,13 @@ const shareButtonText = computed(() => {
}
})
const request = useReadonlyStream(restRequest$, getRESTRequest())
watch(request, () => {
shareLink.value = null
})
const copyRequest = async () => {
if (shareLink.value) {
copyShareLink(shareLink.value)
} else {
shareLink.value = ""
fetchingShareLink.value = true
const request = getRESTRequest()
const shortcodeResult = await createShortcode(request)()
const shortcodeResult = await createShortcode(tab.value.document.request)()
if (E.isLeft(shortcodeResult)) {
toast.error(`${shortcodeResult.left.error}`)
shareLink.value = `${t("error.something_went_wrong")}`
@@ -511,33 +533,26 @@ const cycleDownMethod = () => {
}
const saveRequest = () => {
const saveCtx = getRESTSaveContext()
const saveCtx = tab.value.document.saveContext
if (!saveCtx) {
showSaveRequestModal.value = true
return
}
if (saveCtx.originLocation === "user-collection") {
const req = getRESTRequest()
const req = tab.value.document.request
try {
editRESTRequest(
saveCtx.folderPath,
saveCtx.requestIndex,
getRESTRequest()
)
setRESTSaveContext({
originLocation: "user-collection",
folderPath: saveCtx.folderPath,
requestIndex: saveCtx.requestIndex,
req: cloneDeep(req),
})
editRESTRequest(saveCtx.folderPath, saveCtx.requestIndex, req)
tab.value.document.isDirty = false
toast.success(`${t("request.saved")}`)
} catch (e) {
setRESTSaveContext(null)
tab.value.document.saveContext = undefined
saveRequest()
}
} else if (saveCtx.originLocation === "team-collection") {
const req = getRESTRequest()
const req = tab.value.document.request
// TODO: handle error case (NOTE: overwriteRequestTeams is async)
try {
@@ -551,11 +566,8 @@ const saveRequest = () => {
if (E.isLeft(result)) {
toast.error(`${t("profile.no_permission")}`)
} else {
setRESTSaveContext({
originLocation: "team-collection",
requestID: saveCtx.requestID,
req: cloneDeep(req),
})
tab.value.document.isDirty = false
toast.success(`${t("request.saved")}`)
}
})
@@ -587,10 +599,11 @@ defineActionHandler("request.method.delete", () => updateMethod("DELETE"))
defineActionHandler("request.method.head", () => updateMethod("HEAD"))
const isCustomMethod = computed(() => {
return newMethod.value === "CUSTOM" || !methods.includes(newMethod.value)
return (
tab.value.document.request.method === "CUSTOM" ||
!methods.includes(newMethod.value)
)
})
const requestName = useRESTRequestName()
const COLUMN_LAYOUT = useSetting("COLUMN_LAYOUT")
</script>