Skip to content

Commit 4c1911c

Browse files
12fahednivedinjamesgeorge007
authored
feat(common): add erase response functionality with keybindings (hoppscotch#5435)
Co-authored-by: nivedin <[email protected]> Co-authored-by: James George <[email protected]>
1 parent fdbec04 commit 4c1911c

File tree

11 files changed

+326
-28
lines changed

11 files changed

+326
-28
lines changed

packages/hoppscotch-common/locales/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"clear_cache": "Clear Cache",
1313
"clear_history": "Clear all History",
1414
"clear_unpinned": "Clear Unpinned",
15+
"clear_response": "Clear Response",
1516
"close": "Close",
1617
"confirm": "Confirm",
1718
"connect": "Connect",

packages/hoppscotch-common/src/components/lenses/renderers/AudioLensRenderer.vue

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,43 @@
66
<label class="truncate font-semibold text-secondaryLight">
77
{{ t("response.body") }}
88
</label>
9-
<div class="flex">
9+
<div v-if="response.body" class="flex">
1010
<HoppButtonSecondary
11-
v-if="response.body"
1211
v-tippy="{ theme: 'tooltip', allowHTML: true }"
1312
:title="`${t(
1413
'action.download_file'
1514
)} <kbd>${getSpecialKey()}</kbd><kbd>J</kbd>`"
1615
:icon="downloadIcon"
1716
@click="downloadResponse"
1817
/>
18+
<tippy
19+
v-if="!isEditable"
20+
interactive
21+
trigger="click"
22+
theme="popover"
23+
:on-shown="() => responseMoreActionsTippy?.focus()"
24+
>
25+
<HoppButtonSecondary
26+
v-tippy="{ theme: 'tooltip' }"
27+
:title="t('action.more')"
28+
:icon="IconMore"
29+
/>
30+
<template #content="{ hide }">
31+
<div
32+
ref="responseMoreActionsTippy"
33+
class="flex flex-col focus:outline-none"
34+
tabindex="0"
35+
@keyup.escape="hide()"
36+
>
37+
<HoppSmartItem
38+
:label="t('action.clear_response')"
39+
:icon="IconEraser"
40+
:shortcut="[getSpecialKey(), 'Delete']"
41+
@click="eraseResponse"
42+
/>
43+
</div>
44+
</template>
45+
</tippy>
1946
</div>
2047
</div>
2148
<div class="flex flex-1 items-center justify-center overflow-auto">
@@ -25,7 +52,7 @@
2552
</template>
2653

2754
<script setup lang="ts">
28-
import { computed } from "vue"
55+
import { computed, ref } from "vue"
2956
import { useI18n } from "@composables/i18n"
3057
import { useDownloadResponse } from "@composables/lens-actions"
3158
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
@@ -37,13 +64,21 @@ import * as RNEA from "fp-ts/ReadonlyNonEmptyArray"
3764
import * as A from "fp-ts/Array"
3865
import * as O from "fp-ts/Option"
3966
import { objFieldMatches } from "~/helpers/functional/object"
67+
import { HoppRESTRequestResponse } from "@hoppscotch/data"
68+
import IconEraser from "~icons/lucide/eraser"
69+
import IconMore from "~icons/lucide/more-horizontal"
4070
4171
const t = useI18n()
4272
4373
const props = defineProps<{
4474
response: HoppRESTResponse & {
4575
type: "success" | "fail"
4676
}
77+
isEditable: boolean
78+
}>()
79+
80+
const emit = defineEmits<{
81+
(e: "update:response", val: HoppRESTRequestResponse | HoppRESTResponse): void
4782
}>()
4883
4984
const audiosrc = computed(() =>
@@ -54,6 +89,8 @@ const audiosrc = computed(() =>
5489
)
5590
)
5691
92+
const responseMoreActionsTippy = ref<HTMLElement | null>(null)
93+
5794
const responseType = computed(() =>
5895
pipe(
5996
props.response,
@@ -78,5 +115,10 @@ const { downloadIcon, downloadResponse } = useDownloadResponse(
78115
})
79116
)
80117
118+
const eraseResponse = () => {
119+
emit("update:response", null)
120+
}
121+
81122
defineActionHandler("response.file.download", () => downloadResponse())
123+
defineActionHandler("response.erase", () => eraseResponse())
82124
</script>

packages/hoppscotch-common/src/components/lenses/renderers/HTMLLensRenderer.vue

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,16 @@
77
<label class="truncate font-semibold text-secondaryLight">
88
{{ t("response.body") }}
99
</label>
10-
<div class="flex">
10+
<div v-if="response.body" class="flex">
1111
<HoppButtonSecondary
12-
v-if="response.body && !previewEnabled"
12+
v-if="!previewEnabled"
1313
v-tippy="{ theme: 'tooltip' }"
1414
:title="t('state.linewrap')"
1515
:class="{ '!text-accent': WRAP_LINES }"
1616
:icon="IconWrapText"
1717
@click.prevent="toggleNestedSetting('WRAP_LINES', 'httpResponseBody')"
1818
/>
1919
<HoppButtonSecondary
20-
v-if="response.body"
2120
v-tippy="{ theme: 'tooltip', allowHTML: true }"
2221
:title="`${
2322
previewEnabled ? t('hide.preview') : t('response.preview_html')
@@ -26,7 +25,6 @@
2625
@click.prevent="doTogglePreview"
2726
/>
2827
<HoppButtonSecondary
29-
v-if="response.body"
3028
v-tippy="{ theme: 'tooltip', allowHTML: true }"
3129
:title="`${t(
3230
'action.download_file'
@@ -35,7 +33,7 @@
3533
@click="downloadResponse"
3634
/>
3735
<HoppButtonSecondary
38-
v-if="response.body"
36+
v-if="!isEditable"
3937
v-tippy="{ theme: 'tooltip', allowHTML: true }"
4038
:title="
4139
isSavable
@@ -51,14 +49,41 @@
5149
@click="isSavable ? saveAsExample() : null"
5250
/>
5351
<HoppButtonSecondary
54-
v-if="response.body"
5552
v-tippy="{ theme: 'tooltip', allowHTML: true }"
5653
:title="`${t(
5754
'action.copy'
5855
)} <kbd>${getSpecialKey()}</kbd><kbd>.</kbd>`"
5956
:icon="copyIcon"
6057
@click="copyResponse"
6158
/>
59+
<tippy
60+
v-if="!isEditable"
61+
interactive
62+
trigger="click"
63+
theme="popover"
64+
:on-shown="() => responseMoreActionsTippy?.focus()"
65+
>
66+
<HoppButtonSecondary
67+
v-tippy="{ theme: 'tooltip' }"
68+
:title="t('action.more')"
69+
:icon="IconMore"
70+
/>
71+
<template #content="{ hide }">
72+
<div
73+
ref="responseMoreActionsTippy"
74+
class="flex flex-col focus:outline-none"
75+
tabindex="0"
76+
@keyup.escape="hide()"
77+
>
78+
<HoppSmartItem
79+
:label="t('action.clear_response')"
80+
:icon="IconEraser"
81+
:shortcut="[getSpecialKey(), 'Delete']"
82+
@click="eraseResponse"
83+
/>
84+
</div>
85+
</template>
86+
</tippy>
6287
</div>
6388
</div>
6489
<div
@@ -101,6 +126,8 @@ import IconEye from "~icons/lucide/eye"
101126
import IconEyeOff from "~icons/lucide/eye-off"
102127
import IconWrapText from "~icons/lucide/wrap-text"
103128
import IconSave from "~icons/lucide/save"
129+
import IconEraser from "~icons/lucide/eraser"
130+
import IconMore from "~icons/lucide/more-horizontal"
104131
import { HoppRESTRequestResponse } from "@hoppscotch/data"
105132
import { computedAsync } from "@vueuse/core"
106133
import { useScrollerRef } from "~/composables/useScrollerRef"
@@ -126,9 +153,14 @@ const { containerRef } = useScrollerRef(
126153
127154
const emit = defineEmits<{
128155
(e: "save-as-example"): void
156+
(
157+
e: "update:response",
158+
val: HoppRESTRequestResponse | HoppRESTResponse | null
159+
): void
129160
}>()
130161
131162
const htmlResponse = ref<any | null>(null)
163+
const responseMoreActionsTippy = ref<HTMLElement | null>(null)
132164
const WRAP_LINES = useNestedSetting("WRAP_LINES", "httpResponseBody")
133165
134166
const responseName = computed(() => {
@@ -174,6 +206,10 @@ const doTogglePreview = async () => {
174206
175207
const { copyIcon, copyResponse } = useCopyResponse(responseBodyText)
176208
209+
const eraseResponse = () => {
210+
emit("update:response", null)
211+
}
212+
177213
const saveAsExample = () => {
178214
emit("save-as-example")
179215
}
@@ -196,6 +232,7 @@ useCodemirror(
196232
defineActionHandler("response.preview.toggle", () => doTogglePreview())
197233
defineActionHandler("response.file.download", () => downloadResponse())
198234
defineActionHandler("response.copy", () => copyResponse())
235+
defineActionHandler("response.erase", () => eraseResponse())
199236
defineActionHandler("response.save-as-example", () => {
200237
props.isSavable ? saveAsExample() : null
201238
})

packages/hoppscotch-common/src/components/lenses/renderers/ImageLensRenderer.vue

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,43 @@
66
<label class="truncate font-semibold text-secondaryLight">
77
{{ t("response.body") }}
88
</label>
9-
<div class="flex">
9+
<div v-if="response.body" class="flex">
1010
<HoppButtonSecondary
11-
v-if="response.body"
1211
v-tippy="{ theme: 'tooltip', allowHTML: true }"
1312
:title="`${t(
1413
'action.download_file'
1514
)} <kbd>${getSpecialKey()}</kbd><kbd>J</kbd>`"
1615
:icon="downloadIcon"
1716
@click="downloadResponse"
1817
/>
18+
<tippy
19+
v-if="!isEditable"
20+
interactive
21+
trigger="click"
22+
theme="popover"
23+
:on-shown="() => responseMoreActionsTippy?.focus()"
24+
>
25+
<HoppButtonSecondary
26+
v-tippy="{ theme: 'tooltip' }"
27+
:title="t('action.more')"
28+
:icon="IconMore"
29+
/>
30+
<template #content="{ hide }">
31+
<div
32+
ref="responseMoreActionsTippy"
33+
class="flex flex-col focus:outline-none"
34+
tabindex="0"
35+
@keyup.escape="hide()"
36+
>
37+
<HoppSmartItem
38+
:label="t('action.clear_response')"
39+
:icon="IconEraser"
40+
:shortcut="[getSpecialKey(), 'Delete']"
41+
@click="eraseResponse"
42+
/>
43+
</div>
44+
</template>
45+
</tippy>
1946
</div>
2047
</div>
2148
<img
@@ -40,14 +67,23 @@ import * as RNEA from "fp-ts/ReadonlyNonEmptyArray"
4067
import * as A from "fp-ts/Array"
4168
import * as O from "fp-ts/Option"
4269
import { objFieldMatches } from "~/helpers/functional/object"
70+
import { HoppRESTRequestResponse } from "@hoppscotch/data"
71+
import IconEraser from "~icons/lucide/eraser"
72+
import IconMore from "~icons/lucide/more-horizontal"
4373
4474
const t = useI18n()
4575
4676
const props = defineProps<{
4777
response: HoppRESTResponse & { type: "success" | "fail" }
78+
isEditable: boolean
79+
}>()
80+
81+
const emit = defineEmits<{
82+
(e: "update:response", val: HoppRESTRequestResponse | HoppRESTResponse): void
4883
}>()
4984
5085
const imageSource = ref("")
86+
const responseMoreActionsTippy = ref<HTMLElement | null>(null)
5187
5288
const responseType = computed(() =>
5389
pipe(
@@ -101,5 +137,10 @@ onMounted(() => {
101137
reader.readAsDataURL(blob)
102138
})
103139
140+
const eraseResponse = () => {
141+
emit("update:response", null)
142+
}
143+
104144
defineActionHandler("response.file.download", () => downloadResponse())
145+
defineActionHandler("response.erase", () => eraseResponse())
105146
</script>

packages/hoppscotch-common/src/components/lenses/renderers/JSONLensRenderer.vue

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
@click="copyResponse"
6060
/>
6161
<tippy
62-
v-if="showResponse"
62+
v-if="showResponse && response.body && !isEditable"
6363
interactive
6464
trigger="click"
6565
theme="popover"
@@ -87,6 +87,12 @@
8787
}
8888
"
8989
/>
90+
<HoppSmartItem
91+
:label="t('action.clear_response')"
92+
:icon="IconEraser"
93+
:shortcut="[getSpecialKey(), 'Delete']"
94+
@click="eraseResponse"
95+
/>
9096
</div>
9197
</template>
9298
</tippy>
@@ -252,6 +258,7 @@ import IconMore from "~icons/lucide/more-horizontal"
252258
import IconHelpCircle from "~icons/lucide/help-circle"
253259
import IconNetwork from "~icons/lucide/network"
254260
import IconSave from "~icons/lucide/save"
261+
import IconEraser from "~icons/lucide/eraser"
255262
import * as LJSON from "lossless-json"
256263
import * as O from "fp-ts/Option"
257264
import * as E from "fp-ts/Either"
@@ -458,6 +465,11 @@ const saveAsExample = () => {
458465
}
459466
460467
const { copyIcon, copyResponse } = useCopyResponse(jsonBodyText)
468+
469+
const eraseResponse = () => {
470+
emit("update:response", null)
471+
}
472+
461473
const { downloadIcon, downloadResponse } = useDownloadResponse(
462474
"application/json",
463475
jsonBodyText,
@@ -520,6 +532,7 @@ const toggleFilterState = () => {
520532
521533
defineActionHandler("response.file.download", () => downloadResponse())
522534
defineActionHandler("response.copy", () => copyResponse())
535+
defineActionHandler("response.erase", () => eraseResponse())
523536
defineActionHandler("response.save-as-example", () => {
524537
props.isSavable ? saveAsExample() : null
525538
})

0 commit comments

Comments
 (0)