refactor(common): route mock server and published docs operations through platform backend (#6036)

This commit is contained in:
Nivedin 2026-03-26 00:41:36 +05:30 committed by GitHub
parent 59c1b595a6
commit f690d5969a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 220 additions and 158 deletions

View file

@ -300,11 +300,7 @@ import {
CreatePublishedDocsArgs,
UpdatePublishedDocsArgs,
} from "~/helpers/backend/graphql"
import {
createPublishedDoc,
deletePublishedDoc,
updatePublishedDoc,
} from "~/helpers/backend/mutations/PublishedDocs"
import { platform } from "~/platform"
import * as E from "fp-ts/Either"
import * as TE from "fp-ts/TaskEither"
@ -976,7 +972,7 @@ const handlePublish = async (
}
await pipe(
createPublishedDoc(doc),
platform.backend.createPublishedDoc(doc),
TE.match(
(error) => {
console.error("Error publishing documentation:", error)
@ -1032,7 +1028,7 @@ const handleUpdate = async (
}
await pipe(
updatePublishedDoc(id, doc),
platform.backend.updatePublishedDoc(id, doc),
TE.match(
(error) => {
console.error("Error updating documentation:", error)
@ -1077,7 +1073,7 @@ const handleDelete = async () => {
isProcessingPublish.value = true
await pipe(
deletePublishedDoc(publishedDocId.value),
platform.backend.deletePublishedDoc(publishedDocId.value),
TE.match(
(error) => {
console.error("Error deleting documentation:", error)

View file

@ -195,7 +195,7 @@ import { useReadonlyStream } from "@composables/stream"
import { useToast } from "@composables/toast"
import { refAutoReset } from "@vueuse/core"
import { computed, ref, watch } from "vue"
import { MockServer } from "~/helpers/backend/graphql"
import type { MockServer } from "~/helpers/backend/types/MockServer"
import { copyToClipboard as copyToClipboardHelper } from "~/helpers/utils/clipboard"
import {
mockServers$,

View file

@ -298,7 +298,7 @@ import { useReadonlyStream } from "@composables/stream"
import { useToast } from "@composables/toast"
import { computed, ref, watch } from "vue"
import { TippyComponent } from "vue-tippy"
import { MockServer } from "~/helpers/backend/graphql"
import type { MockServer } from "~/helpers/backend/types/MockServer"
import { showCreateMockServerModal$ } from "~/newstore/mockServers"
import { useMockServer } from "~/composables/useMockServer"
import MockServerCreatedInfo from "~/components/mockServer/MockServerCreatedInfo.vue"

View file

@ -169,9 +169,9 @@ import { pipe } from "fp-ts/function"
import * as TE from "fp-ts/TaskEither"
import { ref, watch } from "vue"
import { useToast } from "~/composables/toast"
import { updateMockServer as updateMockServerMutation } from "~/helpers/backend/mutations/MockServer"
import { platform } from "~/platform"
import { copyToClipboard } from "~/helpers/utils/clipboard"
import type { MockServer } from "~/newstore/mockServers"
import type { MockServer } from "~/helpers/backend/types/MockServer"
import { updateMockServer as updateMockServerInStore } from "~/newstore/mockServers"
// Icons
@ -228,7 +228,7 @@ const updateMockServer = async () => {
}
await pipe(
updateMockServerMutation(props.mockServer.id, payload),
platform.backend.updateMockServer(props.mockServer.id, payload),
TE.match(
() => {
toast.error(t("error.something_went_wrong"))
@ -259,7 +259,9 @@ const toggleMockServer = async () => {
const newActiveState = !isActive.value
await pipe(
updateMockServerMutation(props.mockServer.id, { isActive: newActiveState }),
platform.backend.updateMockServer(props.mockServer.id, {
isActive: newActiveState,
}),
TE.match(
() => {
toast.error(t("error.something_went_wrong"))

View file

@ -63,7 +63,7 @@
import { useI18n } from "@composables/i18n"
import { useToast } from "@composables/toast"
import { refAutoReset } from "@vueuse/core"
import { MockServer } from "~/helpers/backend/graphql"
import type { MockServer } from "~/helpers/backend/types/MockServer"
import { copyToClipboard as copyToClipboardHelper } from "~/helpers/utils/clipboard"
// Icons

View file

@ -211,7 +211,7 @@ import { useMockServerStatus } from "~/composables/mockServer"
import { useToast } from "~/composables/toast"
import { useReadonlyStream } from "~/composables/stream"
import { copyToClipboard } from "~/helpers/utils/clipboard"
import type { MockServer } from "~/newstore/mockServers"
import type { MockServer } from "~/helpers/backend/types/MockServer"
import { platform } from "~/platform"
import {
@ -223,10 +223,6 @@ import {
import MockServerEditMockServer from "~/components/mockServer/EditMockServer.vue"
import MockServerLogs from "~/components/mockServer/MockServerLogs.vue"
import {
deleteMockServer as deleteMockServerMutation,
updateMockServer as updateMockServerMutation,
} from "~/helpers/backend/mutations/MockServer"
// Icons
import IconCheck from "~icons/lucide/check"
@ -275,7 +271,9 @@ const toggleMockServer = async (mockServer: MockServer) => {
const newActiveState = !mockServer.isActive
await pipe(
updateMockServerMutation(mockServer.id, { isActive: newActiveState }),
platform.backend.updateMockServer(mockServer.id, {
isActive: newActiveState,
}),
TE.match(
() => {
toast.error(t("error.something_went_wrong"))
@ -317,7 +315,7 @@ const confirmDelete = async () => {
confirmDeleteMockServer.value = false
await pipe(
deleteMockServerMutation(mockServer.id),
platform.backend.deleteMockServer(mockServer.id),
TE.match(
() => {
toast.error(t("error.something_went_wrong"))

View file

@ -115,10 +115,7 @@
<script setup lang="ts">
import { ref, onMounted } from "vue"
import { useI18n } from "~/composables/i18n"
import {
getMockServerLogs,
deleteMockServerLog,
} from "~/helpers/backend/queries/MockServerLogs"
import { platform } from "~/platform"
import * as TE from "fp-ts/TaskEither"
import { pipe } from "fp-ts/function"
import { useToast } from "~/composables/toast"
@ -141,7 +138,7 @@ const logToDelete = ref<string | null>(null)
const fetchLogs = async () => {
loading.value = true
await pipe(
getMockServerLogs(props.mockServerID),
platform.backend.getMockServerLogs(props.mockServerID),
TE.match(
() => {
toast.error(t("error.something_went_wrong"))
@ -169,7 +166,7 @@ const confirmRemoveLog = (id: string) => {
const confirmDelete = async () => {
if (logToDelete.value) {
await pipe(
deleteMockServerLog(logToDelete.value),
platform.backend.deleteMockServerLog(logToDelete.value),
TE.match(
() => {
toast.error(t("error.something_went_wrong"))

View file

@ -1,7 +1,7 @@
import { computed } from "vue"
import { useReadonlyStream } from "~/composables/stream"
import { mockServers$ } from "~/newstore/mockServers"
import type { MockServer } from "~/newstore/mockServers"
import type { MockServer } from "~/helpers/backend/types/MockServer"
/**
* Composable to get mock server status for collections

View file

@ -5,11 +5,9 @@ import { useService } from "dioc/vue"
import { pipe } from "fp-ts/function"
import * as TE from "fp-ts/TaskEither"
import { computed } from "vue"
import { MockServer, WorkspaceType } from "~/helpers/backend/graphql"
import {
createMockServer as createMockServerMutation,
updateMockServer,
} from "~/helpers/backend/mutations/MockServer"
import { WorkspaceType } from "~/helpers/backend/graphql"
import type { MockServer } from "~/helpers/backend/types/MockServer"
import { platform } from "~/platform"
import {
createTeamEnvironment,
updateTeamEnvironment,
@ -31,7 +29,6 @@ import {
} from "~/newstore/mockServers"
import { TeamCollectionsService } from "~/services/team-collection.service"
import { WorkspaceService } from "~/services/workspace.service"
import { platform } from "~/platform"
export function useMockServer() {
const t = useI18n()
@ -259,7 +256,7 @@ export function useMockServer() {
: undefined
const result = await pipe(
createMockServerMutation(
platform.backend.createMockServer(
mockServerName.trim(),
workspaceType,
workspaceID,
@ -307,7 +304,9 @@ export function useMockServer() {
const newActiveState = !mockServer.isActive
return await pipe(
updateMockServer(mockServer.id, { isActive: newActiveState }),
platform.backend.updateMockServer(mockServer.id, {
isActive: newActiveState,
}),
TE.match(
() => {
toast.error(t("error.something_went_wrong"))

View file

@ -6,36 +6,10 @@ import {
CreateMockServerDocument,
UpdateMockServerDocument,
DeleteMockServerDocument,
GetTeamMockServersDocument,
WorkspaceType,
} from "../graphql"
// Types for mock server
export type MockServer = {
id: string
name: string
subdomain: string
serverUrlPathBased?: string
serverUrlDomainBased?: string | null
workspaceType: WorkspaceType
workspaceID?: string | null
delayInMs?: number
isPublic: boolean
isActive: boolean
createdOn: Date
updatedOn: Date
creator?: {
uid: string
}
collection?: {
id: string
title: string
requests?: any[]
}
// Legacy fields for backward compatibility
userUid?: string
collectionID?: string
}
import type { MockServer } from "../types/MockServer"
type CreateMockServerError =
| "mock_server/invalid_collection"
@ -174,42 +148,6 @@ export const deleteMockServer = (id: string) =>
(error) => (error as Error).message as DeleteMockServerError
)
export const getTeamMockServers = (
teamID: string,
skip?: number,
take?: number
) =>
TE.tryCatch(
async () => {
const result = await client
.value!.query(GetTeamMockServersDocument, {
teamID,
skip,
take,
})
.toPromise()
if (result.error) {
throw new Error(
result.error.message || "Failed to get team mock servers"
)
}
if (!result.data) {
throw new Error("No data returned from get team mock servers query")
}
const data = result.data.teamMockServers
// Map the GraphQL response to frontend format
return data.map((mockServer: any) => ({
...mockServer,
userUid: mockServer.creator?.uid || "", // Legacy field
collectionID: mockServer.collection?.id || "", // Legacy field
})) as MockServer[]
},
(error) => (error as Error).message as CreateMockServerError
)
// Centralized mapper for backend GraphQL error tokens to user-facing messages.
export const getErrorMessage = (err: GQLError<string> | string | Error) => {
const t = getI18n()

View file

@ -8,6 +8,7 @@ import {
type TeamPublishedDocsListQuery,
PublishedDocDocument,
PublishedDocs,
type PublishedDocQuery as GqlPublishedDocQuery,
} from "../graphql"
import {
HoppCollection,
@ -241,7 +242,7 @@ export const getPublishedDocByID = (id: string) =>
throw result.left
}
const data = result.right as PublishedDocQuery
const data = result.right as GqlPublishedDocQuery
return data.publishedDoc
},
(error) => {

View file

@ -0,0 +1,31 @@
import { WorkspaceType } from "~/helpers/backend/graphql"
/**
* Canonical MockServer type used across the frontend.
* Shared by BackendPlatformDef, newstore/mockServers, and mutation helpers.
*/
export type MockServer = {
id: string
name: string
subdomain: string
serverUrlPathBased?: string
serverUrlDomainBased?: string | null
workspaceType: WorkspaceType
workspaceID?: string | null
delayInMs?: number
isPublic: boolean
isActive: boolean
createdOn: Date | string
updatedOn: Date | string
creator?: {
uid: string
} | null
collection?: {
id: string
title: string
requests?: any[]
} | null
// Legacy fields for backward compatibility
userUid?: string
collectionID?: string
}

View file

@ -2,41 +2,13 @@ import { pipe } from "fp-ts/function"
import * as TE from "fp-ts/TaskEither"
import { BehaviorSubject } from "rxjs"
import { pluck } from "rxjs/operators"
import {
getMyMockServers,
getTeamMockServers,
} from "~/helpers/backend/queries/MockServer"
import { getService } from "~/modules/dioc"
import { WorkspaceService } from "~/services/workspace.service"
import { platform } from "~/platform"
import DispatchingStore, { defineDispatchers } from "./DispatchingStore"
export type WorkspaceType = "USER" | "TEAM"
export type MockServer = {
id: string
name: string
subdomain: string
serverUrlPathBased?: string
serverUrlDomainBased?: string | null
workspaceType: WorkspaceType
workspaceID?: string | null
delayInMs?: number
isPublic: boolean
isActive: boolean
createdOn: Date
updatedOn: Date
creator?: {
uid: string
}
collection?: {
id: string
title: string
requests?: any[]
} | null
// Legacy fields for backward compatibility
userUid?: string
collectionID?: string
}
import type { MockServer } from "~/helpers/backend/types/MockServer"
import { WorkspaceType } from "~/helpers/backend/graphql"
export type CreateMockServerInput = {
name: string
@ -179,7 +151,7 @@ export function loadMockServers(skip?: number, take?: number) {
}
setLoading(true)
return pipe(
getMyMockServers(skip, take),
platform.backend.getMyMockServers(skip, take),
TE.match(
(error) => {
console.error("Failed to load mock servers:", error)
@ -195,7 +167,7 @@ export function loadMockServers(skip?: number, take?: number) {
// Fallback to user mock servers if workspace service is not available
setLoading(true)
return pipe(
getMyMockServers(skip, take),
platform.backend.getMyMockServers(skip, take),
TE.match(
(error) => {
console.error("Failed to load mock servers:", error)
@ -218,7 +190,7 @@ export function loadTeamMockServers(
) {
setLoading(true)
return pipe(
getTeamMockServers(teamID, skip, take),
platform.backend.getTeamMockServers(teamID, skip, take),
TE.match(
(error) => {
console.error("Failed to load team mock servers:", error)

View file

@ -4,22 +4,31 @@ import * as E from "fp-ts/lib/Either"
import { GQLError } from "~/helpers/backend/GQLClient"
import {
AcceptTeamInvitationMutation,
CreatePublishedDocMutation,
CreatePublishedDocsArgs,
CreateShortcodeMutation,
CreateTeamInvitationMutation,
CreateTeamMutation,
DeletePublishedDocMutation,
GetInviteDetailsQuery,
GetInviteDetailsQueryVariables,
GetMockServerLogsQuery,
GetMyTeamsQuery,
PublishedDocQuery,
GetUserShortcodesQuery,
TeamAccessRole,
TeamPublishedDocsListQuery,
UpdatePublishedDocMutation,
UpdatePublishedDocsArgs,
UserPublishedDocsListQuery,
WorkspaceType,
} from "~/helpers/backend/graphql"
import { useGQLQuery } from "~/composables/graphql"
import { Email } from "~/helpers/backend/types/Email"
import type { MockServer } from "~/helpers/backend/types/MockServer"
import { TeamName } from "~/helpers/backend/types/TeamName"
import {
AcceptTeamInvitationMutation,
CreateTeamInvitationMutation,
CreateTeamMutation,
} from "../helpers/backend/graphql"
export type BackendPlatformDef = {
// Read actions via GQL queries
@ -69,4 +78,85 @@ export type BackendPlatformDef = {
request: HoppRESTRequest,
properties?: string
) => TE.TaskEither<GQLError<string>, CreateShortcodeMutation>
// Mock server operations
createMockServer: (
name: string,
workspaceType?: WorkspaceType,
workspaceID?: string,
delayInMs?: number,
isPublic?: boolean,
collectionID?: string,
autoCreateCollection?: boolean,
autoCreateRequestExample?: boolean
) => TE.TaskEither<string, MockServer>
updateMockServer: (
id: string,
input: {
name?: string
isActive?: boolean
delayInMs?: number
isPublic?: boolean
}
) => TE.TaskEither<string, MockServer>
deleteMockServer: (id: string) => TE.TaskEither<string, boolean>
getMockServer: (id: string) => TE.TaskEither<string, MockServer>
getMyMockServers: (
skip?: number,
take?: number
) => TE.TaskEither<string, MockServer[]>
getTeamMockServers: (
teamID: string,
skip?: number,
take?: number
) => TE.TaskEither<string, MockServer[]>
getMockServerLogs: (
mockServerID: string,
skip?: number,
take?: number
) => TE.TaskEither<string, GetMockServerLogsQuery["mockServerLogs"]>
deleteMockServerLog: (logID: string) => TE.TaskEither<string, boolean>
// Published docs operations
createPublishedDoc: (
doc: CreatePublishedDocsArgs
) => TE.TaskEither<GQLError<string>, CreatePublishedDocMutation>
updatePublishedDoc: (
id: string,
doc: UpdatePublishedDocsArgs
) => TE.TaskEither<GQLError<string>, UpdatePublishedDocMutation>
deletePublishedDoc: (
id: string
) => TE.TaskEither<GQLError<string>, DeletePublishedDocMutation>
getPublishedDocByID: (
id: string
) => TE.TaskEither<string, PublishedDocQuery["publishedDoc"]>
getUserPublishedDocs: (
skip?: number,
take?: number
) => TE.TaskEither<
string,
UserPublishedDocsListQuery["userPublishedDocsList"]
>
getTeamPublishedDocs: (
teamID: string,
collectionID?: string,
skip?: number,
take?: number
) => TE.TaskEither<
string,
TeamPublishedDocsListQuery["teamPublishedDocsList"]
>
}

View file

@ -31,6 +31,31 @@ import {
TeamAccessRole,
} from "../../helpers/backend/graphql"
import {
createMockServer,
updateMockServer,
deleteMockServer,
} from "../../helpers/backend/mutations/MockServer"
import {
getMockServer,
getMyMockServers,
getTeamMockServers,
} from "../../helpers/backend/queries/MockServer"
import {
getMockServerLogs,
deleteMockServerLog,
} from "../../helpers/backend/queries/MockServerLogs"
import {
createPublishedDoc,
updatePublishedDoc,
deletePublishedDoc,
} from "../../helpers/backend/mutations/PublishedDocs"
import {
getPublishedDocByID,
getUserPublishedDocs,
getTeamPublishedDocs,
} from "../../helpers/backend/queries/PublishedDocs"
const getInviteDetails = <GetInviteDetailsError extends string>(
inviteID: string
) => {
@ -129,4 +154,18 @@ export const def: BackendPlatformDef = {
createTeamInvitation,
acceptTeamInvitation,
createShortcode,
createMockServer,
updateMockServer,
deleteMockServer,
getMockServer,
getMyMockServers,
getTeamMockServers,
getMockServerLogs,
deleteMockServerLog,
createPublishedDoc,
updatePublishedDoc,
deletePublishedDoc,
getPublishedDocByID,
getUserPublishedDocs,
getTeamPublishedDocs,
}

View file

@ -16,14 +16,15 @@ import {
isLiveVersion,
CURRENT_VERSION_TAG,
} from "../documentation.service"
import {
getUserPublishedDocs,
getTeamPublishedDocs,
} from "~/helpers/backend/queries/PublishedDocs"
import { platform } from "~/platform"
vi.mock("~/helpers/backend/queries/PublishedDocs", () => ({
vi.mock("~/platform", () => ({
platform: {
backend: {
getUserPublishedDocs: vi.fn(),
getTeamPublishedDocs: vi.fn(),
},
},
}))
describe("DocumentationService", () => {
@ -88,6 +89,7 @@ describe("DocumentationService", () => {
}
beforeEach(() => {
vi.resetAllMocks()
container = new TestContainer()
service = container.bind(DocumentationService)
})
@ -479,7 +481,7 @@ describe("DocumentationService", () => {
},
]
vi.mocked(getUserPublishedDocs).mockReturnValue(() =>
vi.mocked(platform.backend.getUserPublishedDocs).mockReturnValue(() =>
Promise.resolve(E.right(mockDocs as any))
)
@ -514,7 +516,7 @@ describe("DocumentationService", () => {
},
]
vi.mocked(getTeamPublishedDocs).mockReturnValue(() =>
vi.mocked(platform.backend.getTeamPublishedDocs).mockReturnValue(() =>
Promise.resolve(E.right(mockDocs as any))
)
@ -538,7 +540,7 @@ describe("DocumentationService", () => {
it("should handle error when fetching user published docs", async () => {
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {})
vi.mocked(getUserPublishedDocs).mockReturnValue(() =>
vi.mocked(platform.backend.getUserPublishedDocs).mockReturnValue(() =>
Promise.resolve(E.left("user/not_authenticated"))
)
@ -553,7 +555,7 @@ describe("DocumentationService", () => {
it("should handle error when fetching team published docs", async () => {
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {})
vi.mocked(getTeamPublishedDocs).mockReturnValue(() =>
vi.mocked(platform.backend.getTeamPublishedDocs).mockReturnValue(() =>
Promise.resolve(E.left("team/not_required" as any))
)
@ -635,7 +637,7 @@ describe("DocumentationService", () => {
})
// Mock the first call to be slow
vi.mocked(getUserPublishedDocs)
vi.mocked(platform.backend.getUserPublishedDocs)
.mockReturnValueOnce(() => slowPromise as any)
.mockReturnValueOnce(() => Promise.resolve(E.right(fastDocs as any)))

View file

@ -1,11 +1,8 @@
import { Service } from "dioc"
import { reactive, computed, ref } from "vue"
import { HoppCollection, HoppRESTRequest } from "@hoppscotch/data"
import {
getUserPublishedDocs,
getTeamPublishedDocs,
} from "~/helpers/backend/queries/PublishedDocs"
import * as E from "fp-ts/Either"
import { platform } from "~/platform"
// Types for documentation
export type DocumentationType = "collection" | "request"
@ -284,7 +281,7 @@ export class DocumentationService extends Service {
const requestId = ++this.fetchRequestId
try {
const result = await getUserPublishedDocs()()
const result = await platform.backend.getUserPublishedDocs()()
// If a newer request has started, ignore this result
if (requestId !== this.fetchRequestId) return
@ -330,7 +327,7 @@ export class DocumentationService extends Service {
try {
// Fetch all published docs for the team (collectionID is optional now)
const result = await getTeamPublishedDocs(teamID)()
const result = await platform.backend.getTeamPublishedDocs(teamID)()
// If a newer request has started, ignore this result
if (requestId !== this.fetchRequestId) return