diff --git a/packages/hoppscotch-backend/package.json b/packages/hoppscotch-backend/package.json index 6d9c57df7..789e345f7 100644 --- a/packages/hoppscotch-backend/package.json +++ b/packages/hoppscotch-backend/package.json @@ -1,6 +1,6 @@ { "name": "hoppscotch-backend", - "version": "2024.10.1", + "version": "2024.10.2", "description": "", "author": "", "private": true, diff --git a/packages/hoppscotch-common/locales/en.json b/packages/hoppscotch-common/locales/en.json index 6c9ca16ae..f72388ac0 100644 --- a/packages/hoppscotch-common/locales/en.json +++ b/packages/hoppscotch-common/locales/en.json @@ -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", diff --git a/packages/hoppscotch-common/package.json b/packages/hoppscotch-common/package.json index 0a7748d45..51e3be7c5 100644 --- a/packages/hoppscotch-common/package.json +++ b/packages/hoppscotch-common/package.json @@ -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", diff --git a/packages/hoppscotch-common/src/components/graphql/RequestOptions.vue b/packages/hoppscotch-common/src/components/graphql/RequestOptions.vue index afadb96ae..a224174fc 100644 --- a/packages/hoppscotch-common/src/components/graphql/RequestOptions.vue +++ b/packages/hoppscotch-common/src/components/graphql/RequestOptions.vue @@ -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", diff --git a/packages/hoppscotch-common/src/helpers/graphql/connection.ts b/packages/hoppscotch-common/src/helpers/graphql/connection.ts index b5666e990..abf797306 100644 --- a/packages/hoppscotch-common/src/helpers/graphql/connection.ts +++ b/packages/hoppscotch-common/src/helpers/graphql/connection.ts @@ -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() 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) => + 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 } = diff --git a/packages/hoppscotch-common/src/pages/graphql.vue b/packages/hoppscotch-common/src/pages/graphql.vue index 8bdffb800..fa3325cbe 100644 --- a/packages/hoppscotch-common/src/pages/graphql.vue +++ b/packages/hoppscotch-common/src/pages/graphql.vue @@ -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) diff --git a/packages/hoppscotch-selfhost-desktop/package.json b/packages/hoppscotch-selfhost-desktop/package.json index 31e0bcc66..2d2dfd821 100644 --- a/packages/hoppscotch-selfhost-desktop/package.json +++ b/packages/hoppscotch-selfhost-desktop/package.json @@ -1,7 +1,7 @@ { "name": "@hoppscotch/selfhost-desktop", "private": true, - "version": "2024.10.1", + "version": "2024.10.2", "type": "module", "scripts": { "dev:vite": "vite", diff --git a/packages/hoppscotch-selfhost-desktop/src-tauri/Cargo.lock b/packages/hoppscotch-selfhost-desktop/src-tauri/Cargo.lock index 347218710..82eee473b 100644 --- a/packages/hoppscotch-selfhost-desktop/src-tauri/Cargo.lock +++ b/packages/hoppscotch-selfhost-desktop/src-tauri/Cargo.lock @@ -1417,7 +1417,7 @@ dependencies = [ [[package]] name = "hoppscotch-desktop" -version = "24.10.1" +version = "24.10.2" dependencies = [ "cocoa 0.25.0", "dashmap", diff --git a/packages/hoppscotch-selfhost-desktop/src-tauri/Cargo.toml b/packages/hoppscotch-selfhost-desktop/src-tauri/Cargo.toml index ec2539656..3feb24420 100644 --- a/packages/hoppscotch-selfhost-desktop/src-tauri/Cargo.toml +++ b/packages/hoppscotch-selfhost-desktop/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hoppscotch-desktop" -version = "24.10.1" +version = "24.10.2" description = "A Tauri App" authors = ["you"] license = "" diff --git a/packages/hoppscotch-selfhost-desktop/src-tauri/tauri.conf.json b/packages/hoppscotch-selfhost-desktop/src-tauri/tauri.conf.json index 5ea78e53e..248aee01a 100644 --- a/packages/hoppscotch-selfhost-desktop/src-tauri/tauri.conf.json +++ b/packages/hoppscotch-selfhost-desktop/src-tauri/tauri.conf.json @@ -8,7 +8,7 @@ }, "package": { "productName": "Hoppscotch", - "version": "24.10.1" + "version": "24.10.2" }, "tauri": { "allowlist": { diff --git a/packages/hoppscotch-selfhost-web/package.json b/packages/hoppscotch-selfhost-web/package.json index 0da34be46..7b4cdd090 100644 --- a/packages/hoppscotch-selfhost-web/package.json +++ b/packages/hoppscotch-selfhost-web/package.json @@ -1,7 +1,7 @@ { "name": "@hoppscotch/selfhost-web", "private": true, - "version": "2024.10.1", + "version": "2024.10.2", "type": "module", "scripts": { "dev:vite": "vite", diff --git a/packages/hoppscotch-sh-admin/package.json b/packages/hoppscotch-sh-admin/package.json index 7b2009b5e..48051560c 100644 --- a/packages/hoppscotch-sh-admin/package.json +++ b/packages/hoppscotch-sh-admin/package.json @@ -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:*",