feat: shared request (#3486)
Co-authored-by: jamesgeorge007 <jamesgeorge998001@gmail.com>
This commit is contained in:
@@ -1,122 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="my-6 block w-full divide-y divide-dividerLight border border-dividerLight lg:my-0 lg:flex lg:divide-x lg:divide-y-0 lg:border-0"
|
||||
>
|
||||
<div class="table-box font-mono text-tiny">
|
||||
{{ shortcode.id }}
|
||||
</div>
|
||||
<div class="table-box" :class="requestLabelColor">
|
||||
{{ parseShortcodeRequest.method }}
|
||||
</div>
|
||||
<div class="table-box">
|
||||
{{ parseShortcodeRequest.endpoint }}
|
||||
</div>
|
||||
<div ref="timeStampRef" class="table-box">
|
||||
{{ dateStamp }}
|
||||
</div>
|
||||
<div class="table-box justify-center">
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="t('action.open_workspace')"
|
||||
:to="`${shortcodeBaseURL}/r/${shortcode.id}`"
|
||||
blank
|
||||
:icon="IconExternalLink"
|
||||
class="px-3 text-accent hover:text-accent"
|
||||
/>
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="t('action.copy')"
|
||||
color="green"
|
||||
:icon="copyIconRefs"
|
||||
class="px-3"
|
||||
@click="copyShortcode(shortcode.id)"
|
||||
/>
|
||||
<HoppButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="t('action.delete')"
|
||||
:icon="IconTrash"
|
||||
color="red"
|
||||
class="px-3"
|
||||
@click="deleteShortcode(shortcode.id)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from "vue"
|
||||
import { pipe } from "fp-ts/function"
|
||||
import * as RR from "fp-ts/ReadonlyRecord"
|
||||
import * as O from "fp-ts/Option"
|
||||
import { translateToNewRequest } from "@hoppscotch/data"
|
||||
import { refAutoReset } from "@vueuse/core"
|
||||
import { useI18n } from "@composables/i18n"
|
||||
import { useToast } from "@composables/toast"
|
||||
import { copyToClipboard } from "~/helpers/utils/clipboard"
|
||||
import { Shortcode } from "~/helpers/shortcodes/Shortcode"
|
||||
import { shortDateTime } from "~/helpers/utils/date"
|
||||
|
||||
import IconTrash from "~icons/lucide/trash"
|
||||
import IconExternalLink from "~icons/lucide/external-link"
|
||||
import IconCopy from "~icons/lucide/copy"
|
||||
import IconCheck from "~icons/lucide/check"
|
||||
|
||||
const t = useI18n()
|
||||
const toast = useToast()
|
||||
|
||||
const props = defineProps<{
|
||||
shortcode: Shortcode
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "delete-shortcode", codeID: string): void
|
||||
}>()
|
||||
|
||||
const deleteShortcode = (codeID: string) => {
|
||||
emit("delete-shortcode", codeID)
|
||||
}
|
||||
|
||||
const requestMethodLabels = {
|
||||
get: "text-green-500",
|
||||
post: "text-yellow-500",
|
||||
put: "text-blue-500",
|
||||
delete: "text-red-500",
|
||||
default: "text-gray-500",
|
||||
} as const
|
||||
|
||||
const timeStampRef = ref()
|
||||
|
||||
const copyIconRefs = refAutoReset<typeof IconCopy | typeof IconCheck>(
|
||||
IconCopy,
|
||||
1000
|
||||
)
|
||||
|
||||
const parseShortcodeRequest = computed(() =>
|
||||
pipe(props.shortcode.request, JSON.parse, translateToNewRequest)
|
||||
)
|
||||
|
||||
const requestLabelColor = computed(() =>
|
||||
pipe(
|
||||
requestMethodLabels,
|
||||
RR.lookup(parseShortcodeRequest.value.method.toLowerCase()),
|
||||
O.getOrElseW(() => requestMethodLabels.default)
|
||||
)
|
||||
)
|
||||
|
||||
const dateStamp = computed(() => shortDateTime(props.shortcode.createdOn))
|
||||
|
||||
const shortcodeBaseURL =
|
||||
import.meta.env.VITE_SHORTCODE_BASE_URL ?? "https://hopp.sh"
|
||||
|
||||
const copyShortcode = (codeID: string) => {
|
||||
copyToClipboard(`${shortcodeBaseURL}/r/${codeID}`)
|
||||
toast.success(`${t("state.copied_to_clipboard")}`)
|
||||
copyIconRefs.value = IconCheck
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table-box {
|
||||
@apply flex flex-1 items-center truncate px-4 py-1;
|
||||
}
|
||||
</style>
|
||||
@@ -1,168 +0,0 @@
|
||||
<template>
|
||||
<section class="p-4">
|
||||
<h4 class="font-semibold text-secondaryDark">
|
||||
{{ t("settings.short_codes") }}
|
||||
</h4>
|
||||
<div class="my-1 text-secondaryLight">
|
||||
{{ t("settings.short_codes_description") }}
|
||||
</div>
|
||||
<div class="relative overflow-x-auto py-4">
|
||||
<div v-if="loading" class="flex flex-col items-center justify-center">
|
||||
<HoppSmartSpinner class="mb-4" />
|
||||
<span class="text-secondaryLight">{{ t("state.loading") }}</span>
|
||||
</div>
|
||||
<HoppSmartPlaceholder
|
||||
v-if="!loading && myShortcodes.length === 0"
|
||||
:src="`/images/states/${colorMode.value}/add_files.svg`"
|
||||
:alt="`${t('empty.shortcodes')}`"
|
||||
:text="t('empty.shortcodes')"
|
||||
>
|
||||
</HoppSmartPlaceholder>
|
||||
<div v-else-if="!loading">
|
||||
<div
|
||||
class="hidden w-full rounded-t border-x border-t border-dividerLight bg-primaryLight lg:flex"
|
||||
>
|
||||
<div class="flex w-full overflow-y-scroll">
|
||||
<div class="table-box">
|
||||
{{ t("shortcodes.short_code") }}
|
||||
</div>
|
||||
<div class="table-box">
|
||||
{{ t("shortcodes.method") }}
|
||||
</div>
|
||||
<div class="table-box">
|
||||
{{ t("shortcodes.url") }}
|
||||
</div>
|
||||
<div class="table-box">
|
||||
{{ t("shortcodes.created_on") }}
|
||||
</div>
|
||||
<div class="table-box justify-center">
|
||||
{{ t("shortcodes.actions") }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="flex max-h-sm w-full flex-col items-center justify-between divide-dividerLight overflow-y-scroll rounded border border-dividerLight lg:divide-y lg:rounded-t-none"
|
||||
>
|
||||
<ProfileShortcode
|
||||
v-for="(shortcode, shortcodeIndex) in myShortcodes"
|
||||
:key="`shortcode-${shortcodeIndex}`"
|
||||
:shortcode="shortcode"
|
||||
@delete-shortcode="deleteShortcode"
|
||||
/>
|
||||
<HoppSmartIntersection
|
||||
v-if="hasMoreShortcodes && myShortcodes.length > 0"
|
||||
@intersecting="loadMoreShortcodes()"
|
||||
>
|
||||
<div v-if="adapterLoading" class="flex flex-col items-center py-3">
|
||||
<HoppSmartSpinner />
|
||||
</div>
|
||||
</HoppSmartIntersection>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="!loading && adapterError"
|
||||
class="flex flex-col items-center py-4"
|
||||
>
|
||||
<icon-lucide-help-circle class="svg-icons mb-4" />
|
||||
{{ getErrorMessage(adapterError) }}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watchEffect, computed } from "vue"
|
||||
import { pipe } from "fp-ts/function"
|
||||
import * as TE from "fp-ts/TaskEither"
|
||||
import { GQLError } from "~/helpers/backend/GQLClient"
|
||||
import { platform } from "~/platform"
|
||||
|
||||
import { onAuthEvent, onLoggedIn } from "@composables/auth"
|
||||
import { useReadonlyStream } from "@composables/stream"
|
||||
import { useI18n } from "@composables/i18n"
|
||||
import { useToast } from "@composables/toast"
|
||||
import { useColorMode } from "@composables/theming"
|
||||
import { usePageHead } from "@composables/head"
|
||||
|
||||
import ShortcodeListAdapter from "~/helpers/shortcodes/ShortcodeListAdapter"
|
||||
import { deleteShortcode as backendDeleteShortcode } from "~/helpers/backend/mutations/Shortcode"
|
||||
|
||||
const t = useI18n()
|
||||
const toast = useToast()
|
||||
const colorMode = useColorMode()
|
||||
|
||||
usePageHead({
|
||||
title: computed(() => t("navigation.profile")),
|
||||
})
|
||||
|
||||
const currentUser = useReadonlyStream(
|
||||
platform.auth.getCurrentUserStream(),
|
||||
platform.auth.getCurrentUser()
|
||||
)
|
||||
|
||||
const displayName = ref(currentUser.value?.displayName)
|
||||
watchEffect(() => (displayName.value = currentUser.value?.displayName))
|
||||
|
||||
const emailAddress = ref(currentUser.value?.email)
|
||||
watchEffect(() => (emailAddress.value = currentUser.value?.email))
|
||||
|
||||
const adapter = new ShortcodeListAdapter(true)
|
||||
const adapterLoading = useReadonlyStream(adapter.loading$, false)
|
||||
const adapterError = useReadonlyStream(adapter.error$, null)
|
||||
const myShortcodes = useReadonlyStream(adapter.shortcodes$, [])
|
||||
const hasMoreShortcodes = useReadonlyStream(adapter.hasMoreShortcodes$, true)
|
||||
|
||||
const loading = computed(
|
||||
() => adapterLoading.value && myShortcodes.value.length === 0
|
||||
)
|
||||
|
||||
onLoggedIn(() => {
|
||||
try {
|
||||
adapter.initialize()
|
||||
} catch (e) {}
|
||||
})
|
||||
|
||||
onAuthEvent((ev) => {
|
||||
if (ev.event === "logout" && adapter.isInitialized()) {
|
||||
adapter.dispose()
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
const deleteShortcode = (codeID: string) => {
|
||||
pipe(
|
||||
backendDeleteShortcode(codeID),
|
||||
TE.match(
|
||||
(err: GQLError<string>) => {
|
||||
toast.error(`${getErrorMessage(err)}`)
|
||||
},
|
||||
() => {
|
||||
toast.success(`${t("shortcodes.deleted")}`)
|
||||
}
|
||||
)
|
||||
)()
|
||||
}
|
||||
|
||||
const loadMoreShortcodes = () => {
|
||||
adapter.loadMore()
|
||||
}
|
||||
|
||||
const getErrorMessage = (err: GQLError<string>) => {
|
||||
if (err.type === "network_error") {
|
||||
return t("error.network_error")
|
||||
} else {
|
||||
switch (err.error) {
|
||||
case "shortcode/not_found":
|
||||
return t("shortcodes.not_found")
|
||||
default:
|
||||
return t("error.something_went_wrong")
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table-box {
|
||||
@apply flex flex-1 items-center truncate px-4 py-2;
|
||||
}
|
||||
</style>
|
||||
@@ -174,12 +174,7 @@ const getErrorMessage = (err: GQLError<string>) => {
|
||||
if (err.type === "network_error") {
|
||||
return t("error.network_error")
|
||||
} else {
|
||||
switch (err.error) {
|
||||
case "shortcode/not_found":
|
||||
return t("shortcodes.not_found")
|
||||
default:
|
||||
return t("error.something_went_wrong")
|
||||
}
|
||||
return t("error.something_went_wrong")
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user