fix: inspections bugs (#3277)
* fix: environment add bug in inspection * chore: add 127.0.0.1 in url inspection * chore: update browserextension inspection help url * fix: team env not showing bug in selector * chore: rework inspector systems to be reactive * chore: handling tab changes gracefully * refactor: move out url interceptor from the platform * chore: add view function in inspector service to get views into the list * fix: interceptors not kicking in on initial load * fix: don't show no internet connection error unless browser deems so * chore: fix tests --------- Co-authored-by: Andrew Bastin <andrewbastin.k@gmail.com>
This commit is contained in:
@@ -21,7 +21,12 @@
|
||||
<label for="value" class="font-semibold min-w-10">{{
|
||||
t("environment.value")
|
||||
}}</label>
|
||||
<input type="text" :value="value" class="input" />
|
||||
<input
|
||||
v-model="editingValue"
|
||||
type="text"
|
||||
class="input"
|
||||
:placeholder="t('environment.value')"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center space-x-8 ml-2">
|
||||
<label for="scope" class="font-semibold min-w-10">
|
||||
@@ -105,9 +110,12 @@ watch(
|
||||
scope.value = {
|
||||
type: "global",
|
||||
}
|
||||
editingName.value = ""
|
||||
replaceWithVariable.value = false
|
||||
editingName.value = ""
|
||||
editingValue.value = ""
|
||||
}
|
||||
editingName.value = props.name
|
||||
editingValue.value = props.value
|
||||
}
|
||||
)
|
||||
|
||||
@@ -132,6 +140,7 @@ const scope = ref<Scope>({
|
||||
const replaceWithVariable = ref(false)
|
||||
|
||||
const editingName = ref(props.name)
|
||||
const editingValue = ref(props.value)
|
||||
|
||||
const addEnvironment = async () => {
|
||||
if (!editingName.value) {
|
||||
@@ -141,13 +150,13 @@ const addEnvironment = async () => {
|
||||
if (scope.value.type === "global") {
|
||||
addGlobalEnvVariable({
|
||||
key: editingName.value,
|
||||
value: props.value,
|
||||
value: editingValue.value,
|
||||
})
|
||||
toast.success(`${t("environment.updated")}`)
|
||||
} else if (scope.value.type === "my-environment") {
|
||||
addEnvironmentVariable(scope.value.index, {
|
||||
key: editingName.value,
|
||||
value: props.value,
|
||||
value: editingValue.value,
|
||||
})
|
||||
toast.success(`${t("environment.updated")}`)
|
||||
} else {
|
||||
@@ -155,7 +164,7 @@ const addEnvironment = async () => {
|
||||
...scope.value.environment.environment.variables,
|
||||
{
|
||||
key: editingName.value,
|
||||
value: props.value,
|
||||
value: editingValue.value,
|
||||
},
|
||||
]
|
||||
await pipe(
|
||||
@@ -182,7 +191,7 @@ const addEnvironment = async () => {
|
||||
//replace the currenttab endpoint containing the value in the text with variablename
|
||||
currentActiveTab.value.document.request.endpoint =
|
||||
currentActiveTab.value.document.request.endpoint.replace(
|
||||
props.value,
|
||||
editingValue.value,
|
||||
variableName
|
||||
)
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
@keyup.escape="hide()"
|
||||
>
|
||||
<HoppSmartItem
|
||||
v-if="!isScopeSelector"
|
||||
:label="`${t('environment.no_environment')}`"
|
||||
:info-icon="
|
||||
selectedEnvironmentIndex.type === 'NO_ENV_SELECTED'
|
||||
@@ -48,6 +49,21 @@
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartItem
|
||||
v-else-if="isScopeSelector && modelValue"
|
||||
:label="t('environment.global')"
|
||||
:icon="IconGlobe"
|
||||
:info-icon="modelValue.type === 'global' ? IconCheck : undefined"
|
||||
:active-info-icon="modelValue.type === 'global'"
|
||||
@click="
|
||||
() => {
|
||||
$emit('update:modelValue', {
|
||||
type: 'global',
|
||||
})
|
||||
hide()
|
||||
}
|
||||
"
|
||||
/>
|
||||
<HoppSmartTabs
|
||||
v-model="selectedEnvTab"
|
||||
:styles="`sticky overflow-x-auto my-2 border border-divider rounded flex-shrink-0 z-0 top-0 bg-primary ${
|
||||
@@ -66,14 +82,14 @@
|
||||
:key="`gen-${index}`"
|
||||
:icon="IconLayers"
|
||||
:label="gen.name"
|
||||
:info-icon="index === selectedEnv.index ? IconCheck : undefined"
|
||||
:active-info-icon="index === selectedEnv.index"
|
||||
:info-icon="isEnvActive(index) ? IconCheck : undefined"
|
||||
:active-info-icon="isEnvActive(index)"
|
||||
@click="
|
||||
() => {
|
||||
selectedEnvironmentIndex = {
|
||||
type: 'MY_ENV',
|
||||
index: index,
|
||||
}
|
||||
handleEnvironmentChange(index, {
|
||||
type: 'my-environment',
|
||||
environment: gen,
|
||||
})
|
||||
hide()
|
||||
}
|
||||
"
|
||||
@@ -113,18 +129,14 @@
|
||||
:key="`gen-team-${index}`"
|
||||
:icon="IconLayers"
|
||||
:label="gen.environment.name"
|
||||
:info-icon="
|
||||
gen.id === selectedEnv.teamEnvID ? IconCheck : undefined
|
||||
"
|
||||
:active-info-icon="gen.id === selectedEnv.teamEnvID"
|
||||
:info-icon="isEnvActive(gen.id) ? IconCheck : undefined"
|
||||
:active-info-icon="isEnvActive(gen.id)"
|
||||
@click="
|
||||
() => {
|
||||
selectedEnvironmentIndex = {
|
||||
type: 'TEAM_ENV',
|
||||
teamEnvID: gen.id,
|
||||
teamID: gen.teamID,
|
||||
environment: gen.environment,
|
||||
}
|
||||
handleEnvironmentChange(index, {
|
||||
type: 'team-environment',
|
||||
environment: gen,
|
||||
})
|
||||
hide()
|
||||
}
|
||||
"
|
||||
@@ -285,6 +297,7 @@ import IconCheck from "~icons/lucide/check"
|
||||
import IconLayers from "~icons/lucide/layers"
|
||||
import IconEye from "~icons/lucide/eye"
|
||||
import IconEdit from "~icons/lucide/edit"
|
||||
import IconGlobe from "~icons/lucide/globe"
|
||||
import { TippyComponent } from "vue-tippy"
|
||||
import { useI18n } from "~/composables/i18n"
|
||||
import { GQLError } from "~/helpers/backend/GQLClient"
|
||||
@@ -295,11 +308,39 @@ import {
|
||||
selectedEnvironmentIndex$,
|
||||
setSelectedEnvironmentIndex,
|
||||
} from "~/newstore/environments"
|
||||
import { workspaceStatus$ } from "~/newstore/workspace"
|
||||
import { changeWorkspace, workspaceStatus$ } from "~/newstore/workspace"
|
||||
import TeamEnvironmentAdapter from "~/helpers/teams/TeamEnvironmentAdapter"
|
||||
import { useColorMode } from "@composables/theming"
|
||||
import { breakpointsTailwind, useBreakpoints } from "@vueuse/core"
|
||||
import { invokeAction } from "~/helpers/actions"
|
||||
import { TeamEnvironment } from "~/helpers/teams/TeamEnvironment"
|
||||
import { Environment } from "@hoppscotch/data"
|
||||
import { onMounted } from "vue"
|
||||
import { onLoggedIn } from "~/composables/auth"
|
||||
import TeamListAdapter from "~/helpers/teams/TeamListAdapter"
|
||||
import { useLocalState } from "~/newstore/localstate"
|
||||
import { GetMyTeamsQuery } from "~/helpers/backend/graphql"
|
||||
|
||||
type Scope =
|
||||
| {
|
||||
type: "global"
|
||||
}
|
||||
| {
|
||||
type: "my-environment"
|
||||
environment: Environment
|
||||
index: number
|
||||
}
|
||||
| {
|
||||
type: "team-environment"
|
||||
environment: TeamEnvironment
|
||||
}
|
||||
const props = defineProps<{
|
||||
isScopeSelector?: boolean
|
||||
modelValue?: Scope
|
||||
}>()
|
||||
const emit = defineEmits<{
|
||||
(e: "update:modelValue", data: Scope): void
|
||||
}>()
|
||||
|
||||
const breakpoints = useBreakpoints(breakpointsTailwind)
|
||||
const mdAndLarger = breakpoints.greater("md")
|
||||
@@ -314,6 +355,38 @@ const myEnvironments = useReadonlyStream(environments$, [])
|
||||
|
||||
const workspace = useReadonlyStream(workspaceStatus$, { type: "personal" })
|
||||
|
||||
// TeamList-Adapter
|
||||
const teamListAdapter = new TeamListAdapter(true)
|
||||
const myTeams = useReadonlyStream(teamListAdapter.teamList$, null)
|
||||
const teamListFetched = ref(false)
|
||||
const REMEMBERED_TEAM_ID = useLocalState("REMEMBERED_TEAM_ID")
|
||||
|
||||
onLoggedIn(() => {
|
||||
!teamListAdapter.isInitialized && teamListAdapter.initialize()
|
||||
})
|
||||
|
||||
const switchToTeamWorkspace = (team: GetMyTeamsQuery["myTeams"][number]) => {
|
||||
REMEMBERED_TEAM_ID.value = team.id
|
||||
changeWorkspace({
|
||||
teamID: team.id,
|
||||
teamName: team.name,
|
||||
type: "team",
|
||||
})
|
||||
}
|
||||
watch(
|
||||
() => myTeams.value,
|
||||
(newTeams) => {
|
||||
if (newTeams && !teamListFetched.value) {
|
||||
teamListFetched.value = true
|
||||
if (REMEMBERED_TEAM_ID.value) {
|
||||
const team = newTeams.find((t) => t.id === REMEMBERED_TEAM_ID.value)
|
||||
if (team) switchToTeamWorkspace(team)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// TeamEnv List Adapter
|
||||
const teamEnvListAdapter = new TeamEnvironmentAdapter(undefined)
|
||||
const teamListLoading = useReadonlyStream(teamEnvListAdapter.loading$, false)
|
||||
const teamAdapterError = useReadonlyStream(teamEnvListAdapter.error$, null)
|
||||
@@ -322,6 +395,70 @@ const teamEnvironmentList = useReadonlyStream(
|
||||
[]
|
||||
)
|
||||
|
||||
const handleEnvironmentChange = (
|
||||
index: number,
|
||||
env?:
|
||||
| {
|
||||
type: "my-environment"
|
||||
environment: Environment
|
||||
}
|
||||
| {
|
||||
type: "team-environment"
|
||||
environment: TeamEnvironment
|
||||
}
|
||||
) => {
|
||||
if (props.isScopeSelector && env) {
|
||||
if (env.type === "my-environment") {
|
||||
emit("update:modelValue", {
|
||||
type: "my-environment",
|
||||
environment: env.environment,
|
||||
index,
|
||||
})
|
||||
} else if (env.type === "team-environment") {
|
||||
emit("update:modelValue", {
|
||||
type: "team-environment",
|
||||
environment: env.environment,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if (env && env.type === "my-environment") {
|
||||
selectedEnvironmentIndex.value = {
|
||||
type: "MY_ENV",
|
||||
index,
|
||||
}
|
||||
} else if (env && env.type === "team-environment") {
|
||||
selectedEnvironmentIndex.value = {
|
||||
type: "TEAM_ENV",
|
||||
teamEnvID: env.environment.id,
|
||||
teamID: env.environment.teamID,
|
||||
environment: env.environment.environment,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const isEnvActive = (id: string | number) => {
|
||||
if (props.isScopeSelector) {
|
||||
if (props.modelValue?.type === "my-environment") {
|
||||
return props.modelValue.index === id
|
||||
} else if (props.modelValue?.type === "team-environment") {
|
||||
return (
|
||||
props.modelValue?.type === "team-environment" &&
|
||||
props.modelValue.environment &&
|
||||
props.modelValue.environment.id === id
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if (selectedEnvironmentIndex.value.type === "MY_ENV") {
|
||||
return selectedEnv.value.index === id
|
||||
} else {
|
||||
return (
|
||||
selectedEnvironmentIndex.value.type === "TEAM_ENV" &&
|
||||
selectedEnv.value.teamEnvID === id
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const selectedEnvironmentIndex = useStream(
|
||||
selectedEnvironmentIndex$,
|
||||
{ type: "NO_ENV_SELECTED" },
|
||||
@@ -349,34 +486,90 @@ watch(
|
||||
)
|
||||
|
||||
const selectedEnv = computed(() => {
|
||||
if (selectedEnvironmentIndex.value.type === "MY_ENV") {
|
||||
const environment =
|
||||
myEnvironments.value[selectedEnvironmentIndex.value.index]
|
||||
return {
|
||||
type: "MY_ENV",
|
||||
index: selectedEnvironmentIndex.value.index,
|
||||
name: environment.name,
|
||||
variables: environment.variables,
|
||||
}
|
||||
} else if (selectedEnvironmentIndex.value.type === "TEAM_ENV") {
|
||||
const teamEnv = teamEnvironmentList.value.find(
|
||||
(env) =>
|
||||
env.id ===
|
||||
(selectedEnvironmentIndex.value.type === "TEAM_ENV" &&
|
||||
selectedEnvironmentIndex.value.teamEnvID)
|
||||
)
|
||||
if (teamEnv) {
|
||||
if (props.isScopeSelector) {
|
||||
if (props.modelValue?.type === "my-environment") {
|
||||
return {
|
||||
type: "MY_ENV",
|
||||
index: props.modelValue.index,
|
||||
name: props.modelValue.environment?.name,
|
||||
}
|
||||
} else if (props.modelValue?.type === "team-environment") {
|
||||
return {
|
||||
type: "TEAM_ENV",
|
||||
name: teamEnv.environment.name,
|
||||
teamEnvID: selectedEnvironmentIndex.value.teamEnvID,
|
||||
variables: teamEnv.environment.variables,
|
||||
name: props.modelValue.environment.environment.name,
|
||||
teamEnvID: props.modelValue.environment.id,
|
||||
}
|
||||
} else {
|
||||
return { type: "global", name: "Global" }
|
||||
}
|
||||
} else {
|
||||
if (selectedEnvironmentIndex.value.type === "MY_ENV") {
|
||||
const environment =
|
||||
myEnvironments.value[selectedEnvironmentIndex.value.index]
|
||||
return {
|
||||
type: "MY_ENV",
|
||||
index: selectedEnvironmentIndex.value.index,
|
||||
name: environment.name,
|
||||
variables: environment.variables,
|
||||
}
|
||||
} else if (selectedEnvironmentIndex.value.type === "TEAM_ENV") {
|
||||
const teamEnv = teamEnvironmentList.value.find(
|
||||
(env) =>
|
||||
env.id ===
|
||||
(selectedEnvironmentIndex.value.type === "TEAM_ENV" &&
|
||||
selectedEnvironmentIndex.value.teamEnvID)
|
||||
)
|
||||
if (teamEnv) {
|
||||
return {
|
||||
type: "TEAM_ENV",
|
||||
name: teamEnv.environment.name,
|
||||
teamEnvID: selectedEnvironmentIndex.value.teamEnvID,
|
||||
variables: teamEnv.environment.variables,
|
||||
}
|
||||
} else {
|
||||
return { type: "NO_ENV_SELECTED" }
|
||||
}
|
||||
} else {
|
||||
return { type: "NO_ENV_SELECTED" }
|
||||
}
|
||||
} else {
|
||||
return { type: "NO_ENV_SELECTED" }
|
||||
}
|
||||
})
|
||||
|
||||
// Set the selected environment as initial scope value
|
||||
onMounted(() => {
|
||||
if (props.isScopeSelector) {
|
||||
if (
|
||||
selectedEnvironmentIndex.value.type === "MY_ENV" &&
|
||||
selectedEnvironmentIndex.value.index !== undefined
|
||||
) {
|
||||
emit("update:modelValue", {
|
||||
type: "my-environment",
|
||||
environment: myEnvironments.value[selectedEnvironmentIndex.value.index],
|
||||
index: selectedEnvironmentIndex.value.index,
|
||||
})
|
||||
} else if (
|
||||
selectedEnvironmentIndex.value.type === "TEAM_ENV" &&
|
||||
selectedEnvironmentIndex.value.teamEnvID &&
|
||||
teamEnvironmentList.value &&
|
||||
teamEnvironmentList.value.length > 0
|
||||
) {
|
||||
const teamEnv = teamEnvironmentList.value.find(
|
||||
(env) =>
|
||||
env.id ===
|
||||
(selectedEnvironmentIndex.value.type === "TEAM_ENV" &&
|
||||
selectedEnvironmentIndex.value.teamEnvID)
|
||||
)
|
||||
if (teamEnv) {
|
||||
emit("update:modelValue", {
|
||||
type: "team-environment",
|
||||
environment: teamEnv,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
emit("update:modelValue", {
|
||||
type: "global",
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -300,7 +300,7 @@ watch(
|
||||
|
||||
defineActionHandler("modals.environment.add", ({ envName, variableName }) => {
|
||||
editingVariableName.value = envName
|
||||
editingVariableValue.value = variableName
|
||||
if (variableName) editingVariableValue.value = variableName
|
||||
displayModalNew(true)
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -508,30 +508,17 @@ const changeTab = (tab: ComputedHeader["source"]) => {
|
||||
|
||||
const inspectionService = useService(InspectionService)
|
||||
|
||||
const allTabResults = inspectionService.tabs
|
||||
const headerKeyResults = inspectionService.getResultViewFor(
|
||||
currentTabID.value,
|
||||
(result) =>
|
||||
result.locations.type === "header" && result.locations.position === "key"
|
||||
)
|
||||
|
||||
const headerKeyResults = computed(() => {
|
||||
return (
|
||||
allTabResults.value
|
||||
.get(currentTabID.value)
|
||||
.filter(
|
||||
(result) =>
|
||||
result.locations.type === "header" &&
|
||||
result.locations.position === "key"
|
||||
) ?? []
|
||||
)
|
||||
})
|
||||
const headerValueResults = computed(() => {
|
||||
return (
|
||||
allTabResults.value
|
||||
.get(currentTabID.value)
|
||||
.filter(
|
||||
(result) =>
|
||||
result.locations.type === "header" &&
|
||||
result.locations.position === "value"
|
||||
) ?? []
|
||||
)
|
||||
})
|
||||
const headerValueResults = inspectionService.getResultViewFor(
|
||||
currentTabID.value,
|
||||
(result) =>
|
||||
result.locations.type === "header" && result.locations.position === "value"
|
||||
)
|
||||
|
||||
const getInspectorResult = (results: InspectorResult[], index: number) => {
|
||||
return results.filter((result) => {
|
||||
|
||||
@@ -178,7 +178,7 @@ import IconCheckCircle from "~icons/lucide/check-circle"
|
||||
import IconCircle from "~icons/lucide/circle"
|
||||
import IconTrash from "~icons/lucide/trash"
|
||||
import IconWrapText from "~icons/lucide/wrap-text"
|
||||
import { computed, reactive, ref, watch } from "vue"
|
||||
import { reactive, ref, watch } from "vue"
|
||||
import { flow, pipe } from "fp-ts/function"
|
||||
import * as O from "fp-ts/Option"
|
||||
import * as A from "fp-ts/Array"
|
||||
@@ -409,30 +409,18 @@ const clearContent = () => {
|
||||
|
||||
const inspectionService = useService(InspectionService)
|
||||
|
||||
const allTabResults = inspectionService.tabs
|
||||
const parameterKeyResults = inspectionService.getResultViewFor(
|
||||
currentTabID.value,
|
||||
(result) =>
|
||||
result.locations.type === "parameter" && result.locations.position === "key"
|
||||
)
|
||||
|
||||
const parameterKeyResults = computed(() => {
|
||||
return (
|
||||
allTabResults.value
|
||||
.get(currentTabID.value)
|
||||
.filter(
|
||||
(result) =>
|
||||
result.locations.type === "parameter" &&
|
||||
result.locations.position === "key"
|
||||
) ?? []
|
||||
)
|
||||
})
|
||||
const parameterValueResults = computed(() => {
|
||||
return (
|
||||
allTabResults.value
|
||||
.get(currentTabID.value)
|
||||
.filter(
|
||||
(result) =>
|
||||
result.locations.type === "parameter" &&
|
||||
result.locations.position === "value"
|
||||
) ?? []
|
||||
)
|
||||
})
|
||||
const parameterValueResults = inspectionService.getResultViewFor(
|
||||
currentTabID.value,
|
||||
(result) =>
|
||||
result.locations.type === "parameter" &&
|
||||
result.locations.position === "value"
|
||||
)
|
||||
|
||||
const getInspectorResult = (results: InspectorResult[], index: number) => {
|
||||
return results.filter((result) => {
|
||||
|
||||
@@ -642,9 +642,5 @@ const COLUMN_LAYOUT = useSetting("COLUMN_LAYOUT")
|
||||
|
||||
const inspectionService = useService(InspectionService)
|
||||
|
||||
const allTabResults = inspectionService.tabs
|
||||
|
||||
const tabResults = computed(() => {
|
||||
return allTabResults.value.get(currentTabID.value) ?? []
|
||||
})
|
||||
const tabResults = inspectionService.getResultViewFor(currentTabID.value)
|
||||
</script>
|
||||
|
||||
@@ -145,13 +145,8 @@ const statusCategory = computed(() => {
|
||||
|
||||
const inspectionService = useService(InspectionService)
|
||||
|
||||
const allTabResults = inspectionService.tabs
|
||||
|
||||
const tabResults = computed(() => {
|
||||
return (
|
||||
allTabResults.value
|
||||
.get(currentTabID.value)
|
||||
?.filter((result) => result.locations.type === "response") ?? []
|
||||
)
|
||||
})
|
||||
const tabResults = inspectionService.getResultViewFor(
|
||||
currentTabID.value,
|
||||
(result) => result.locations.type === "response"
|
||||
)
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user