Request.vue (hoppscotch-2.0.0) | : | Request.vue (hoppscotch-2.1.0) | ||
---|---|---|---|---|
<template> | <template> | |||
<div class="bg-primary flex space-x-2 p-4 top-0 z-10 sticky"> | <div | |||
class=" | ||||
bg-primary | ||||
flex | ||||
space-x-2 | ||||
p-4 | ||||
top-0 | ||||
z-10 | ||||
sticky | ||||
overflow-x-auto | ||||
hide-scrollbar | ||||
" | ||||
> | ||||
<div class="flex flex-1"> | <div class="flex flex-1"> | |||
<div class="flex relative"> | <div class="flex relative"> | |||
<label for="method"> | <label for="method"> | |||
<tippy | <tippy | |||
ref="methodOptions" | ref="methodOptions" | |||
interactive | interactive | |||
trigger="click" | trigger="click" | |||
theme="popover" | theme="popover" | |||
arrow | arrow | |||
> | > | |||
skipping to change at line 27 | skipping to change at line 39 | |||
class=" | class=" | |||
bg-primaryLight | bg-primaryLight | |||
border border-divider | border border-divider | |||
rounded-l | rounded-l | |||
cursor-pointer | cursor-pointer | |||
flex | flex | |||
font-semibold | font-semibold | |||
text-secondaryDark | text-secondaryDark | |||
py-2 | py-2 | |||
px-4 | px-4 | |||
w-28 | w-26 | |||
hover:border-dividerDark | hover:border-dividerDark | |||
focus-visible:bg-transparent | focus-visible:bg-transparent | |||
focus-visible:border-dividerDark | focus-visible:border-dividerDark | |||
" | " | |||
:value="newMethod" | :value="newMethod" | |||
:readonly="!isCustomMethod" | :readonly="!isCustomMethod" | |||
:placeholder="$t('request.method')" | :placeholder="`${$t('request.method')}`" | |||
@input="onSelectMethod($event.target.value)" | @input="onSelectMethod($event.target.value)" | |||
/> | /> | |||
</span> | </span> | |||
</template> | </template> | |||
<SmartItem | <SmartItem | |||
v-for="(method, index) in methods" | v-for="(method, index) in methods" | |||
:key="`method-${index}`" | :key="`method-${index}`" | |||
:label="method" | :label="method" | |||
@click.native="onSelectMethod(method)" | @click.native="onSelectMethod(method)" | |||
/> | /> | |||
</tippy> | </tippy> | |||
</label> | </label> | |||
</div> | </div> | |||
<div class="flex flex-1"> | <div class="flex flex-1"> | |||
<SmartEnvInput | <SmartEnvInput | |||
v-if="EXPERIMENTAL_URL_BAR_ENABLED" | ||||
v-model="newEndpoint" | v-model="newEndpoint" | |||
:placeholder="$t('request.url')" | :placeholder="`${$t('request.url')}`" | |||
styles=" | styles=" | |||
bg-primaryLight | bg-primaryLight | |||
border border-divider | border border-divider | |||
flex | flex | |||
flex-1 | flex-1 | |||
rounded-r | rounded-r | |||
text-secondaryDark | text-secondaryDark | |||
min-w-32 | ||||
py-1 | py-1 | |||
px-4 | px-4 | |||
hover:border-dividerDark | hover:border-dividerDark | |||
focus-visible:border-dividerDark | focus-visible:border-dividerDark | |||
focus-visible:bg-transparent | focus-visible:bg-transparent | |||
" | " | |||
@enter="newSendRequest()" | @enter="newSendRequest()" | |||
/> | /> | |||
<input | ||||
v-else | ||||
id="url" | ||||
v-model="newEndpoint" | ||||
v-focus | ||||
class=" | ||||
bg-primaryLight | ||||
border border-divider | ||||
rounded-r | ||||
flex | ||||
text-secondaryDark | ||||
w-full | ||||
py-2 | ||||
px-4 | ||||
hover:border-dividerDark | ||||
focus-visible:bg-transparent focus-visible:border-dividerDark | ||||
" | ||||
name="url" | ||||
type="text" | ||||
spellcheck="false" | ||||
:placeholder="$t('request.url')" | ||||
autofocus | ||||
@keyup.enter="newSendRequest()" | ||||
/> | ||||
</div> | </div> | |||
</div> | </div> | |||
<div class="flex"> | <div class="flex"> | |||
<ButtonPrimary | <ButtonPrimary | |||
id="send" | id="send" | |||
class="rounded-r-none flex-1 min-w-22" | class="rounded-r-none flex-1 min-w-20" | |||
:label="!loading ? $t('action.send') : $t('action.cancel')" | :label="`${!loading ? $t('action.send') : $t('action.cancel')}`" | |||
@click.native="!loading ? newSendRequest() : cancelRequest()" | @click.native="!loading ? newSendRequest() : cancelRequest()" | |||
/> | /> | |||
<span class="flex"> | <span class="flex"> | |||
<tippy | <tippy | |||
ref="sendOptions" | ref="sendOptions" | |||
interactive | interactive | |||
trigger="click" | trigger="click" | |||
theme="popover" | theme="popover" | |||
arrow | arrow | |||
> | > | |||
<template #trigger> | <template #trigger> | |||
<ButtonPrimary | <ButtonPrimary class="rounded-l-none" filled svg="chevron-down" /> | |||
class="rounded-l-none" | ||||
filled | ||||
icon="keyboard_arrow_down" | ||||
/> | ||||
</template> | </template> | |||
<SmartItem | <SmartItem | |||
:label="$t('import.curl')" | :label="`${$t('import.curl')}`" | |||
icon="import_export" | svg="terminal" | |||
@click.native=" | @click.native=" | |||
() => { | () => { | |||
showCurlImportModal = !showCurlImportModal | showCurlImportModal = !showCurlImportModal | |||
sendOptions.tippy().hide() | sendOptions.tippy().hide() | |||
} | } | |||
" | " | |||
/> | /> | |||
<SmartItem | <SmartItem | |||
:label="$t('show.code')" | :label="`${$t('show.code')}`" | |||
icon="code" | svg="code" | |||
@click.native=" | @click.native=" | |||
() => { | () => { | |||
showCodegenModal = !showCodegenModal | showCodegenModal = !showCodegenModal | |||
sendOptions.tippy().hide() | sendOptions.tippy().hide() | |||
} | } | |||
" | " | |||
/> | /> | |||
<SmartItem | <SmartItem | |||
ref="clearAll" | ref="clearAll" | |||
:label="$t('action.clear_all')" | :label="`${$t('action.clear_all')}`" | |||
icon="clear_all" | svg="rotate-ccw" | |||
@click.native=" | @click.native=" | |||
() => { | () => { | |||
clearContent() | clearContent() | |||
sendOptions.tippy().hide() | sendOptions.tippy().hide() | |||
} | } | |||
" | " | |||
/> | /> | |||
</tippy> | </tippy> | |||
</span> | </span> | |||
<ButtonSecondary | <ButtonSecondary | |||
class="rounded-r-none ml-2" | class="rounded rounded-r-none ml-2" | |||
:label="$t('request.save')" | :label=" | |||
windowInnerWidth.x.value >= 768 && COLUMN_LAYOUT | ||||
? `${$t('request.save')}` | ||||
: '' | ||||
" | ||||
filled | filled | |||
icon="save" | svg="save" | |||
@click.native="saveRequest()" | @click.native="saveRequest()" | |||
/> | /> | |||
<span class="flex"> | <span class="flex"> | |||
<tippy | <tippy | |||
ref="saveOptions" | ref="saveOptions" | |||
interactive | interactive | |||
trigger="click" | trigger="click" | |||
theme="popover" | theme="popover" | |||
arrow | arrow | |||
> | > | |||
<template #trigger> | <template #trigger> | |||
<ButtonSecondary | <ButtonSecondary | |||
icon="keyboard_arrow_down" | svg="chevron-down" | |||
filled | filled | |||
class="rounded-r" | class="rounded rounded-l-none" | |||
/> | /> | |||
</template> | </template> | |||
<input | <input | |||
id="request-name" | id="request-name" | |||
v-model="requestName" | v-model="requestName" | |||
:placeholder="$t('request.name')" | :placeholder="`${$t('request.name')}`" | |||
name="request-name" | name="request-name" | |||
type="text" | type="text" | |||
autocomplete="off" | ||||
class="mb-2 input" | class="mb-2 input" | |||
@keyup.enter="saveOptions.tippy().hide()" | @keyup.enter="saveOptions.tippy().hide()" | |||
/> | /> | |||
<SmartItem | <SmartItem | |||
ref="copyRequest" | ref="copyRequest" | |||
:label="$t('request.copy_link')" | :label="`${$t('request.copy_link')}`" | |||
:icon="hasNavigatorShare ? 'share' : 'content_copy'" | :svg="hasNavigatorShare ? 'share-2' : 'copy'" | |||
@click.native=" | @click.native=" | |||
() => { | () => { | |||
copyRequest() | copyRequest() | |||
saveOptions.tippy().hide() | saveOptions.tippy().hide() | |||
} | } | |||
" | " | |||
/> | /> | |||
<SmartItem | <SmartItem | |||
ref="saveRequest" | ref="saveRequest" | |||
:label="$t('request.save_as')" | :label="`${$t('request.save_as')}`" | |||
icon="create_new_folder" | svg="folder-plus" | |||
@click.native=" | @click.native=" | |||
() => { | () => { | |||
showSaveRequestModal = true | showSaveRequestModal = true | |||
saveOptions.tippy().hide() | saveOptions.tippy().hide() | |||
} | } | |||
" | " | |||
/> | /> | |||
</tippy> | </tippy> | |||
</span> | </span> | |||
</div> | </div> | |||
skipping to change at line 223 | skipping to change at line 212 | |||
<CollectionsSaveRequest | <CollectionsSaveRequest | |||
mode="rest" | mode="rest" | |||
:show="showSaveRequestModal" | :show="showSaveRequestModal" | |||
@hide-modal="showSaveRequestModal = false" | @hide-modal="showSaveRequestModal = false" | |||
/> | /> | |||
</div> | </div> | |||
</template> | </template> | |||
<script setup lang="ts"> | <script setup lang="ts"> | |||
import { computed, ref, useContext, watch } from "@nuxtjs/composition-api" | import { computed, ref, useContext, watch } from "@nuxtjs/composition-api" | |||
import { isRight } from "fp-ts/lib/Either" | ||||
import { | import { | |||
updateRESTResponse, | updateRESTResponse, | |||
restEndpoint$, | restEndpoint$, | |||
setRESTEndpoint, | setRESTEndpoint, | |||
restMethod$, | restMethod$, | |||
updateRESTMethod, | updateRESTMethod, | |||
resetRESTRequest, | resetRESTRequest, | |||
useRESTRequestName, | useRESTRequestName, | |||
getRESTSaveContext, | getRESTSaveContext, | |||
getRESTRequest, | getRESTRequest, | |||
skipping to change at line 246 | skipping to change at line 236 | |||
import { | import { | |||
useStreamSubscriber, | useStreamSubscriber, | |||
useStream, | useStream, | |||
useNuxt, | useNuxt, | |||
} from "~/helpers/utils/composables" | } from "~/helpers/utils/composables" | |||
import { defineActionHandler } from "~/helpers/actions" | import { defineActionHandler } from "~/helpers/actions" | |||
import { copyToClipboard } from "~/helpers/utils/clipboard" | import { copyToClipboard } from "~/helpers/utils/clipboard" | |||
import { useSetting } from "~/newstore/settings" | import { useSetting } from "~/newstore/settings" | |||
import { overwriteRequestTeams } from "~/helpers/teams/utils" | import { overwriteRequestTeams } from "~/helpers/teams/utils" | |||
import { apolloClient } from "~/helpers/apollo" | import { apolloClient } from "~/helpers/apollo" | |||
import useWindowSize from "~/helpers/utils/useWindowSize" | ||||
const methods = [ | const methods = [ | |||
"GET", | "GET", | |||
"POST", | "POST", | |||
"PUT", | "PUT", | |||
"PATCH", | "PATCH", | |||
"DELETE", | "DELETE", | |||
"HEAD", | "HEAD", | |||
"CONNECT", | "CONNECT", | |||
"OPTIONS", | "OPTIONS", | |||
skipping to change at line 293 | skipping to change at line 284 | |||
// Update Nuxt Loading bar | // Update Nuxt Loading bar | |||
watch(loading, () => { | watch(loading, () => { | |||
if (loading.value) { | if (loading.value) { | |||
nuxt.value.$loading.start() | nuxt.value.$loading.start() | |||
} else { | } else { | |||
nuxt.value.$loading.finish() | nuxt.value.$loading.finish() | |||
} | } | |||
}) | }) | |||
const newSendRequest = () => { | const newSendRequest = async () => { | |||
loading.value = true | loading.value = true | |||
subscribeToStream( | // Double calling is because the function returns a TaskEither than should be | |||
runRESTRequest$(), | executed | |||
(responseState) => { | const streamResult = await runRESTRequest$()() | |||
if (loading.value) { | ||||
// Check exists because, loading can be set to false | // TODO: What if stream fetching failed (script execution errors ?) (isLeft) | |||
// when cancelled | if (isRight(streamResult)) { | |||
updateRESTResponse(responseState) | subscribeToStream( | |||
streamResult.right, | ||||
(responseState) => { | ||||
if (loading.value) { | ||||
// Check exists because, loading can be set to false | ||||
// when cancelled | ||||
updateRESTResponse(responseState) | ||||
} | ||||
}, | ||||
() => { | ||||
loading.value = false | ||||
}, | ||||
() => { | ||||
loading.value = false | ||||
} | } | |||
}, | ) | |||
() => { | } | |||
loading.value = false | ||||
}, | ||||
() => { | ||||
loading.value = false | ||||
} | ||||
) | ||||
} | } | |||
const cancelRequest = () => { | const cancelRequest = () => { | |||
loading.value = false | loading.value = false | |||
updateRESTResponse(null) | updateRESTResponse(null) | |||
} | } | |||
const updateMethod = (method: string) => { | const updateMethod = (method: string) => { | |||
updateRESTMethod(method) | updateRESTMethod(method) | |||
} | } | |||
skipping to change at line 347 | skipping to change at line 344 | |||
navigator | navigator | |||
.share({ | .share({ | |||
title: "Hoppscotch", | title: "Hoppscotch", | |||
text: `Hoppscotch • Open source API development ecosystem at ${time} on ${date}`, | text: `Hoppscotch • Open source API development ecosystem at ${time} on ${date}`, | |||
url: window.location.href, | url: window.location.href, | |||
}) | }) | |||
.then(() => {}) | .then(() => {}) | |||
.catch(() => {}) | .catch(() => {}) | |||
} else { | } else { | |||
copyToClipboard(window.location.href) | copyToClipboard(window.location.href) | |||
$toast.success(t("state.copied_to_clipboard").toString(), { | $toast.success(`${t("state.copied_to_clipboard")}`, { | |||
icon: "content_paste", | icon: "content_paste", | |||
}) | }) | |||
} | } | |||
} | } | |||
const cycleUpMethod = () => { | const cycleUpMethod = () => { | |||
const currentIndex = methods.indexOf(newMethod.value) | const currentIndex = methods.indexOf(newMethod.value) | |||
if (currentIndex === -1) { | if (currentIndex === -1) { | |||
// Most probs we are in CUSTOM mode | // Most probs we are in CUSTOM mode | |||
// Cycle up from CUSTOM is PATCH | // Cycle up from CUSTOM is PATCH | |||
skipping to change at line 404 | skipping to change at line 401 | |||
apolloClient, | apolloClient, | |||
JSON.stringify(req), | JSON.stringify(req), | |||
req.name, | req.name, | |||
saveCtx.requestID | saveCtx.requestID | |||
) | ) | |||
} catch (error) { | } catch (error) { | |||
showSaveRequestModal.value = true | showSaveRequestModal.value = true | |||
return | return | |||
} | } | |||
} | } | |||
$toast.success(t("request.saved").toString(), { | $toast.success(`${t("request.saved")}`, { | |||
icon: "playlist_add_check", | icon: "playlist_add_check", | |||
}) | }) | |||
} | } | |||
defineActionHandler("request.send-cancel", () => { | defineActionHandler("request.send-cancel", () => { | |||
if (!loading.value) newSendRequest() | if (!loading.value) newSendRequest() | |||
else cancelRequest() | else cancelRequest() | |||
}) | }) | |||
defineActionHandler("request.reset", clearContent) | defineActionHandler("request.reset", clearContent) | |||
defineActionHandler("request.copy-link", copyRequest) | defineActionHandler("request.copy-link", copyRequest) | |||
skipping to change at line 434 | skipping to change at line 431 | |||
defineActionHandler("request.method.put", () => updateMethod("PUT")) | defineActionHandler("request.method.put", () => updateMethod("PUT")) | |||
defineActionHandler("request.method.delete", () => updateMethod("DELETE")) | defineActionHandler("request.method.delete", () => updateMethod("DELETE")) | |||
defineActionHandler("request.method.head", () => updateMethod("HEAD")) | defineActionHandler("request.method.head", () => updateMethod("HEAD")) | |||
const isCustomMethod = computed(() => { | const isCustomMethod = computed(() => { | |||
return newMethod.value === "CUSTOM" || !methods.includes(newMethod.value) | return newMethod.value === "CUSTOM" || !methods.includes(newMethod.value) | |||
}) | }) | |||
const requestName = useRESTRequestName() | const requestName = useRESTRequestName() | |||
const EXPERIMENTAL_URL_BAR_ENABLED = useSetting("EXPERIMENTAL_URL_BAR_ENABLED") | const windowInnerWidth = useWindowSize() | |||
const COLUMN_LAYOUT = useSetting("COLUMN_LAYOUT") | ||||
</script> | </script> | |||
End of changes. 28 change blocks. | ||||
71 lines changed or deleted | 70 lines changed or added |