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:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user