chore: merge hoppscotch/main into hoppscotch/next
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hoppscotch-backend",
|
||||
"version": "2024.10.1",
|
||||
"version": "2024.10.2",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
|
||||
@@ -452,6 +452,7 @@
|
||||
},
|
||||
"graphql": {
|
||||
"connection_switch_confirm": "Do you want to connect with the latest GraphQL endpoint?",
|
||||
"connection_error_http": "Failed to fetch GraphQL Schema due to network error.",
|
||||
"connection_switch_new_url": "Switching to a tab will disconnected you from the active GraphQL connection. New connection URL is",
|
||||
"connection_switch_url": "You're connected to a GraphQL endpoint the connection URL is",
|
||||
"mutations": "Mutations",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@hoppscotch/common",
|
||||
"private": true,
|
||||
"version": "2024.10.1",
|
||||
"version": "2024.10.2",
|
||||
"scripts": {
|
||||
"dev": "pnpm exec npm-run-all -p -l dev:*",
|
||||
"test": "vitest --run",
|
||||
|
||||
@@ -224,7 +224,10 @@ watch(
|
||||
watch(
|
||||
() => connection,
|
||||
(newVal) => {
|
||||
if (newVal.error && newVal.state === "DISCONNECTED") {
|
||||
if (
|
||||
newVal.error &&
|
||||
(newVal.state === "DISCONNECTED" || newVal.state === "ERROR")
|
||||
) {
|
||||
const response = [
|
||||
{
|
||||
type: "error",
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
printSchema,
|
||||
} from "graphql"
|
||||
import { Component, computed, reactive, ref } from "vue"
|
||||
import { useToast } from "~/composables/toast"
|
||||
import { getService } from "~/modules/dioc"
|
||||
import { getI18n } from "~/modules/i18n"
|
||||
|
||||
@@ -52,7 +53,11 @@ export type GQLResponseEvent =
|
||||
}
|
||||
}
|
||||
|
||||
export type ConnectionState = "CONNECTING" | "CONNECTED" | "DISCONNECTED"
|
||||
export type ConnectionState =
|
||||
| "CONNECTING"
|
||||
| "CONNECTED"
|
||||
| "DISCONNECTED"
|
||||
| "ERROR"
|
||||
export type SubscriptionState = "SUBSCRIBING" | "SUBSCRIBED" | "UNSUBSCRIBED"
|
||||
|
||||
const GQL = {
|
||||
@@ -100,10 +105,7 @@ export const gqlMessageEvent = ref<GQLResponseEvent | "reset">()
|
||||
|
||||
export const schemaString = computed(() => {
|
||||
if (!connection.schema) return ""
|
||||
|
||||
return printSchema(connection.schema, {
|
||||
commentDescriptions: true,
|
||||
})
|
||||
return printSchema(connection.schema)
|
||||
})
|
||||
|
||||
export const queryFields = computed(() => {
|
||||
@@ -159,21 +161,40 @@ export const graphqlTypes = computed(() => {
|
||||
|
||||
let timeoutSubscription: any
|
||||
|
||||
export const connect = async (url: string, headers: GQLHeader[]) => {
|
||||
export const connect = async (
|
||||
url: string,
|
||||
headers: GQLHeader[],
|
||||
isRunGQLOperation = false
|
||||
) => {
|
||||
if (connection.state === "CONNECTED") {
|
||||
throw new Error(
|
||||
"A connection is already running. Close it before starting another."
|
||||
)
|
||||
}
|
||||
|
||||
// Polling
|
||||
connection.state = "CONNECTED"
|
||||
const toast = useToast()
|
||||
const t = getI18n()
|
||||
|
||||
connection.state = "CONNECTING"
|
||||
|
||||
const poll = async () => {
|
||||
await getSchema(url, headers)
|
||||
timeoutSubscription = setTimeout(() => {
|
||||
poll()
|
||||
}, GQL_SCHEMA_POLL_INTERVAL)
|
||||
try {
|
||||
await getSchema(url, headers)
|
||||
// polling for schema
|
||||
if (connection.state !== "CONNECTED") connection.state = "CONNECTED"
|
||||
timeoutSubscription = setTimeout(() => {
|
||||
poll()
|
||||
}, GQL_SCHEMA_POLL_INTERVAL)
|
||||
} catch (error) {
|
||||
connection.state = "ERROR"
|
||||
|
||||
// Show an error toast if the introspection attempt failed and not while sending a request
|
||||
if (!isRunGQLOperation) {
|
||||
toast.error(t("graphql.connection_error_http"))
|
||||
}
|
||||
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
await poll()
|
||||
@@ -221,6 +242,8 @@ const getSchema = async (url: string, headers: GQLHeader[]) => {
|
||||
const res = await interceptorService.runRequest(reqOptions).response
|
||||
|
||||
if (E.isLeft(res)) {
|
||||
connection.state = "ERROR"
|
||||
|
||||
if (
|
||||
res.left !== "cancellation" &&
|
||||
res.left.error === "NO_PW_EXT_HOOK" &&
|
||||
@@ -237,6 +260,17 @@ const getSchema = async (url: string, headers: GQLHeader[]) => {
|
||||
throw new Error(res.left.toString())
|
||||
}
|
||||
|
||||
if (res.right.status !== 200) {
|
||||
connection.state = "ERROR"
|
||||
connection.error = {
|
||||
type: "HTTP_ERROR",
|
||||
message: (t: ReturnType<typeof getI18n>) =>
|
||||
t("graphql.connection_error_http"),
|
||||
component: undefined,
|
||||
}
|
||||
throw new Error("Failed to fetch schema. Status: " + res.right.status)
|
||||
}
|
||||
|
||||
const data = res.right
|
||||
|
||||
// HACK : Temporary trailing null character issue from the extension fix
|
||||
@@ -258,7 +292,7 @@ const getSchema = async (url: string, headers: GQLHeader[]) => {
|
||||
|
||||
export const runGQLOperation = async (options: RunQueryOptions) => {
|
||||
if (connection.state !== "CONNECTED") {
|
||||
await connect(options.url, options.headers)
|
||||
await connect(options.url, options.headers, true)
|
||||
}
|
||||
|
||||
const { url, headers, query, variables, auth, operationName, operationType } =
|
||||
|
||||
@@ -87,7 +87,8 @@
|
||||
import { usePageHead } from "@composables/head"
|
||||
import { useI18n } from "@composables/i18n"
|
||||
import { useService } from "dioc/vue"
|
||||
import { computed, onBeforeUnmount, ref } from "vue"
|
||||
import { computed, onBeforeUnmount, ref, watch } from "vue"
|
||||
import { useToast } from "~/composables/toast"
|
||||
import { defineActionHandler } from "~/helpers/actions"
|
||||
import { connection, disconnect } from "~/helpers/graphql/connection"
|
||||
import { getDefaultGQLRequest } from "~/helpers/graphql/default"
|
||||
@@ -97,6 +98,7 @@ import { HoppTab } from "~/services/tab"
|
||||
import { GQLTabService } from "~/services/tab/graphql"
|
||||
|
||||
const t = useI18n()
|
||||
const toast = useToast()
|
||||
const tabs = useService(GQLTabService)
|
||||
|
||||
const currentTabID = computed(() => tabs.currentTabID.value)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@hoppscotch/selfhost-desktop",
|
||||
"private": true,
|
||||
"version": "2024.10.1",
|
||||
"version": "2024.10.2",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev:vite": "vite",
|
||||
|
||||
@@ -1417,7 +1417,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hoppscotch-desktop"
|
||||
version = "24.10.1"
|
||||
version = "24.10.2"
|
||||
dependencies = [
|
||||
"cocoa 0.25.0",
|
||||
"dashmap",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "hoppscotch-desktop"
|
||||
version = "24.10.1"
|
||||
version = "24.10.2"
|
||||
description = "A Tauri App"
|
||||
authors = ["you"]
|
||||
license = ""
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
},
|
||||
"package": {
|
||||
"productName": "Hoppscotch",
|
||||
"version": "24.10.1"
|
||||
"version": "24.10.2"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@hoppscotch/selfhost-web",
|
||||
"private": true,
|
||||
"version": "2024.10.1",
|
||||
"version": "2024.10.2",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev:vite": "vite",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "hoppscotch-sh-admin",
|
||||
"private": true,
|
||||
"version": "2024.10.1",
|
||||
"version": "2024.10.2",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "pnpm exec npm-run-all -p -l dev:*",
|
||||
|
||||
Reference in New Issue
Block a user