feat: migrate pre-request script, test script, settings to nuxt composition
This commit is contained in:
@@ -14,7 +14,7 @@
|
|||||||
// Text color
|
// Text color
|
||||||
--secondary-color: theme("colors.true-gray.400");
|
--secondary-color: theme("colors.true-gray.400");
|
||||||
// Light Text color
|
// Light Text color
|
||||||
--secondary-light-color: theme("colors.true-gray.200");
|
--secondary-light-color: theme("colors.true-gray.500");
|
||||||
// Dark Text color
|
// Dark Text color
|
||||||
--secondary-dark-color: theme("colors.white");
|
--secondary-dark-color: theme("colors.white");
|
||||||
// Border color
|
// Border color
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ export default defineComponent({
|
|||||||
params,
|
params,
|
||||||
headers,
|
headers,
|
||||||
preRequestScript: "",
|
preRequestScript: "",
|
||||||
|
testScript: "",
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
53
components/http/PreRequestScript.vue
Normal file
53
components/http/PreRequestScript.vue
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<template>
|
||||||
|
<AppSection label="preRequest">
|
||||||
|
<div
|
||||||
|
class="
|
||||||
|
bg-primary
|
||||||
|
border-b border-dividerLight
|
||||||
|
flex flex-1
|
||||||
|
pl-4
|
||||||
|
top-110px
|
||||||
|
z-10
|
||||||
|
sticky
|
||||||
|
items-center
|
||||||
|
justify-between
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<label class="font-semibold text-xs">
|
||||||
|
{{ $t("javascript_code") }}
|
||||||
|
</label>
|
||||||
|
<ButtonSecondary
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
to="https://github.com/hoppscotch/hoppscotch/wiki/Pre-Request-Scripts"
|
||||||
|
blank
|
||||||
|
:title="$t('wiki')"
|
||||||
|
icon="help_outline"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<SmartJsEditor
|
||||||
|
v-model="preRequestScript"
|
||||||
|
:options="{
|
||||||
|
maxLines: '16',
|
||||||
|
minLines: '8',
|
||||||
|
fontSize: '14px',
|
||||||
|
autoScrollEditorIntoView: true,
|
||||||
|
showPrintMargin: false,
|
||||||
|
useWorker: false,
|
||||||
|
}"
|
||||||
|
complete-mode="pre"
|
||||||
|
/>
|
||||||
|
</AppSection>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from "@nuxtjs/composition-api"
|
||||||
|
import { usePreRequestScript } from "~/newstore/RESTSession"
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
preRequestScript: usePreRequestScript(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
92
components/http/Tests.vue
Normal file
92
components/http/Tests.vue
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
<template>
|
||||||
|
<AppSection label="postRequestTests">
|
||||||
|
<div
|
||||||
|
class="
|
||||||
|
bg-primary
|
||||||
|
border-b border-dividerLight
|
||||||
|
flex flex-1
|
||||||
|
pl-4
|
||||||
|
top-110px
|
||||||
|
z-10
|
||||||
|
sticky
|
||||||
|
items-center
|
||||||
|
justify-between
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<label class="font-semibold text-xs">
|
||||||
|
{{ $t("javascript_code") }}
|
||||||
|
</label>
|
||||||
|
<ButtonSecondary
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
to="https://github.com/hoppscotch/hoppscotch/wiki/Post-Request-Tests"
|
||||||
|
blank
|
||||||
|
:title="$t('wiki')"
|
||||||
|
icon="help_outline"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<SmartJsEditor
|
||||||
|
v-model="testScript"
|
||||||
|
:options="{
|
||||||
|
maxLines: '16',
|
||||||
|
minLines: '8',
|
||||||
|
fontSize: '14px',
|
||||||
|
autoScrollEditorIntoView: true,
|
||||||
|
showPrintMargin: false,
|
||||||
|
useWorker: false,
|
||||||
|
}"
|
||||||
|
complete-mode="test"
|
||||||
|
/>
|
||||||
|
<div v-if="testReports.length !== 0">
|
||||||
|
<div class="flex flex-1 pl-4 items-center justify-between">
|
||||||
|
<label class="font-semibold text-xs"> Test Reports </label>
|
||||||
|
<ButtonSecondary
|
||||||
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
|
:title="$t('clear')"
|
||||||
|
icon="clear_all"
|
||||||
|
@click.native="clearContent('tests', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-for="(testReport, index) in testReports"
|
||||||
|
:key="`testReport-${index}`"
|
||||||
|
class="px-4"
|
||||||
|
>
|
||||||
|
<div v-if="testReport.startBlock">
|
||||||
|
<hr />
|
||||||
|
<h4 class="heading">
|
||||||
|
{{ testReport.startBlock }}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
v-else-if="testReport.result"
|
||||||
|
class="flex font-mono flex-1 text-xs info"
|
||||||
|
>
|
||||||
|
<span :class="testReport.styles.class" class="flex items-center">
|
||||||
|
<i class="text-sm material-icons">
|
||||||
|
{{ testReport.styles.icon }}
|
||||||
|
</i>
|
||||||
|
<span> {{ testReport.result }}</span>
|
||||||
|
<span v-if="testReport.message">
|
||||||
|
<label>: {{ testReport.message }}</label>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<div v-else-if="testReport.endBlock"><hr /></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AppSection>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from "@nuxtjs/composition-api"
|
||||||
|
import { useTestScript } from "~/newstore/RESTSession"
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
testScript: useTestScript(),
|
||||||
|
testReports: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -20,6 +20,7 @@ export interface HoppRESTRequest {
|
|||||||
params: HoppRESTParam[]
|
params: HoppRESTParam[]
|
||||||
headers: HoppRESTHeader[]
|
headers: HoppRESTHeader[]
|
||||||
preRequestScript: string
|
preRequestScript: string
|
||||||
|
testScript: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeRESTRequest(
|
export function makeRESTRequest(
|
||||||
@@ -56,6 +57,7 @@ export function translateToNewRequest(x: any): HoppRESTRequest {
|
|||||||
const method = x.method
|
const method = x.method
|
||||||
|
|
||||||
const preRequestScript = x.preRequestScript
|
const preRequestScript = x.preRequestScript
|
||||||
|
const testScript = x.testScript
|
||||||
|
|
||||||
const result: HoppRESTRequest = {
|
const result: HoppRESTRequest = {
|
||||||
endpoint,
|
endpoint,
|
||||||
@@ -63,6 +65,7 @@ export function translateToNewRequest(x: any): HoppRESTRequest {
|
|||||||
params,
|
params,
|
||||||
method,
|
method,
|
||||||
preRequestScript,
|
preRequestScript,
|
||||||
|
testScript,
|
||||||
v: RESTReqSchemaVersion,
|
v: RESTReqSchemaVersion,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
60
helpers/utils/composables.ts
Normal file
60
helpers/utils/composables.ts
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import {
|
||||||
|
customRef,
|
||||||
|
onBeforeUnmount,
|
||||||
|
readonly,
|
||||||
|
Ref,
|
||||||
|
ref,
|
||||||
|
} from "@nuxtjs/composition-api"
|
||||||
|
import { Observable, Subscription } from "rxjs"
|
||||||
|
|
||||||
|
export function useReadonlyStream<T>(stream$: Observable<T>, initialValue: T) {
|
||||||
|
let sub: Subscription | null = null
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (sub) {
|
||||||
|
sub.unsubscribe()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const targetRef = ref(initialValue) as Ref<T>
|
||||||
|
|
||||||
|
sub = stream$.subscribe((value) => {
|
||||||
|
targetRef.value = value
|
||||||
|
})
|
||||||
|
|
||||||
|
return readonly(targetRef)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useStream<T>(
|
||||||
|
stream$: Observable<T>,
|
||||||
|
initialValue: T,
|
||||||
|
setter: (val: T) => void
|
||||||
|
) {
|
||||||
|
let sub: Subscription | null = null
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (sub) {
|
||||||
|
sub.unsubscribe()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return customRef((track, trigger) => {
|
||||||
|
let value = initialValue
|
||||||
|
|
||||||
|
sub = stream$.subscribe((val) => {
|
||||||
|
value = val
|
||||||
|
trigger()
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
get() {
|
||||||
|
track()
|
||||||
|
return value
|
||||||
|
},
|
||||||
|
set(value: T) {
|
||||||
|
trigger()
|
||||||
|
setter(value)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -340,6 +340,7 @@
|
|||||||
"we_sent_magic_link_description": "Check your inbox - we sent an email to {email}. It contains a magic link that will log you in.",
|
"we_sent_magic_link_description": "Check your inbox - we sent an email to {email}. It contains a magic link that will log you in.",
|
||||||
"hide_sidebar": "Hide sidebar",
|
"hide_sidebar": "Hide sidebar",
|
||||||
"show_sidebar": "Show sidebar",
|
"show_sidebar": "Show sidebar",
|
||||||
|
"navigation_sidebar": "Navigation sidebar",
|
||||||
"protocols": "Protocols",
|
"protocols": "Protocols",
|
||||||
"protocol_count": "Protocol {count}",
|
"protocol_count": "Protocol {count}",
|
||||||
"share": "Share",
|
"share": "Share",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<Pane class="flex flex-1 overflow-auto">
|
<Pane class="flex flex-1 overflow-auto">
|
||||||
<Splitpanes vertical :dbl-click-splitter="false">
|
<Splitpanes vertical :dbl-click-splitter="false">
|
||||||
<Pane
|
<Pane
|
||||||
v-if="!hideNavigationPane"
|
v-if="!HIDE_NAVBAR"
|
||||||
style="width: auto"
|
style="width: auto"
|
||||||
class="hide-scrollbar overflow-auto"
|
class="hide-scrollbar overflow-auto"
|
||||||
>
|
>
|
||||||
@@ -28,12 +28,10 @@
|
|||||||
<div>
|
<div>
|
||||||
<ButtonSecondary
|
<ButtonSecondary
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
:title="
|
:title="HIDE_NAVBAR ? $t('show_sidebar') : $t('hide_sidebar')"
|
||||||
hideNavigationPane ? $t('show_sidebar') : $t('hide_sidebar')
|
|
||||||
"
|
|
||||||
icon="menu_open"
|
icon="menu_open"
|
||||||
:class="{ 'transform rotate-180': hideNavigationPane }"
|
:class="{ 'transform rotate-180': HIDE_NAVBAR }"
|
||||||
@click.native="hideNavigationPane = !hideNavigationPane"
|
@click.native="toggleSetting('HIDE_NAVBAR')"
|
||||||
/>
|
/>
|
||||||
<ButtonSecondary
|
<ButtonSecondary
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
@@ -72,16 +70,21 @@ import { performMigrations } from "~/helpers/migrations"
|
|||||||
import { initUserInfo } from "~/helpers/teams/BackendUserInfo"
|
import { initUserInfo } from "~/helpers/teams/BackendUserInfo"
|
||||||
import { registerApolloAuthUpdate } from "~/helpers/apollo"
|
import { registerApolloAuthUpdate } from "~/helpers/apollo"
|
||||||
import { initializeFirebase } from "~/helpers/fb"
|
import { initializeFirebase } from "~/helpers/fb"
|
||||||
import { getSettingSubject } from "~/newstore/settings"
|
import { getSettingSubject, toggleSetting } from "~/newstore/settings"
|
||||||
import { logPageView } from "~/helpers/fb/analytics"
|
import { logPageView } from "~/helpers/fb/analytics"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { Splitpanes, Pane },
|
components: { Splitpanes, Pane },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
hideNavigationPane: false,
|
|
||||||
zenMode: false,
|
zenMode: false,
|
||||||
hideRightPane: false,
|
hideRightPane: false,
|
||||||
|
HIDE_NAVBAR: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
subscriptions() {
|
||||||
|
return {
|
||||||
|
HIDE_NAVBAR: getSettingSubject("HIDE_NAVBAR"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -146,5 +149,10 @@ export default {
|
|||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
document.removeEventListener("keydown", this._keyListener)
|
document.removeEventListener("keydown", this._keyListener)
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
toggleSetting(key) {
|
||||||
|
toggleSetting(key)
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { pluck, distinctUntilChanged, map, filter } from "rxjs/operators"
|
import { pluck, distinctUntilChanged, map, filter } from "rxjs/operators"
|
||||||
import { customRef, onBeforeUnmount, Ref } from "@nuxtjs/composition-api"
|
import { Ref } from "@nuxtjs/composition-api"
|
||||||
import { Subscription } from "rxjs"
|
|
||||||
import DispatchingStore, { defineDispatchers } from "./DispatchingStore"
|
import DispatchingStore, { defineDispatchers } from "./DispatchingStore"
|
||||||
import {
|
import {
|
||||||
HoppRESTHeader,
|
HoppRESTHeader,
|
||||||
@@ -9,6 +8,7 @@ import {
|
|||||||
RESTReqSchemaVersion,
|
RESTReqSchemaVersion,
|
||||||
} from "~/helpers/types/HoppRESTRequest"
|
} from "~/helpers/types/HoppRESTRequest"
|
||||||
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
|
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
|
||||||
|
import { useStream } from "~/helpers/utils/composables"
|
||||||
|
|
||||||
function getParamsInURL(url: string): { key: string; value: string }[] {
|
function getParamsInURL(url: string): { key: string; value: string }[] {
|
||||||
const result: { key: string; value: string }[] = []
|
const result: { key: string; value: string }[] = []
|
||||||
@@ -124,6 +124,7 @@ const defaultRESTSession: RESTSession = {
|
|||||||
headers: [],
|
headers: [],
|
||||||
method: "GET",
|
method: "GET",
|
||||||
preRequestScript: "// pw.env.set('variable', 'value');",
|
preRequestScript: "// pw.env.set('variable', 'value');",
|
||||||
|
testScript: "// pw.expect('variable').toBe('value');",
|
||||||
},
|
},
|
||||||
response: null,
|
response: null,
|
||||||
}
|
}
|
||||||
@@ -298,6 +299,14 @@ const dispatchers = defineDispatchers({
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
setTestScript(curr: RESTSession, { newScript }: { newScript: string }) {
|
||||||
|
return {
|
||||||
|
request: {
|
||||||
|
...curr.request,
|
||||||
|
testScript: newScript,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
updateResponse(
|
updateResponse(
|
||||||
_curr: RESTSession,
|
_curr: RESTSession,
|
||||||
{ updatedRes }: { updatedRes: HoppRESTResponse | null }
|
{ updatedRes }: { updatedRes: HoppRESTResponse | null }
|
||||||
@@ -416,7 +425,7 @@ export function deleteAllRESTHeaders() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setPreRequestScript(newScript: string) {
|
export function setRESTPreRequestScript(newScript: string) {
|
||||||
restSessionStore.dispatch({
|
restSessionStore.dispatch({
|
||||||
dispatcher: "setPreRequestScript",
|
dispatcher: "setPreRequestScript",
|
||||||
payload: {
|
payload: {
|
||||||
@@ -425,6 +434,15 @@ export function setPreRequestScript(newScript: string) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setRESTTestScript(newScript: string) {
|
||||||
|
restSessionStore.dispatch({
|
||||||
|
dispatcher: "setTestScript",
|
||||||
|
payload: {
|
||||||
|
newScript,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export function updateRESTResponse(updatedRes: HoppRESTResponse | null) {
|
export function updateRESTResponse(updatedRes: HoppRESTResponse | null) {
|
||||||
restSessionStore.dispatch({
|
restSessionStore.dispatch({
|
||||||
dispatcher: "updateResponse",
|
dispatcher: "updateResponse",
|
||||||
@@ -479,6 +497,11 @@ export const restPreRequestScript$ = restSessionStore.subject$.pipe(
|
|||||||
distinctUntilChanged()
|
distinctUntilChanged()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export const restTestScript$ = restSessionStore.subject$.pipe(
|
||||||
|
pluck("request", "testScript"),
|
||||||
|
distinctUntilChanged()
|
||||||
|
)
|
||||||
|
|
||||||
export const restResponse$ = restSessionStore.subject$.pipe(
|
export const restResponse$ = restSessionStore.subject$.pipe(
|
||||||
pluck("response"),
|
pluck("response"),
|
||||||
distinctUntilChanged()
|
distinctUntilChanged()
|
||||||
@@ -499,28 +522,28 @@ export const completedRESTResponse$ = restResponse$.pipe(
|
|||||||
* dispatches.
|
* dispatches.
|
||||||
*/
|
*/
|
||||||
export function usePreRequestScript(): Ref<string> {
|
export function usePreRequestScript(): Ref<string> {
|
||||||
let sub: Subscription | null = null
|
return useStream(
|
||||||
|
restPreRequestScript$,
|
||||||
onBeforeUnmount(() => {
|
restSessionStore.value.request.preRequestScript,
|
||||||
if (sub) {
|
(value) => {
|
||||||
sub.unsubscribe()
|
setRESTPreRequestScript(value)
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
|
}
|
||||||
return customRef((track, trigger) => {
|
|
||||||
sub = restPreRequestScript$.subscribe(() => {
|
/**
|
||||||
trigger()
|
* A Vue 3 composable function that gives access to a ref
|
||||||
})
|
* which is updated to the testScript value in the store.
|
||||||
|
* The ref value is kept in sync with the store and all writes
|
||||||
return {
|
* to the ref are dispatched to the store as `setTestScript`
|
||||||
get() {
|
* dispatches.
|
||||||
track()
|
*/
|
||||||
return restSessionStore.value.request.preRequestScript
|
export function useTestScript(): Ref<string> {
|
||||||
},
|
return useStream(
|
||||||
set(value: string) {
|
restTestScript$,
|
||||||
trigger()
|
restSessionStore.value.request.testScript,
|
||||||
setPreRequestScript(value)
|
(value) => {
|
||||||
},
|
setRESTTestScript(value)
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import { pluck, distinctUntilChanged } from "rxjs/operators"
|
import { pluck, distinctUntilChanged } from "rxjs/operators"
|
||||||
import has from "lodash/has"
|
import has from "lodash/has"
|
||||||
import { Observable } from "rxjs"
|
import { Observable } from "rxjs"
|
||||||
|
import { Ref } from "@nuxtjs/composition-api"
|
||||||
import DispatchingStore, { defineDispatchers } from "./DispatchingStore"
|
import DispatchingStore, { defineDispatchers } from "./DispatchingStore"
|
||||||
import type { KeysMatching } from "~/types/ts-utils"
|
import type { KeysMatching } from "~/types/ts-utils"
|
||||||
|
import { useStream } from "~/helpers/utils/composables"
|
||||||
|
|
||||||
export const HoppBgColors = ["system", "light", "dark", "black"] as const
|
export const HoppBgColors = ["system", "light", "dark", "black"] as const
|
||||||
|
|
||||||
@@ -43,6 +45,7 @@ export type SettingsType = {
|
|||||||
BG_COLOR: HoppBgColor
|
BG_COLOR: HoppBgColor
|
||||||
TELEMETRY_ENABLED: boolean
|
TELEMETRY_ENABLED: boolean
|
||||||
SHORTCUTS_INDICATOR_ENABLED: boolean
|
SHORTCUTS_INDICATOR_ENABLED: boolean
|
||||||
|
HIDE_NAVBAR: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultSettings: SettingsType = {
|
export const defaultSettings: SettingsType = {
|
||||||
@@ -66,6 +69,7 @@ export const defaultSettings: SettingsType = {
|
|||||||
BG_COLOR: "system",
|
BG_COLOR: "system",
|
||||||
TELEMETRY_ENABLED: true,
|
TELEMETRY_ENABLED: true,
|
||||||
SHORTCUTS_INDICATOR_ENABLED: false,
|
SHORTCUTS_INDICATOR_ENABLED: false,
|
||||||
|
HIDE_NAVBAR: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
const validKeys = Object.keys(defaultSettings)
|
const validKeys = Object.keys(defaultSettings)
|
||||||
@@ -152,3 +156,21 @@ export function applySetting<K extends keyof SettingsType>(
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useSetting<K extends keyof SettingsType>(
|
||||||
|
settingKey: K
|
||||||
|
): Ref<SettingsType[K]> {
|
||||||
|
return useStream(
|
||||||
|
settingsStore.subject$.pipe(pluck(settingKey), distinctUntilChanged()),
|
||||||
|
settingsStore.value[settingKey],
|
||||||
|
(value: SettingsType[K]) => {
|
||||||
|
settingsStore.dispatch({
|
||||||
|
dispatcher: "applySetting",
|
||||||
|
payload: {
|
||||||
|
settingKey,
|
||||||
|
value,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
141
pages/index.vue
141
pages/index.vue
@@ -31,19 +31,7 @@
|
|||||||
<span class="select-wrapper">
|
<span class="select-wrapper">
|
||||||
<input
|
<input
|
||||||
id="contentType"
|
id="contentType"
|
||||||
class="
|
class="bg-primary rounded-lg flex font-semibold font-mono text-xs w-full py-2 px-4 transition truncate focus:outline-none"
|
||||||
bg-primary
|
|
||||||
rounded-lg
|
|
||||||
flex
|
|
||||||
font-semibold font-mono
|
|
||||||
text-xs
|
|
||||||
w-full
|
|
||||||
py-2
|
|
||||||
px-4
|
|
||||||
transition
|
|
||||||
truncate
|
|
||||||
focus:outline-none
|
|
||||||
"
|
|
||||||
v-model="contentType"
|
v-model="contentType"
|
||||||
readonly
|
readonly
|
||||||
/>
|
/>
|
||||||
@@ -319,128 +307,11 @@
|
|||||||
:id="'pre_request_script'"
|
:id="'pre_request_script'"
|
||||||
:label="$t('pre_request_script')"
|
:label="$t('pre_request_script')"
|
||||||
>
|
>
|
||||||
<AppSection v-if="showPreRequestScript" label="preRequest">
|
<HttpPreRequestScript />
|
||||||
<div
|
|
||||||
class="
|
|
||||||
bg-primary
|
|
||||||
border-b border-dividerLight
|
|
||||||
flex flex-1
|
|
||||||
pl-4
|
|
||||||
top-110px
|
|
||||||
z-10
|
|
||||||
sticky
|
|
||||||
items-center
|
|
||||||
justify-between
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<label class="font-semibold text-xs">
|
|
||||||
{{ $t("javascript_code") }}
|
|
||||||
</label>
|
|
||||||
<ButtonSecondary
|
|
||||||
to="https://github.com/hoppscotch/hoppscotch/wiki/Pre-Request-Scripts"
|
|
||||||
blank
|
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
|
||||||
:title="$t('wiki')"
|
|
||||||
icon="help_outline"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<SmartJsEditor
|
|
||||||
v-model="preRequestScript"
|
|
||||||
:options="{
|
|
||||||
maxLines: '16',
|
|
||||||
minLines: '8',
|
|
||||||
fontSize: '14px',
|
|
||||||
autoScrollEditorIntoView: true,
|
|
||||||
showPrintMargin: false,
|
|
||||||
useWorker: false,
|
|
||||||
}"
|
|
||||||
completeMode="pre"
|
|
||||||
/>
|
|
||||||
</AppSection>
|
|
||||||
</SmartTab>
|
</SmartTab>
|
||||||
|
|
||||||
<SmartTab :id="'tests'" :label="$t('tests')">
|
<SmartTab :id="'tests'" :label="$t('tests')">
|
||||||
<AppSection v-if="testsEnabled" label="postRequestTests">
|
<HttpTests />
|
||||||
<div
|
|
||||||
class="
|
|
||||||
bg-primary
|
|
||||||
border-b border-dividerLight
|
|
||||||
flex flex-1
|
|
||||||
pl-4
|
|
||||||
top-110px
|
|
||||||
z-10
|
|
||||||
sticky
|
|
||||||
items-center
|
|
||||||
justify-between
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<label class="font-semibold text-xs">
|
|
||||||
{{ $t("javascript_code") }}
|
|
||||||
</label>
|
|
||||||
<ButtonSecondary
|
|
||||||
to="https://github.com/hoppscotch/hoppscotch/wiki/Post-Request-Tests"
|
|
||||||
blank
|
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
|
||||||
:title="$t('wiki')"
|
|
||||||
icon="help_outline"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<SmartJsEditor
|
|
||||||
v-model="testScript"
|
|
||||||
:options="{
|
|
||||||
maxLines: '16',
|
|
||||||
minLines: '8',
|
|
||||||
fontSize: '14px',
|
|
||||||
autoScrollEditorIntoView: true,
|
|
||||||
showPrintMargin: false,
|
|
||||||
useWorker: false,
|
|
||||||
}"
|
|
||||||
completeMode="test"
|
|
||||||
/>
|
|
||||||
<div v-if="testReports.length !== 0">
|
|
||||||
<div class="flex flex-1 pl-4 items-center justify-between">
|
|
||||||
<label class="font-semibold text-xs">
|
|
||||||
Test Reports
|
|
||||||
</label>
|
|
||||||
<ButtonSecondary
|
|
||||||
@click.native="clearContent('tests', $event)"
|
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
|
||||||
:title="$t('clear')"
|
|
||||||
icon="clear_all"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-for="(testReport, index) in testReports"
|
|
||||||
:key="`testReport-${index}`"
|
|
||||||
class="px-4"
|
|
||||||
>
|
|
||||||
<div v-if="testReport.startBlock">
|
|
||||||
<hr />
|
|
||||||
<h4 class="heading">
|
|
||||||
{{ testReport.startBlock }}
|
|
||||||
</h4>
|
|
||||||
</div>
|
|
||||||
<p
|
|
||||||
v-else-if="testReport.result"
|
|
||||||
class="flex font-mono flex-1 text-xs info"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
:class="testReport.styles.class"
|
|
||||||
class="flex items-center"
|
|
||||||
>
|
|
||||||
<i class="text-sm material-icons">
|
|
||||||
{{ testReport.styles.icon }}
|
|
||||||
</i>
|
|
||||||
<span> {{ testReport.result }}</span>
|
|
||||||
<span v-if="testReport.message">
|
|
||||||
<label>: {{ testReport.message }}</label>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<div v-else-if="testReport.endBlock"><hr /></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</AppSection>
|
|
||||||
</SmartTab>
|
</SmartTab>
|
||||||
</SmartTabs>
|
</SmartTabs>
|
||||||
</Pane>
|
</Pane>
|
||||||
@@ -615,8 +486,6 @@ export default defineComponent({
|
|||||||
return {
|
return {
|
||||||
showCurlImportModal: false,
|
showCurlImportModal: false,
|
||||||
showPreRequestScript: true,
|
showPreRequestScript: true,
|
||||||
testsEnabled: true,
|
|
||||||
testScript: "// pw.expect('variable').toBe('value');",
|
|
||||||
testReports: [],
|
testReports: [],
|
||||||
copyButton: '<i class="material-icons">content_copy</i>',
|
copyButton: '<i class="material-icons">content_copy</i>',
|
||||||
downloadButton: '<i class="material-icons">save_alt</i>',
|
downloadButton: '<i class="material-icons">save_alt</i>',
|
||||||
@@ -731,7 +600,6 @@ export default defineComponent({
|
|||||||
this.preRequestScript = newValue.preRequestScript
|
this.preRequestScript = newValue.preRequestScript
|
||||||
}
|
}
|
||||||
if (newValue.testScript) {
|
if (newValue.testScript) {
|
||||||
this.testsEnabled = true
|
|
||||||
this.testScript = newValue.testScript
|
this.testScript = newValue.testScript
|
||||||
}
|
}
|
||||||
this.name = newValue.name
|
this.name = newValue.name
|
||||||
@@ -1333,7 +1201,6 @@ export default defineComponent({
|
|||||||
contentType: this.contentType,
|
contentType: this.contentType,
|
||||||
requestType: this.requestType,
|
requestType: this.requestType,
|
||||||
testScript: this.testScript,
|
testScript: this.testScript,
|
||||||
usesPostScripts: this.testsEnabled,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -1678,7 +1545,7 @@ export default defineComponent({
|
|||||||
requestType: this.requestType,
|
requestType: this.requestType,
|
||||||
preRequestScript:
|
preRequestScript:
|
||||||
this.showPreRequestScript == true ? this.preRequestScript : null,
|
this.showPreRequestScript == true ? this.preRequestScript : null,
|
||||||
testScript: this.testsEnabled == true ? this.testScript : null,
|
testScript: this.testScript,
|
||||||
name: this.requestName,
|
name: this.requestName,
|
||||||
}
|
}
|
||||||
this.showSaveRequestModal = true
|
this.showSaveRequestModal = true
|
||||||
|
|||||||
@@ -182,6 +182,15 @@
|
|||||||
}}
|
}}
|
||||||
</SmartToggle>
|
</SmartToggle>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<SmartToggle
|
||||||
|
:on="HIDE_NAVBAR"
|
||||||
|
@change="toggleSetting('HIDE_NAVBAR')"
|
||||||
|
>
|
||||||
|
{{ $t("navigation_sidebar") }}
|
||||||
|
{{ HIDE_NAVBAR ? $t("enabled") : $t("disabled") }}
|
||||||
|
</SmartToggle>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
@@ -302,21 +311,39 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from "vue"
|
import { defineComponent } from "@nuxtjs/composition-api"
|
||||||
import { hasExtensionInstalled } from "../helpers/strategies/ExtensionStrategy"
|
import { hasExtensionInstalled } from "../helpers/strategies/ExtensionStrategy"
|
||||||
import {
|
import {
|
||||||
getSettingSubject,
|
|
||||||
applySetting,
|
applySetting,
|
||||||
toggleSetting,
|
toggleSetting,
|
||||||
defaultSettings,
|
defaultSettings,
|
||||||
|
useSetting,
|
||||||
} from "~/newstore/settings"
|
} from "~/newstore/settings"
|
||||||
import type { KeysMatching } from "~/types/ts-utils"
|
import type { KeysMatching } from "~/types/ts-utils"
|
||||||
import { currentUser$ } from "~/helpers/fb/auth"
|
import { currentUser$ } from "~/helpers/fb/auth"
|
||||||
import { getLocalConfig } from "~/newstore/localpersistence"
|
import { getLocalConfig } from "~/newstore/localpersistence"
|
||||||
|
import { useReadonlyStream } from "~/helpers/utils/composables"
|
||||||
|
|
||||||
type SettingsType = typeof defaultSettings
|
type SettingsType = typeof defaultSettings
|
||||||
|
|
||||||
export default Vue.extend({
|
export default defineComponent({
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
SCROLL_INTO_ENABLED: useSetting("SCROLL_INTO_ENABLED"),
|
||||||
|
PROXY_ENABLED: useSetting("PROXY_ENABLED"),
|
||||||
|
PROXY_URL: useSetting("PROXY_URL"),
|
||||||
|
PROXY_KEY: useSetting("PROXY_KEY"),
|
||||||
|
EXTENSIONS_ENABLED: useSetting("EXTENSIONS_ENABLED"),
|
||||||
|
EXPERIMENTAL_URL_BAR_ENABLED: useSetting("EXPERIMENTAL_URL_BAR_ENABLED"),
|
||||||
|
SYNC_COLLECTIONS: useSetting("syncCollections"),
|
||||||
|
SYNC_ENVIRONMENTS: useSetting("syncEnvironments"),
|
||||||
|
SYNC_HISTORY: useSetting("syncHistory"),
|
||||||
|
TELEMETRY_ENABLED: useSetting("TELEMETRY_ENABLED"),
|
||||||
|
SHORTCUTS_INDICATOR_ENABLED: useSetting("SHORTCUTS_INDICATOR_ENABLED"),
|
||||||
|
HIDE_NAVBAR: useSetting("HIDE_NAVBAR"),
|
||||||
|
currentUser: useReadonlyStream(currentUser$, currentUser$.value),
|
||||||
|
}
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
extensionVersion: hasExtensionInstalled()
|
extensionVersion: hasExtensionInstalled()
|
||||||
@@ -325,52 +352,10 @@ export default Vue.extend({
|
|||||||
|
|
||||||
clearIcon: "clear_all",
|
clearIcon: "clear_all",
|
||||||
|
|
||||||
SYNC_COLLECTIONS: true,
|
|
||||||
SYNC_ENVIRONMENTS: true,
|
|
||||||
SYNC_HISTORY: true,
|
|
||||||
|
|
||||||
PROXY_URL: "",
|
|
||||||
PROXY_KEY: "",
|
|
||||||
|
|
||||||
EXTENSIONS_ENABLED: true,
|
|
||||||
PROXY_ENABLED: true,
|
|
||||||
|
|
||||||
currentUser: null,
|
|
||||||
|
|
||||||
showLogin: false,
|
showLogin: false,
|
||||||
|
|
||||||
active: getLocalConfig("THEME_COLOR") || "green",
|
active: getLocalConfig("THEME_COLOR") || "green",
|
||||||
confirmRemove: false,
|
confirmRemove: false,
|
||||||
|
|
||||||
TELEMETRY_ENABLED: null,
|
|
||||||
|
|
||||||
SHORTCUTS_INDICATOR_ENABLED: null,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
subscriptions() {
|
|
||||||
return {
|
|
||||||
SCROLL_INTO_ENABLED: getSettingSubject("SCROLL_INTO_ENABLED"),
|
|
||||||
|
|
||||||
PROXY_ENABLED: getSettingSubject("PROXY_ENABLED"),
|
|
||||||
PROXY_URL: getSettingSubject("PROXY_URL"),
|
|
||||||
PROXY_KEY: getSettingSubject("PROXY_KEY"),
|
|
||||||
|
|
||||||
EXTENSIONS_ENABLED: getSettingSubject("EXTENSIONS_ENABLED"),
|
|
||||||
|
|
||||||
EXPERIMENTAL_URL_BAR_ENABLED: getSettingSubject(
|
|
||||||
"EXPERIMENTAL_URL_BAR_ENABLED"
|
|
||||||
),
|
|
||||||
|
|
||||||
SYNC_COLLECTIONS: getSettingSubject("syncCollections"),
|
|
||||||
SYNC_ENVIRONMENTS: getSettingSubject("syncEnvironments"),
|
|
||||||
SYNC_HISTORY: getSettingSubject("syncHistory"),
|
|
||||||
|
|
||||||
TELEMETRY_ENABLED: getSettingSubject("TELEMETRY_ENABLED"),
|
|
||||||
SHORTCUTS_INDICATOR_ENABLED: getSettingSubject(
|
|
||||||
"SHORTCUTS_INDICATOR_ENABLED"
|
|
||||||
),
|
|
||||||
|
|
||||||
currentUser: currentUser$,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
head() {
|
head() {
|
||||||
@@ -421,7 +406,7 @@ export default Vue.extend({
|
|||||||
resetProxy() {
|
resetProxy() {
|
||||||
applySetting("PROXY_URL", `https://proxy.hoppscotch.io/`)
|
applySetting("PROXY_URL", `https://proxy.hoppscotch.io/`)
|
||||||
this.clearIcon = "done"
|
this.clearIcon = "done"
|
||||||
this.$toast.info(this.$t("cleared"), {
|
this.$toast.info(this.$t("cleared").toString(), {
|
||||||
icon: "clear_all",
|
icon: "clear_all",
|
||||||
})
|
})
|
||||||
setTimeout(() => (this.clearIcon = "clear_all"), 1000)
|
setTimeout(() => (this.clearIcon = "clear_all"), 1000)
|
||||||
|
|||||||
Reference in New Issue
Block a user