refactor: save request handle in tabs and remove tabs related logic from personal provider definition

This commit is contained in:
jamesgeorge007
2024-02-09 13:48:19 +05:30
parent 1abbdb0fe0
commit c1a8a871d2
9 changed files with 133 additions and 166 deletions

View File

@@ -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,
},
}

View File

@@ -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),

View File

@@ -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,

View File

@@ -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

View File

@@ -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)) {

View File

@@ -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>,

View File

@@ -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",

View File

@@ -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 = {

View File

@@ -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"),