feat: active tab no longer resets after request (#2917)

Co-authored-by: Andrew Bastin <andrewbastin.k@gmail.com>
Closes https://github.com/hoppscotch/hoppscotch/issues/2080
This commit is contained in:
Jesvin Jose
2023-02-08 10:29:18 +05:30
committed by GitHub
parent ce0898956d
commit a227af05d9
6 changed files with 93 additions and 74 deletions

View File

@@ -3,40 +3,32 @@
<HttpResponseMeta :response="response" /> <HttpResponseMeta :response="response" />
<LensesResponseBodyRenderer <LensesResponseBodyRenderer
v-if="!loading && hasResponse" v-if="!loading && hasResponse"
v-model:selected-tab-preference="selectedTabPreference"
:response="response" :response="response"
/> />
</div> </div>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { computed, defineComponent, watch } from "vue" import { ref, computed, watch } from "vue"
import { startPageProgress, completePageProgress } from "@modules/loadingbar" import { startPageProgress, completePageProgress } from "@modules/loadingbar"
import { useReadonlyStream } from "@composables/stream" import { useReadonlyStream } from "@composables/stream"
import { restResponse$ } from "~/newstore/RESTSession" import { restResponse$ } from "~/newstore/RESTSession"
export default defineComponent({ const selectedTabPreference = ref<string | null>(null)
setup() {
const response = useReadonlyStream(restResponse$, null)
const hasResponse = computed( const response = useReadonlyStream(restResponse$, null)
() =>
response.value?.type === "success" || response.value?.type === "fail"
)
const loading = computed( const hasResponse = computed(
() => response.value === null || response.value.type === "loading" () => response.value?.type === "success" || response.value?.type === "fail"
) )
watch(response, () => { const loading = computed(
if (response.value?.type === "loading") startPageProgress() () => response.value === null || response.value.type === "loading"
else completePageProgress() )
})
return { watch(response, () => {
hasResponse, if (response.value?.type === "loading") startPageProgress()
response, else completePageProgress()
loading,
}
},
}) })
</script> </script>

View File

@@ -107,7 +107,7 @@ const t = useI18n()
const colorMode = useColorMode() const colorMode = useColorMode()
const props = defineProps<{ const props = defineProps<{
response: HoppRESTResponse response: HoppRESTResponse | null
}>() }>()
/** /**
@@ -118,6 +118,7 @@ const props = defineProps<{
*/ */
const readableResponseSize = computed(() => { const readableResponseSize = computed(() => {
if ( if (
props.response === null ||
props.response.type === "loading" || props.response.type === "loading" ||
props.response.type === "network_fail" || props.response.type === "network_fail" ||
props.response.type === "script_fail" || props.response.type === "script_fail" ||
@@ -135,6 +136,7 @@ const readableResponseSize = computed(() => {
const statusCategory = computed(() => { const statusCategory = computed(() => {
if ( if (
props.response === null ||
props.response.type === "loading" || props.response.type === "loading" ||
props.response.type === "network_fail" || props.response.type === "network_fail" ||
props.response.type === "script_fail" || props.response.type === "script_fail" ||

View File

@@ -27,18 +27,18 @@
<script setup lang="ts"> <script setup lang="ts">
import IconCopy from "~icons/lucide/copy" import IconCopy from "~icons/lucide/copy"
import IconCheck from "~icons/lucide/check" import IconCheck from "~icons/lucide/check"
import { HoppRESTHeader } from "@hoppscotch/data"
import { refAutoReset } from "@vueuse/core" import { refAutoReset } from "@vueuse/core"
import { copyToClipboard } from "~/helpers/utils/clipboard" import { copyToClipboard } from "~/helpers/utils/clipboard"
import { useI18n } from "@composables/i18n" import { useI18n } from "@composables/i18n"
import { useToast } from "@composables/toast" import { useToast } from "@composables/toast"
import type { HoppRESTResponseHeader } from "~/helpers/types/HoppRESTResponse"
const t = useI18n() const t = useI18n()
const toast = useToast() const toast = useToast()
const props = defineProps<{ const props = defineProps<{
headers: Array<HoppRESTHeader> headers: HoppRESTResponseHeader[]
}>() }>()
const copyIcon = refAutoReset<typeof IconCopy | typeof IconCheck>( const copyIcon = refAutoReset<typeof IconCopy | typeof IconCheck>(

View File

@@ -30,7 +30,7 @@
import IconCopy from "~icons/lucide/copy" import IconCopy from "~icons/lucide/copy"
import IconCheck from "~icons/lucide/check" import IconCheck from "~icons/lucide/check"
import { refAutoReset } from "@vueuse/core" import { refAutoReset } from "@vueuse/core"
import type { HoppRESTHeader } from "@hoppscotch/data" import type { HoppRESTResponseHeader } from "~/helpers/types/HoppRESTResponse"
import { copyToClipboard } from "~/helpers/utils/clipboard" import { copyToClipboard } from "~/helpers/utils/clipboard"
import { useI18n } from "@composables/i18n" import { useI18n } from "@composables/i18n"
import { useToast } from "@composables/toast" import { useToast } from "@composables/toast"
@@ -40,7 +40,7 @@ const t = useI18n()
const toast = useToast() const toast = useToast()
defineProps<{ defineProps<{
header: HoppRESTHeader header: HoppRESTResponseHeader
}>() }>()
const copyIcon = refAutoReset<typeof IconCopy | typeof IconCheck>( const copyIcon = refAutoReset<typeof IconCopy | typeof IconCheck>(

View File

@@ -11,16 +11,16 @@
:label="t(lens.lensName)" :label="t(lens.lensName)"
class="flex flex-col flex-1 w-full h-full" class="flex flex-col flex-1 w-full h-full"
> >
<component :is="lens.renderer" :response="response" /> <component :is="lensRendererFor(lens.renderer)" :response="response" />
</SmartTab> </SmartTab>
<SmartTab <SmartTab
v-if="headerLength" v-if="maybeHeaders"
id="headers" id="headers"
:label="t('response.headers')" :label="t('response.headers')"
:info="`${headerLength}`" :info="`${maybeHeaders.length}`"
class="flex flex-col flex-1" class="flex flex-col flex-1"
> >
<LensesHeadersRenderer :headers="response.headers" /> <LensesHeadersRenderer :headers="maybeHeaders" />
</SmartTab> </SmartTab>
<SmartTab <SmartTab
id="results" id="results"
@@ -42,54 +42,77 @@
</SmartTabs> </SmartTabs>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { defineComponent } from "vue" import { computed, ref, watch } from "vue"
import { getSuitableLenses, getLensRenderers } from "~/helpers/lenses/lenses" import {
getSuitableLenses,
getLensRenderers,
Lens,
} from "~/helpers/lenses/lenses"
import { useReadonlyStream } from "@composables/stream" import { useReadonlyStream } from "@composables/stream"
import { useI18n } from "@composables/i18n" import { useI18n } from "@composables/i18n"
import type { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
import { restTestResults$ } from "~/newstore/RESTSession" import { restTestResults$ } from "~/newstore/RESTSession"
export default defineComponent({ const props = defineProps<{
components: { response: HoppRESTResponse | null
// Lens Renderers selectedTabPreference: string | null
...getLensRenderers(), }>()
},
props: {
response: { type: Object, default: () => ({}) },
},
setup() {
const testResults = useReadonlyStream(restTestResults$, null)
return { const emit = defineEmits<{
testResults, (e: "update:selectedTabPreference", newTab: string): void
t: useI18n(), }>()
const allLensRenderers = getLensRenderers()
function lensRendererFor(name: string) {
return allLensRenderers[name]
}
const testResults = useReadonlyStream(restTestResults$, null)
const t = useI18n()
const selectedLensTab = ref("")
const maybeHeaders = computed(() => {
if (
!props.response ||
!(props.response.type === "success" || props.response.type === "fail")
)
return null
return props.response.headers
})
const validLenses = computed(() => {
if (!props.response) return []
return getSuitableLenses(props.response)
})
watch(
validLenses,
(newLenses: Lens[]) => {
if (newLenses.length === 0) return
const validRenderers = [
...newLenses.map((x) => x.renderer),
"headers",
"results",
]
if (
props.selectedTabPreference &&
validRenderers.includes(props.selectedTabPreference)
) {
selectedLensTab.value = props.selectedTabPreference
} else {
selectedLensTab.value = newLenses[0].renderer
} }
}, },
data() { { immediate: true }
return { )
selectedLensTab: "",
}
},
computed: {
headerLength() {
if (!this.response || !this.response.headers) return 0
return Object.keys(this.response.headers).length watch(selectedLensTab, (newLensID) => {
}, emit("update:selectedTabPreference", newLensID)
validLenses() {
if (!this.response) return []
return getSuitableLenses(this.response)
},
},
watch: {
validLenses: {
handler(newValue) {
if (newValue.length === 0) return
this.selectedLensTab = newValue[0].renderer
},
immediate: true,
},
},
}) })
</script> </script>

View File

@@ -1,10 +1,12 @@
import { HoppRESTRequest } from "@hoppscotch/data" import { HoppRESTRequest } from "@hoppscotch/data"
export type HoppRESTResponseHeader = { key: string; value: string }
export type HoppRESTResponse = export type HoppRESTResponse =
| { type: "loading"; req: HoppRESTRequest } | { type: "loading"; req: HoppRESTRequest }
| { | {
type: "fail" type: "fail"
headers: { key: string; value: string }[] headers: HoppRESTResponseHeader[]
body: ArrayBuffer body: ArrayBuffer
statusCode: number statusCode: number
@@ -27,7 +29,7 @@ export type HoppRESTResponse =
} }
| { | {
type: "success" type: "success"
headers: { key: string; value: string }[] headers: HoppRESTResponseHeader[]
body: ArrayBuffer body: ArrayBuffer
statusCode: number statusCode: number
meta: { meta: {