refactor: save request handle in tabs and remove tabs related logic from personal provider definition
This commit is contained in:
@@ -253,20 +253,19 @@ const saveRequestAs = async () => {
|
||||
return
|
||||
}
|
||||
|
||||
const resultHandle = await workspaceService.createRESTRequest(
|
||||
const requestHandleResult = await workspaceService.createRESTRequest(
|
||||
collHandle,
|
||||
updatedRequest.name,
|
||||
false
|
||||
updatedRequest
|
||||
)
|
||||
|
||||
if (E.isLeft(resultHandle)) {
|
||||
if (E.isLeft(requestHandleResult)) {
|
||||
// WORKSPACE_INVALIDATED | INVALID_COLLECTION_HANDLE
|
||||
return
|
||||
}
|
||||
|
||||
const result = resultHandle.right
|
||||
const requestHandle = requestHandleResult.right
|
||||
|
||||
if (result.value.type === "invalid") {
|
||||
if (requestHandle.value.type === "invalid") {
|
||||
// WORKSPACE_INVALIDATED | INVALID_COLLECTION_HANDLE
|
||||
return
|
||||
}
|
||||
@@ -315,9 +314,8 @@ const saveRequestAs = async () => {
|
||||
request: updatedRequest,
|
||||
isDirty: false,
|
||||
saveContext: {
|
||||
originLocation: "user-collection",
|
||||
folderPath: picked.value.folderPath,
|
||||
requestIndex: picked.value.requestIndex,
|
||||
originLocation: "workspace-user-collection",
|
||||
requestHandle,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -236,15 +236,28 @@ import { useI18n } from "@composables/i18n"
|
||||
import { useSetting } from "@composables/settings"
|
||||
import { useReadonlyStream, useStreamSubscriber } from "@composables/stream"
|
||||
import { useToast } from "@composables/toast"
|
||||
import { HoppRESTRequest } from "@hoppscotch/data"
|
||||
import { useVModel } from "@vueuse/core"
|
||||
import { useService } from "dioc/vue"
|
||||
import * as E from "fp-ts/Either"
|
||||
import { Ref, computed, ref, onUnmounted } from "vue"
|
||||
import { Ref, computed, onUnmounted, ref } from "vue"
|
||||
import { runRESTRequest$ } from "~/helpers/RequestRunner"
|
||||
import { defineActionHandler, invokeAction } from "~/helpers/actions"
|
||||
import { runMutation } from "~/helpers/backend/GQLClient"
|
||||
import { UpdateRequestDocument } from "~/helpers/backend/graphql"
|
||||
import { getPlatformSpecialKey as getSpecialKey } from "~/helpers/platformutils"
|
||||
import { runRESTRequest$ } from "~/helpers/RequestRunner"
|
||||
import { getDefaultRESTRequest } from "~/helpers/rest/default"
|
||||
import { HoppRESTDocument } from "~/helpers/rest/document"
|
||||
import { getMethodLabelColor } from "~/helpers/rest/labelColoring"
|
||||
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
|
||||
import { RESTHistoryEntry, restHistory$ } from "~/newstore/history"
|
||||
import { platform } from "~/platform"
|
||||
import { InspectionService } from "~/services/inspection"
|
||||
import { InterceptorService } from "~/services/interceptor.service"
|
||||
import { NewWorkspaceService } from "~/services/new-workspace"
|
||||
import { HoppTab } from "~/services/tab"
|
||||
import { RESTTabService } from "~/services/tab/rest"
|
||||
import { WorkspaceService } from "~/services/workspace.service"
|
||||
import IconChevronDown from "~icons/lucide/chevron-down"
|
||||
import IconCode2 from "~icons/lucide/code-2"
|
||||
import IconFileCode from "~icons/lucide/file-code"
|
||||
@@ -252,19 +265,6 @@ import IconFolderPlus from "~icons/lucide/folder-plus"
|
||||
import IconRotateCCW from "~icons/lucide/rotate-ccw"
|
||||
import IconSave from "~icons/lucide/save"
|
||||
import IconShare2 from "~icons/lucide/share-2"
|
||||
import { getDefaultRESTRequest } from "~/helpers/rest/default"
|
||||
import { RESTHistoryEntry, restHistory$ } from "~/newstore/history"
|
||||
import { platform } from "~/platform"
|
||||
import { HoppRESTRequest } from "@hoppscotch/data"
|
||||
import { useService } from "dioc/vue"
|
||||
import { InspectionService } from "~/services/inspection"
|
||||
import { InterceptorService } from "~/services/interceptor.service"
|
||||
import { HoppTab } from "~/services/tab"
|
||||
import { HoppRESTDocument } from "~/helpers/rest/document"
|
||||
import { RESTTabService } from "~/services/tab/rest"
|
||||
import { getMethodLabelColor } from "~/helpers/rest/labelColoring"
|
||||
import { WorkspaceService } from "~/services/workspace.service"
|
||||
import { NewWorkspaceService } from "~/services/new-workspace"
|
||||
|
||||
const t = useI18n()
|
||||
const interceptorService = useService(InterceptorService)
|
||||
@@ -508,80 +508,58 @@ const cycleDownMethod = () => {
|
||||
}
|
||||
|
||||
const saveRequest = async () => {
|
||||
const saveCtx = tab.value.document.saveContext
|
||||
const { saveContext } = tab.value.document
|
||||
|
||||
if (!saveCtx) {
|
||||
if (!saveContext) {
|
||||
showSaveRequestModal.value = true
|
||||
return
|
||||
}
|
||||
if (saveCtx.originLocation === "user-collection") {
|
||||
|
||||
if (saveContext.originLocation === "workspace-user-collection") {
|
||||
const updatedRequest = tab.value.document.request
|
||||
|
||||
if (!newWorkspaceService.activeWorkspaceHandle.value) {
|
||||
if (
|
||||
!newWorkspaceService.activeWorkspaceHandle.value ||
|
||||
!saveContext.requestHandle
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
const collHandleResult = await newWorkspaceService.getCollectionHandle(
|
||||
newWorkspaceService.activeWorkspaceHandle.value,
|
||||
saveCtx.folderPath
|
||||
)
|
||||
const { requestHandle } = saveContext
|
||||
|
||||
if (E.isLeft(collHandleResult)) {
|
||||
// INVALID_WORKSPACE_HANDLE
|
||||
if (!requestHandle.value) {
|
||||
return
|
||||
}
|
||||
|
||||
const collHandle = collHandleResult.right
|
||||
|
||||
if (collHandle.value.type === "invalid") {
|
||||
// WORKSPACE_INVALIDATED | INVALID_COLLECTION_HANDLE
|
||||
return
|
||||
}
|
||||
|
||||
const requestHandleResult = await newWorkspaceService.getRequestHandle(
|
||||
newWorkspaceService.activeWorkspaceHandle.value,
|
||||
`${saveCtx.folderPath}/${saveCtx.requestIndex.toString()}`
|
||||
)
|
||||
|
||||
if (E.isLeft(requestHandleResult)) {
|
||||
// INVALID_REQUEST_HANDLE
|
||||
return
|
||||
}
|
||||
|
||||
const requestHandle = requestHandleResult.right
|
||||
|
||||
if (requestHandle.value.type === "invalid") {
|
||||
// WORKSPACE_INVALIDATED | INVALID_REQUEST_HANDLE
|
||||
showSaveRequestModal.value = true
|
||||
return
|
||||
}
|
||||
|
||||
const updatedRequestResult = await newWorkspaceService.updateRESTRequest(
|
||||
const updateRequestResult = await newWorkspaceService.updateRESTRequest(
|
||||
requestHandle,
|
||||
updatedRequest
|
||||
)
|
||||
|
||||
if (E.isLeft(updatedRequestResult)) {
|
||||
if (E.isLeft(updateRequestResult)) {
|
||||
// INVALID_REQUEST_HANDLE
|
||||
return
|
||||
}
|
||||
showSaveRequestModal.value = true
|
||||
|
||||
const resultHandle = updatedRequestResult.right
|
||||
|
||||
if (resultHandle.value.type === "invalid") {
|
||||
// REQUEST_INVALIDATED | REQUEST_PATH_NOT_FOUND
|
||||
|
||||
if (resultHandle.value.reason === "REQUEST_PATH_NOT_FOUND") {
|
||||
// REQUEST_PATH_NOT_FOUND
|
||||
tab.value.document.saveContext = undefined
|
||||
await saveRequest()
|
||||
if (!tab.value.document.isDirty) {
|
||||
tab.value.document.isDirty = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
tab.value.document.isDirty = false
|
||||
|
||||
tab.value.document.saveContext = {
|
||||
...saveContext,
|
||||
requestHandle,
|
||||
}
|
||||
|
||||
toast.success(`${t("request.saved")}`)
|
||||
} else if (saveCtx.originLocation === "team-collection") {
|
||||
} else if (saveContext.originLocation === "team-collection") {
|
||||
const req = tab.value.document.request
|
||||
|
||||
// TODO: handle error case (NOTE: overwriteRequestTeams is async)
|
||||
@@ -594,7 +572,7 @@ const saveRequest = async () => {
|
||||
})
|
||||
|
||||
runMutation(UpdateRequestDocument, {
|
||||
requestID: saveCtx.requestID,
|
||||
requestID: saveContext.requestID,
|
||||
data: {
|
||||
title: req.name,
|
||||
request: JSON.stringify(req),
|
||||
|
||||
@@ -151,6 +151,10 @@ import { TeamCollection } from "~/helpers/backend/graphql"
|
||||
import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties"
|
||||
import { useReadonlyStream } from "~/composables/stream"
|
||||
import { updateInheritedPropertiesForAffectedRequests } from "~/helpers/collection/collection"
|
||||
import {
|
||||
resolveSaveContextOnRequestReorder,
|
||||
getRequestsByPath,
|
||||
} from "~/helpers/collection/request"
|
||||
|
||||
const t = useI18n()
|
||||
const toast = useToast()
|
||||
@@ -344,22 +348,46 @@ const onAddRequest = async (requestName: string) => {
|
||||
return
|
||||
}
|
||||
|
||||
const result = await workspaceService.createRESTRequest(
|
||||
const newRequest = {
|
||||
...cloneDeep(tabs.currentActiveTab.value.document.request),
|
||||
name: requestName,
|
||||
}
|
||||
|
||||
const requestHandleResult = await workspaceService.createRESTRequest(
|
||||
collectionHandle,
|
||||
requestName,
|
||||
true
|
||||
newRequest
|
||||
)
|
||||
|
||||
if (E.isLeft(result)) {
|
||||
if (E.isLeft(requestHandleResult)) {
|
||||
// INVALID_COLLECTION_HANDLE
|
||||
return
|
||||
}
|
||||
|
||||
if (result.right.value.type === "invalid") {
|
||||
const requestHandle = requestHandleResult.right
|
||||
|
||||
if (requestHandle.value.type === "invalid") {
|
||||
// COLLECTION_INVALIDATED
|
||||
return
|
||||
}
|
||||
|
||||
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
|
||||
requestHandle.value.data.collectionID,
|
||||
"rest"
|
||||
)
|
||||
|
||||
tabs.createNewTab({
|
||||
request: newRequest,
|
||||
isDirty: false,
|
||||
saveContext: {
|
||||
originLocation: "workspace-user-collection",
|
||||
requestHandle,
|
||||
},
|
||||
inheritedProperties: {
|
||||
auth,
|
||||
headers,
|
||||
},
|
||||
})
|
||||
|
||||
displayModalAddRequest(false)
|
||||
}
|
||||
|
||||
@@ -612,6 +640,28 @@ const onRemoveRequest = async () => {
|
||||
return
|
||||
}
|
||||
|
||||
const possibleTab = tabs.getTabRefWithSaveContext({
|
||||
originLocation: "workspace-user-collection",
|
||||
requestHandle,
|
||||
})
|
||||
|
||||
// If there is a tab attached to this request, dissociate its state and mark it dirty
|
||||
if (possibleTab) {
|
||||
possibleTab.value.document.saveContext = null
|
||||
possibleTab.value.document.isDirty = true
|
||||
}
|
||||
|
||||
const { collectionID, requestID } = requestHandle.value.data
|
||||
const requestIndex = parseInt(requestID.split("/").slice(-1)[0])
|
||||
|
||||
// The same function is used to reorder requests since after removing, it's basically doing reorder
|
||||
resolveSaveContextOnRequestReorder({
|
||||
lastIndex: requestIndex,
|
||||
newIndex: -1,
|
||||
folderPath: collectionID,
|
||||
length: getRequestsByPath(restCollectionState.value, collectionID).length,
|
||||
})
|
||||
|
||||
toast.success(t("state.deleted"))
|
||||
displayConfirmModal(false)
|
||||
}
|
||||
@@ -636,7 +686,6 @@ const selectRequest = async (requestIndexPath: string) => {
|
||||
return
|
||||
}
|
||||
|
||||
const requestIndex = parseInt(requestIndexPath.split("/").slice(-1)[0])
|
||||
const request = requestHandle.value.data.request as HoppRESTRequest
|
||||
|
||||
// If there is a request with this save context, switch into it
|
||||
@@ -647,9 +696,8 @@ const selectRequest = async (requestIndexPath: string) => {
|
||||
"rest"
|
||||
)
|
||||
possibleTab = tabs.getTabRefWithSaveContext({
|
||||
originLocation: "user-collection",
|
||||
requestIndex,
|
||||
folderPath: collectionIndexPath,
|
||||
originLocation: "workspace-user-collection",
|
||||
requestHandle,
|
||||
})
|
||||
if (possibleTab) {
|
||||
tabs.setActiveTab(possibleTab.value.id)
|
||||
@@ -659,9 +707,8 @@ const selectRequest = async (requestIndexPath: string) => {
|
||||
request: cloneDeep(request),
|
||||
isDirty: false,
|
||||
saveContext: {
|
||||
originLocation: "user-collection",
|
||||
folderPath: collectionIndexPath,
|
||||
requestIndex,
|
||||
originLocation: "workspace-user-collection",
|
||||
requestHandle,
|
||||
},
|
||||
inheritedProperties: {
|
||||
auth,
|
||||
|
||||
@@ -3,8 +3,21 @@ import { HoppRESTResponse } from "../types/HoppRESTResponse"
|
||||
import { HoppTestResult } from "../types/HoppTestResult"
|
||||
import { RESTOptionTabs } from "~/components/http/RequestOptions.vue"
|
||||
import { HoppInheritedProperty } from "../types/HoppInheritedProperties"
|
||||
import { HandleRef } from "~/services/new-workspace/handle"
|
||||
import { WorkspaceRequest } from "~/services/new-workspace/workspace"
|
||||
|
||||
export type HoppRESTSaveContext =
|
||||
| {
|
||||
/**
|
||||
* The origin source of the request
|
||||
*/
|
||||
// TODO: Make this `user-collection` after porting all usages
|
||||
originLocation: "workspace-user-collection"
|
||||
/**
|
||||
* Handle to a request in the workspace
|
||||
*/
|
||||
requestHandle: HandleRef<WorkspaceRequest>
|
||||
}
|
||||
| {
|
||||
/**
|
||||
* The origin source of the request
|
||||
|
||||
@@ -331,8 +331,7 @@ export class NewWorkspaceService extends Service {
|
||||
|
||||
public async createRESTRequest(
|
||||
parentCollectionHandle: HandleRef<WorkspaceCollection>,
|
||||
requestName: string,
|
||||
openInNewTab: boolean
|
||||
newRequest: HoppRESTRequest
|
||||
): Promise<
|
||||
E.Either<
|
||||
WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">,
|
||||
@@ -353,8 +352,7 @@ export class NewWorkspaceService extends Service {
|
||||
|
||||
const result = await provider.createRESTRequest(
|
||||
parentCollectionHandle,
|
||||
requestName,
|
||||
openInNewTab
|
||||
newRequest
|
||||
)
|
||||
|
||||
if (E.isLeft(result)) {
|
||||
|
||||
@@ -58,8 +58,7 @@ export interface WorkspaceProvider {
|
||||
): Promise<E.Either<unknown, HandleRef<boolean>>>
|
||||
createRESTRequest(
|
||||
parentCollectionHandle: HandleRef<WorkspaceCollection>,
|
||||
requestName: string,
|
||||
openInNewTab: boolean
|
||||
request: HoppRESTRequest
|
||||
): Promise<E.Either<unknown, HandleRef<WorkspaceRequest>>>
|
||||
updateRESTRequest(
|
||||
requestHandle: HandleRef<WorkspaceRequest>,
|
||||
|
||||
@@ -9,7 +9,6 @@ import { useStreamStatic } from "~/composables/stream"
|
||||
import {
|
||||
addRESTCollection,
|
||||
addRESTFolder,
|
||||
cascadeParentCollectionForHeaderAuth,
|
||||
editRESTCollection,
|
||||
editRESTFolder,
|
||||
editRESTRequest,
|
||||
@@ -36,12 +35,6 @@ import {
|
||||
WorkspaceRequest,
|
||||
} from "~/services/new-workspace/workspace"
|
||||
|
||||
import { cloneDeep } from "lodash-es"
|
||||
import {
|
||||
getRequestsByPath,
|
||||
resolveSaveContextOnRequestReorder,
|
||||
} from "~/helpers/collection/request"
|
||||
import { RESTTabService } from "~/services/tab/rest"
|
||||
import IconUser from "~icons/lucide/user"
|
||||
import { NewWorkspaceService } from ".."
|
||||
import { HoppRESTRequest } from "@hoppscotch/data"
|
||||
@@ -60,7 +53,6 @@ export class PersonalWorkspaceProviderService
|
||||
public readonly providerID = "PERSONAL_WORKSPACE_PROVIDER"
|
||||
|
||||
private workspaceService = this.bind(NewWorkspaceService)
|
||||
private tabs = this.bind(RESTTabService)
|
||||
|
||||
public workspaceDecor: Ref<WorkspaceDecor> = ref({
|
||||
headerCurrentIcon: IconUser,
|
||||
@@ -380,8 +372,7 @@ export class PersonalWorkspaceProviderService
|
||||
|
||||
public createRESTRequest(
|
||||
parentCollHandle: HandleRef<WorkspaceCollection>,
|
||||
requestName: string,
|
||||
openInNewTab: boolean
|
||||
newRequest: HoppRESTRequest
|
||||
): Promise<E.Either<unknown, HandleRef<WorkspaceRequest>>> {
|
||||
if (
|
||||
parentCollHandle.value.type !== "ok" ||
|
||||
@@ -408,34 +399,8 @@ export class PersonalWorkspaceProviderService
|
||||
const { collectionID, providerID, workspaceID } =
|
||||
parentCollHandle.value.data
|
||||
|
||||
const newRequest = {
|
||||
...cloneDeep(this.tabs.currentActiveTab.value.document.request),
|
||||
name: requestName,
|
||||
}
|
||||
|
||||
const insertionIndex = saveRESTRequestAs(collectionID, newRequest)
|
||||
|
||||
if (openInNewTab) {
|
||||
const { auth, headers } = cascadeParentCollectionForHeaderAuth(
|
||||
collectionID,
|
||||
"rest"
|
||||
)
|
||||
|
||||
this.tabs.createNewTab({
|
||||
request: newRequest,
|
||||
isDirty: false,
|
||||
saveContext: {
|
||||
originLocation: "user-collection",
|
||||
folderPath: collectionID,
|
||||
requestIndex: insertionIndex,
|
||||
},
|
||||
inheritedProperties: {
|
||||
auth,
|
||||
headers,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
platform.analytics?.logEvent({
|
||||
type: "HOPP_SAVE_REQUEST",
|
||||
workspaceType: "personal",
|
||||
@@ -488,18 +453,6 @@ export class PersonalWorkspaceProviderService
|
||||
const { collectionID, requestID } = requestHandle.value.data
|
||||
const requestIndex = parseInt(requestID.split("/").slice(-1)[0])
|
||||
|
||||
const possibleTab = this.tabs.getTabRefWithSaveContext({
|
||||
originLocation: "user-collection",
|
||||
folderPath: collectionID,
|
||||
requestIndex,
|
||||
})
|
||||
|
||||
// If there is a tab attached to this request, dissociate its state and mark it dirty
|
||||
if (possibleTab) {
|
||||
possibleTab.value.document.saveContext = null
|
||||
possibleTab.value.document.isDirty = true
|
||||
}
|
||||
|
||||
const requestToRemove = navigateToFolderWithIndexPath(
|
||||
restCollectionStore.value.state,
|
||||
collectionID.split("/").map((id) => parseInt(id))
|
||||
@@ -507,17 +460,6 @@ export class PersonalWorkspaceProviderService
|
||||
|
||||
removeRESTRequest(collectionID, requestIndex, requestToRemove?.id)
|
||||
|
||||
// the same function is used to reorder requests since after removing, it's basically doing reorder
|
||||
resolveSaveContextOnRequestReorder({
|
||||
lastIndex: requestIndex,
|
||||
newIndex: -1,
|
||||
folderPath: collectionID,
|
||||
length: getRequestsByPath(
|
||||
this.restCollectionState.value.state,
|
||||
collectionID
|
||||
).length,
|
||||
})
|
||||
|
||||
return {
|
||||
type: "ok",
|
||||
data: true,
|
||||
@@ -617,14 +559,7 @@ export class PersonalWorkspaceProviderService
|
||||
const collection = navigateToFolderWithIndexPath(
|
||||
this.restCollectionState.value.state,
|
||||
collectionID.split("/").map((x) => parseInt(x))
|
||||
)
|
||||
|
||||
if (!collection) {
|
||||
return {
|
||||
type: "invalid" as const,
|
||||
reason: "INVALID_COLLECTION_HANDLE" as const,
|
||||
}
|
||||
}
|
||||
) as HoppCollection
|
||||
|
||||
const { providerID, workspaceID } = workspaceHandle.value.data
|
||||
|
||||
@@ -634,7 +569,7 @@ export class PersonalWorkspaceProviderService
|
||||
providerID,
|
||||
workspaceID,
|
||||
collectionID,
|
||||
name: collection.name,
|
||||
name: collection?.name,
|
||||
},
|
||||
}
|
||||
})
|
||||
@@ -696,15 +631,7 @@ export class PersonalWorkspaceProviderService
|
||||
)
|
||||
|
||||
// Grab the request with it's index
|
||||
const request = (collection?.requests[requestIndex] ??
|
||||
null) as HoppRESTRequest | null
|
||||
|
||||
if (!request) {
|
||||
return {
|
||||
type: "invalid" as const,
|
||||
reason: "INVALID_REQUEST_HANDLE" as const,
|
||||
}
|
||||
}
|
||||
const request = collection?.requests[requestIndex] as HoppRESTRequest
|
||||
|
||||
return {
|
||||
type: "ok",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { HoppCollection, HoppRESTRequest } from "@hoppscotch/data"
|
||||
import { HoppRESTRequest } from "@hoppscotch/data"
|
||||
import { Component } from "vue"
|
||||
|
||||
export type Workspace = {
|
||||
@@ -22,7 +22,7 @@ export type WorkspaceRequest = {
|
||||
collectionID: string
|
||||
requestID: string
|
||||
|
||||
request: HoppRESTRequest | null
|
||||
request: HoppRESTRequest
|
||||
}
|
||||
|
||||
export type WorkspaceDecor = {
|
||||
|
||||
@@ -492,6 +492,13 @@ const HoppRESTResponseSchema = z.discriminatedUnion("type", [
|
||||
|
||||
const HoppRESTSaveContextSchema = z.nullable(
|
||||
z.discriminatedUnion("originLocation", [
|
||||
z
|
||||
.object({
|
||||
originLocation: z.literal("workspace-user-collection"),
|
||||
// TODO: Specify the correct shape
|
||||
requestHandle: z.any(),
|
||||
})
|
||||
.strict(),
|
||||
z
|
||||
.object({
|
||||
originLocation: z.literal("user-collection"),
|
||||
|
||||
Reference in New Issue
Block a user