From 392b2fc48d2a50e0c637854981c5cb0023b3661f Mon Sep 17 00:00:00 2001 From: jamesgeorge007 Date: Fri, 9 Feb 2024 22:49:38 +0530 Subject: [PATCH] refactor: updates based on the provider methods signature changes --- .../components/collections/SaveRequest.vue | 9 +- .../src/components/http/Request.vue | 13 +- .../components/new-collections/rest/index.vue | 223 ++++---- .../helpers/types/HoppInheritedProperties.ts | 16 + .../src/services/new-workspace/index.ts | 108 ++-- .../src/services/new-workspace/provider.ts | 38 +- .../providers/personal.workspace.ts | 495 +++++++++--------- .../src/services/new-workspace/view.ts | 6 + 8 files changed, 476 insertions(+), 432 deletions(-) diff --git a/packages/hoppscotch-common/src/components/collections/SaveRequest.vue b/packages/hoppscotch-common/src/components/collections/SaveRequest.vue index a91c4c40a..ca91a5a78 100644 --- a/packages/hoppscotch-common/src/components/collections/SaveRequest.vue +++ b/packages/hoppscotch-common/src/components/collections/SaveRequest.vue @@ -292,20 +292,19 @@ const saveRequestAs = async () => { return } - const resultHandle = await workspaceService.updateRESTRequest( + const updateRequestResult = await workspaceService.updateRESTRequest( requestHandle, updatedRequest ) - if (E.isLeft(resultHandle)) { + if (E.isLeft(updateRequestResult)) { // WORKSPACE_INVALIDATED | INVALID_REQUEST_HANDLE return } - const result = resultHandle.right + if (updateRequestResult.right.type === "invalid") { + // REQUEST_INVALIDATED | REQUEST_PATH_NOT_FOUND - if (result.value.type === "invalid") { - // WORKSPACE_INVALIDATED | INVALID_REQUEST_HANDLE return } diff --git a/packages/hoppscotch-common/src/components/http/Request.vue b/packages/hoppscotch-common/src/components/http/Request.vue index 8ef60e76c..433257f2e 100644 --- a/packages/hoppscotch-common/src/components/http/Request.vue +++ b/packages/hoppscotch-common/src/components/http/Request.vue @@ -544,9 +544,18 @@ const saveRequest = async () => { if (E.isLeft(updateRequestResult)) { // INVALID_REQUEST_HANDLE showSaveRequestModal.value = true + return + } - if (!tab.value.document.isDirty) { - tab.value.document.isDirty = true + const resultHandle = updateRequestResult.right + + if (resultHandle.type === "invalid") { + // REQUEST_INVALIDATED | REQUEST_PATH_NOT_FOUND + + if (resultHandle.reason === "REQUEST_PATH_NOT_FOUND") { + // REQUEST_PATH_NOT_FOUND + tab.value.document.saveContext = undefined + await saveRequest() } return } diff --git a/packages/hoppscotch-common/src/components/new-collections/rest/index.vue b/packages/hoppscotch-common/src/components/new-collections/rest/index.vue index fd5c8eb40..4c1a9bb45 100644 --- a/packages/hoppscotch-common/src/components/new-collections/rest/index.vue +++ b/packages/hoppscotch-common/src/components/new-collections/rest/index.vue @@ -139,9 +139,7 @@ import IconImport from "~icons/lucide/folder-down" import IconHelpCircle from "~icons/lucide/help-circle" import IconPlus from "~icons/lucide/plus" import { - cascadeParentCollectionForHeaderAuth, navigateToFolderWithIndexPath, - restCollectionStore, restCollections$, saveRESTRequestAs, } from "~/newstore/collections" @@ -256,12 +254,9 @@ const displayConfirmModal = (show: boolean) => { const addNewRootCollection = async (name: string) => { modalLoadingState.value = true - const newCollectionID = restCollectionState.value.length.toString() - const result = await workspaceService.createRESTRootCollection( props.workspaceHandle, - name, - newCollectionID + { name } ) if (E.isLeft(result)) { @@ -306,19 +301,13 @@ const onRemoveRootCollection = async () => { return } - const result = - await workspaceService.removeRESTRootCollection(collectionHandle) + const result = await workspaceService.removeRESTCollection(collectionHandle) if (E.isLeft(result)) { // INVALID_COLLECTION_HANDLE return } - if (result.right.value.type === "invalid") { - // COLLECTION_INVALIDATED - return - } - toast.success(t("state.deleted")) displayConfirmModal(false) } @@ -370,10 +359,24 @@ const onAddRequest = async (requestName: string) => { return } - const { auth, headers } = cascadeParentCollectionForHeaderAuth( - requestHandle.value.data.collectionID, - "rest" - ) + const cascadingAuthHeadersHandleResult = + await workspaceService.getRESTCollectionLevelAuthHeadersView( + collectionHandle + ) + + if (E.isLeft(cascadingAuthHeadersHandleResult)) { + // INVALID_COLLECTION_HANDLE + return + } + + const cascadingAuthHeadersHandle = cascadingAuthHeadersHandleResult.right + + if (cascadingAuthHeadersHandle.value.type === "invalid") { + // COLLECTION_INVALIDATED + return + } + + const { auth, headers } = cascadingAuthHeadersHandle.value.data tabs.createNewTab({ request: newRequest, @@ -396,7 +399,7 @@ const addChildCollection = (parentCollectionIndexPath: string) => { displayModalAddChildColl(true) } -const onAddChildCollection = async (childCollectionName: string) => { +const onAddChildCollection = async (newChildCollectionName: string) => { const parentCollectionIndexPath = editingCollectionIndexPath.value const collectionHandleResult = await workspaceService.getCollectionHandle( @@ -418,7 +421,7 @@ const onAddChildCollection = async (childCollectionName: string) => { const result = await workspaceService.createRESTChildCollection( collectionHandle, - childCollectionName + { name: newChildCollectionName } ) if (E.isLeft(result)) { @@ -466,29 +469,15 @@ const onEditRootCollection = async (newCollectionName: string) => { return } - // We're sure that the collection exists in the given `collectionIndexPath` as there's a validation happening in `getCollectionHandle` above - const updatedCollection = navigateToFolderWithIndexPath( - restCollectionStore.value.state, - collectionIndexPath.split("/").map((id) => parseInt(id)) - ) as HoppCollection - - updatedCollection.name = newCollectionName - - const result = await workspaceService.editRESTCollection( - collectionHandle, - updatedCollection - ) + const result = await workspaceService.updateRESTCollection(collectionHandle, { + name: newCollectionName, + }) if (E.isLeft(result)) { // INVALID_COLLECTION_HANDLE return } - if (result.right.value.type === "invalid") { - // COLLECTION_INVALIDATED - return - } - displayModalEditCollection(false) toast.success(t("collection.renamed")) } @@ -505,7 +494,7 @@ const editChildCollection = (payload: { displayModalEditChildCollection(true) } -const onEditChildCollection = async (newCollectionName: string) => { +const onEditChildCollection = async (newChildCollectionName: string) => { const collectionIndexPath = editingChildCollectionIndexPath.value const collectionHandleResult = await workspaceService.getCollectionHandle( @@ -525,29 +514,15 @@ const onEditChildCollection = async (newCollectionName: string) => { return } - // We're sure that the collection exists in the given `collectionIndexPath` as there's a validation happening in `getCollectionHandle` above - const updatedCollection = navigateToFolderWithIndexPath( - restCollectionStore.value.state, - collectionIndexPath.split("/").map((id) => parseInt(id)) - ) as HoppCollection - - updatedCollection.name = newCollectionName - - const result = await workspaceService.editRESTCollection( - collectionHandle, - updatedCollection - ) + const result = await workspaceService.updateRESTCollection(collectionHandle, { + name: newChildCollectionName, + }) if (E.isLeft(result)) { // INVALID_COLLECTION_HANDLE return } - if (result.right.value.type === "invalid") { - // COLLECTION_INVALIDATED - return - } - displayModalEditChildCollection(false) toast.success(t("collection.renamed")) } @@ -580,7 +555,7 @@ const onRemoveChildCollection = async () => { return } - const result = await workspaceService.removeRESTChildCollection( + const result = await workspaceService.removeRESTCollection( parentCollectionHandle ) @@ -589,11 +564,6 @@ const onRemoveChildCollection = async () => { return } - if (result.right.value.type === "invalid") { - // COLLECTION_INVALIDATED - return - } - toast.success(t("state.deleted")) displayConfirmModal(false) } @@ -635,11 +605,6 @@ const onRemoveRequest = async () => { return } - if (result.right.value.type === "invalid") { - // WORKSPACE_INVALIDATED - return - } - const possibleTab = tabs.getTabRefWithSaveContext({ originLocation: "workspace-user-collection", requestHandle, @@ -669,6 +634,23 @@ const onRemoveRequest = async () => { const selectRequest = async (requestIndexPath: string) => { const collectionIndexPath = requestIndexPath.split("/").slice(0, -1).join("/") + const collectionHandleResult = await workspaceService.getCollectionHandle( + props.workspaceHandle, + collectionIndexPath + ) + + if (E.isLeft(collectionHandleResult)) { + // INVALID_WORKSPACE_HANDLE + return + } + + const collectionHandle = collectionHandleResult.right + + if (collectionHandle.value.type === "invalid") { + // WORKSPACE_INVALIDATED | INVALID_COLLECTION_HANDLE + return + } + const requestHandleResult = await workspaceService.getRequestHandle( props.workspaceHandle, requestIndexPath @@ -686,15 +668,30 @@ const selectRequest = async (requestIndexPath: string) => { return } - const request = requestHandle.value.data.request as HoppRESTRequest + const request = requestHandle.value.data.request // If there is a request with this save context, switch into it let possibleTab = null - const { auth, headers } = cascadeParentCollectionForHeaderAuth( - collectionIndexPath, - "rest" - ) + const cascadingAuthHeadersHandleResult = + await workspaceService.getRESTCollectionLevelAuthHeadersView( + collectionHandle + ) + + if (E.isLeft(cascadingAuthHeadersHandleResult)) { + // INVALID_COLLECTION_HANDLE + return + } + + const cascadingAuthHeadersHandle = cascadingAuthHeadersHandleResult.right + + if (cascadingAuthHeadersHandle.value.type === "invalid") { + // COLLECTION_INVALIDATED + return + } + + const { auth, headers } = cascadingAuthHeadersHandle.value.data + possibleTab = tabs.getTabRefWithSaveContext({ originLocation: "workspace-user-collection", requestHandle, @@ -766,7 +763,7 @@ const editRequest = (payload: { displayModalEditRequest(true) } -const onEditRequest = async (newReqName: string) => { +const onEditRequest = async (newRequestName: string) => { const requestID = editingRequestIndexPath.value const requestHandleResult = await workspaceService.getRequestHandle( @@ -786,22 +783,16 @@ const onEditRequest = async (newReqName: string) => { return } - const updatedRequest = { - ...requestHandle.value.data.request, - name: newReqName, - } as HoppRESTRequest - - const result = await workspaceService.updateRESTRequest( - requestHandle, - updatedRequest - ) + const result = await workspaceService.updateRESTRequest(requestHandle, { + name: newRequestName, + }) if (E.isLeft(result)) { // INVALID_REQUEST_HANDLE return } - if (result.right.value.type === "invalid") { + if (result.right.type === "invalid") { // REQUEST_INVALIDATED return } @@ -830,18 +821,6 @@ const editCollectionProperties = async (collectionIndexPath: string) => { }, ], } as HoppInheritedProperty - // Have a provider level implementation that returns a view that says what the headesd and auth are - if (parentIndex) { - const { auth, headers } = cascadeParentCollectionForHeaderAuth( - parentIndex, - "rest" - ) - - inheritedProperties = { - auth, - headers, - } - } const collectionHandleResult = await workspaceService.getCollectionHandle( props.workspaceHandle, @@ -860,6 +839,32 @@ const editCollectionProperties = async (collectionIndexPath: string) => { return } + if (parentIndex) { + const cascadingAuthHeadersHandleResult = + await workspaceService.getRESTCollectionLevelAuthHeadersView( + collectionHandle + ) + + if (E.isLeft(cascadingAuthHeadersHandleResult)) { + // INVALID_COLLECTION_HANDLE + return + } + + const cascadingAuthHeadersHandle = cascadingAuthHeadersHandleResult.right + + if (cascadingAuthHeadersHandle.value.type === "invalid") { + // COLLECTION_INVALIDATED + return + } + + const { auth, headers } = cascadingAuthHeadersHandle.value.data + + inheritedProperties = { + auth, + headers, + } + } + const collection = navigateToFolderWithIndexPath( restCollectionState.value, collectionIndexPath.split("/").map((id) => parseInt(id)) @@ -899,35 +904,35 @@ const setCollectionProperties = async (updatedCollectionProps: { return } - // We're sure that the collection exists in the given `collectionIndexPath` as there's a validation happening in `getCollectionHandle` above - const collection = navigateToFolderWithIndexPath( - restCollectionStore.value.state, - collectionIndexPath.split("/").map((id) => parseInt(id)) - ) as HoppCollection - - const updatedCollection = { - ...collection, + const result = await workspaceService.updateRESTCollection(collectionHandle, { auth, headers, - } - - const result = await workspaceService.editRESTCollection( - collectionHandle, - updatedCollection - ) + }) if (E.isLeft(result)) { // INVALID_COLLECTION_HANDLE return } - if (result.right.value.type === "invalid") { + const cascadingAuthHeadersHandleResult = + await workspaceService.getRESTCollectionLevelAuthHeadersView( + collectionHandle + ) + + if (E.isLeft(cascadingAuthHeadersHandleResult)) { + // INVALID_COLLECTION_HANDLE + return + } + + const cascadingAuthHeadersHandle = cascadingAuthHeadersHandleResult.right + + if (cascadingAuthHeadersHandle.value.type === "invalid") { // COLLECTION_INVALIDATED return } const { auth: cascadedAuth, headers: cascadedHeaders } = - cascadeParentCollectionForHeaderAuth(collectionIndexPath, "rest") + cascadingAuthHeadersHandle.value.data nextTick(() => { updateInheritedPropertiesForAffectedRequests( diff --git a/packages/hoppscotch-common/src/helpers/types/HoppInheritedProperties.ts b/packages/hoppscotch-common/src/helpers/types/HoppInheritedProperties.ts index 13c70da07..fa066a886 100644 --- a/packages/hoppscotch-common/src/helpers/types/HoppInheritedProperties.ts +++ b/packages/hoppscotch-common/src/helpers/types/HoppInheritedProperties.ts @@ -17,3 +17,19 @@ export type HoppInheritedProperty = { inheritedHeader: HoppRESTHeader | GQLHeader }[] } + +type ModifiedAuth = { + [K in keyof T]: K extends 'inheritedAuth' ? Extract : T[K] +} + +type ModifiedHeaders = { + [K in keyof T]: K extends 'inheritedHeader' ? Extract : T[K] +} + +type ModifiedHoppInheritedProperty = { + auth: ModifiedAuth + headers: ModifiedHeaders[] +} + +export type HoppInheritedRESTProperty = ModifiedHoppInheritedProperty + diff --git a/packages/hoppscotch-common/src/services/new-workspace/index.ts b/packages/hoppscotch-common/src/services/new-workspace/index.ts index e73bda5e5..ff9d0fc61 100644 --- a/packages/hoppscotch-common/src/services/new-workspace/index.ts +++ b/packages/hoppscotch-common/src/services/new-workspace/index.ts @@ -12,7 +12,7 @@ import { WorkspaceProvider } from "./provider" import { HandleRef } from "./handle" import * as E from "fp-ts/Either" import { Workspace, WorkspaceCollection, WorkspaceRequest } from "./workspace" -import { RESTCollectionChildrenView, RootRESTCollectionView } from "./view" +import { RESTCollectionChildrenView, RESTCollectionLevelAuthHeadersView, RootRESTCollectionView } from "./view" import { HoppCollection, HoppRESTRequest } from "@hoppscotch/data" export type WorkspaceError = @@ -170,8 +170,7 @@ export class NewWorkspaceService extends Service { public async createRESTRootCollection( workspaceHandle: HandleRef, - collectionName: string, - newCollectionID: string + newCollection: Partial ): Promise< E.Either< WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">, @@ -192,8 +191,7 @@ export class NewWorkspaceService extends Service { const result = await provider.createRESTRootCollection( workspaceHandle, - collectionName, - newCollectionID + newCollection ) if (E.isLeft(result)) { @@ -205,7 +203,7 @@ export class NewWorkspaceService extends Service { public async createRESTChildCollection( parentCollectionHandle: HandleRef, - collectionName: string + newChildCollection: Partial ): Promise< E.Either< WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">, @@ -226,7 +224,7 @@ export class NewWorkspaceService extends Service { const result = await provider.createRESTChildCollection( parentCollectionHandle, - collectionName + newChildCollection ) if (E.isLeft(result)) { @@ -236,14 +234,11 @@ export class NewWorkspaceService extends Service { return E.right(result.right) } - public async editRESTCollection( + public async updateRESTCollection( collectionHandle: HandleRef, - updatedCollection: HoppCollection + updatedCollection: Partial ): Promise< - E.Either< - WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">, - HandleRef - > + E.Either, void> > { if (collectionHandle.value.type === "invalid") { return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" }) @@ -257,7 +252,7 @@ export class NewWorkspaceService extends Service { return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" }) } - const result = await provider.editRESTCollection( + const result = await provider.updateRESTCollection( collectionHandle, updatedCollection ) @@ -266,16 +261,13 @@ export class NewWorkspaceService extends Service { return E.left({ type: "PROVIDER_ERROR", error: result.left }) } - return E.right(result.right) + return E.right(undefined) } - public async removeRESTRootCollection( + public async removeRESTCollection( collectionHandle: HandleRef ): Promise< - E.Either< - WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">, - HandleRef - > + E.Either, void> > { if (collectionHandle.value.type === "invalid") { return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" }) @@ -289,44 +281,13 @@ export class NewWorkspaceService extends Service { return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" }) } - const result = await provider.removeRESTRootCollection(collectionHandle) + const result = await provider.removeRESTCollection(collectionHandle) if (E.isLeft(result)) { return E.left({ type: "PROVIDER_ERROR", error: result.left }) } - return E.right(result.right) - } - - public async removeRESTChildCollection( - parentCollectionHandle: HandleRef - ): Promise< - E.Either< - WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">, - HandleRef - > - > { - if (parentCollectionHandle.value.type === "invalid") { - return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" }) - } - - const provider = this.registeredProviders.get( - parentCollectionHandle.value.data.providerID - ) - - if (!provider) { - return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" }) - } - - const result = await provider.removeRESTChildCollection( - parentCollectionHandle - ) - - if (E.isLeft(result)) { - return E.left({ type: "PROVIDER_ERROR", error: result.left }) - } - - return E.right(result.right) + return E.right(undefined) } public async createRESTRequest( @@ -365,10 +326,7 @@ export class NewWorkspaceService extends Service { public async removeRESTRequest( requestHandle: HandleRef ): Promise< - E.Either< - WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">, - HandleRef - > + E.Either, void> > { if (requestHandle.value.type === "invalid") { return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" }) @@ -388,16 +346,16 @@ export class NewWorkspaceService extends Service { return E.left({ type: "PROVIDER_ERROR", error: result.left }) } - return E.right(result.right) + return E.right(undefined) } public async updateRESTRequest( requestHandle: HandleRef, - updatedRequest: HoppRESTRequest + updatedRequest: Partial ): Promise< E.Either< WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">, - HandleRef + HandleRef["value"] > > { if (requestHandle.value.type === "invalid") { @@ -483,6 +441,36 @@ export class NewWorkspaceService extends Service { return E.right(result.right) } + public async getRESTCollectionLevelAuthHeadersView( + collectionHandle: HandleRef + ): Promise< + E.Either< + WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">, + HandleRef + > + > { + if (collectionHandle.value.type === "invalid") { + return E.left({ type: "SERVICE_ERROR", error: "INVALID_HANDLE" }) + } + + const provider = this.registeredProviders.get( + collectionHandle.value.data.providerID + ) + + if (!provider) { + return E.left({ type: "SERVICE_ERROR", error: "INVALID_PROVIDER" }) + } + + const result = + await provider.getRESTCollectionLevelAuthHeadersView(collectionHandle) + + if (E.isLeft(result)) { + return E.left({ type: "PROVIDER_ERROR", error: result.left }) + } + + return E.right(result.right) + } + public registerWorkspaceProvider(provider: WorkspaceProvider) { if (this.registeredProviders.has(provider.providerID)) { console.warn( diff --git a/packages/hoppscotch-common/src/services/new-workspace/provider.ts b/packages/hoppscotch-common/src/services/new-workspace/provider.ts index 62b44f917..2fba7551a 100644 --- a/packages/hoppscotch-common/src/services/new-workspace/provider.ts +++ b/packages/hoppscotch-common/src/services/new-workspace/provider.ts @@ -7,7 +7,11 @@ import { WorkspaceDecor, WorkspaceRequest, } from "./workspace" -import { RESTCollectionChildrenView, RootRESTCollectionView } from "./view" +import { + RESTCollectionLevelAuthHeadersView, + RESTCollectionChildrenView, + RootRESTCollectionView, +} from "./view" import { HoppCollection, HoppRESTRequest } from "@hoppscotch/data" export interface WorkspaceProvider { @@ -33,38 +37,34 @@ export interface WorkspaceProvider { getRESTCollectionChildrenView( collectionHandle: HandleRef ): Promise>> - // getRESTCollectionAuthHeaders( - // collectionHandle: HandleRef - // ): Promise>> + getRESTCollectionLevelAuthHeadersView( + collectionHandle: HandleRef + ): Promise>> createRESTRootCollection( workspaceHandle: HandleRef, - collectionName: string, - newCollectionID: string + newCollection: Partial ): Promise>> createRESTChildCollection( parentCollectionHandle: HandleRef, - collectionName: string + newChildCollection: Partial ): Promise>> - editRESTCollection( + updateRESTCollection( collectionHandle: HandleRef, - updatedCollection: HoppCollection - ): Promise>> - removeRESTRootCollection( + updatedCollection: Partial + ): Promise> + removeRESTCollection( collectionHandle: HandleRef - ): Promise>> - removeRESTChildCollection( - parentCollectionHandle: HandleRef - ): Promise>> + ): Promise> createRESTRequest( parentCollectionHandle: HandleRef, - request: HoppRESTRequest + newRequest: HoppRESTRequest ): Promise>> updateRESTRequest( requestHandle: HandleRef, - updatedRequest: HoppRESTRequest - ): Promise>> + updatedRequest: Partial + ): Promise["value"]>> removeRESTRequest( requestHandle: HandleRef - ): Promise>> + ): Promise> } diff --git a/packages/hoppscotch-common/src/services/new-workspace/providers/personal.workspace.ts b/packages/hoppscotch-common/src/services/new-workspace/providers/personal.workspace.ts index d94531829..bb2136dad 100644 --- a/packages/hoppscotch-common/src/services/new-workspace/providers/personal.workspace.ts +++ b/packages/hoppscotch-common/src/services/new-workspace/providers/personal.workspace.ts @@ -1,4 +1,10 @@ -import { HoppCollection, makeCollection } from "@hoppscotch/data" +import { + HoppCollection, + HoppGQLAuth, + HoppRESTAuth, + HoppRESTHeaders, + makeCollection, +} from "@hoppscotch/data" import { Service } from "dioc" import * as E from "fp-ts/Either" import { Ref, computed, markRaw, ref, shallowRef } from "vue" @@ -24,6 +30,7 @@ import { platform } from "~/platform" import { HandleRef } from "~/services/new-workspace/handle" import { WorkspaceProvider } from "~/services/new-workspace/provider" import { + RESTCollectionLevelAuthHeadersView, RESTCollectionChildrenView, RESTCollectionViewItem, RootRESTCollectionView, @@ -43,6 +50,9 @@ import { resolveSaveContextOnCollectionReorder, getFoldersByPath, } from "~/helpers/collection/collection" +import { HoppGQLHeader } from "~/helpers/graphql" +import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties" +import { computedAsync } from "@vueuse/core" export class PersonalWorkspaceProviderService extends Service @@ -88,8 +98,7 @@ export class PersonalWorkspaceProviderService public createRESTRootCollection( workspaceHandle: HandleRef, - collectionName: string, - newCollectionID: string + newCollection: Partial ): Promise>> { if ( workspaceHandle.value.type !== "ok" || @@ -113,8 +122,12 @@ export class PersonalWorkspaceProviderService } } + const newCollectionName = newCollection.name as string + const newCollectionID = + this.restCollectionState.value.state.length.toString() + const newRootCollection = makeCollection({ - name: collectionName, + name: newCollectionName, folders: [], requests: [], headers: [], @@ -138,7 +151,7 @@ export class PersonalWorkspaceProviderService providerID: this.providerID, workspaceID: workspaceHandle.value.data.workspaceID, collectionID: newCollectionID, - name: collectionName, + name: newCollectionName, }, } }) @@ -147,13 +160,13 @@ export class PersonalWorkspaceProviderService } public createRESTChildCollection( - parentCollHandle: HandleRef, - collectionName: string + parentCollectionHandle: HandleRef, + newChildCollection: Partial ): Promise>> { if ( - parentCollHandle.value.type !== "ok" || - parentCollHandle.value.data.providerID !== this.providerID || - parentCollHandle.value.data.workspaceID !== "personal" + parentCollectionHandle.value.type !== "ok" || + parentCollectionHandle.value.data.providerID !== this.providerID || + parentCollectionHandle.value.data.workspaceID !== "personal" ) { return Promise.resolve(E.left("INVALID_COLLECTION_HANDLE" as const)) } @@ -162,9 +175,9 @@ export class PersonalWorkspaceProviderService E.right( computed(() => { if ( - parentCollHandle.value.type !== "ok" || - parentCollHandle.value.data.providerID !== this.providerID || - parentCollHandle.value.data.workspaceID !== "personal" + parentCollectionHandle.value.type !== "ok" || + parentCollectionHandle.value.data.providerID !== this.providerID || + parentCollectionHandle.value.data.workspaceID !== "personal" ) { return { type: "invalid" as const, @@ -173,9 +186,10 @@ export class PersonalWorkspaceProviderService } const { collectionID, providerID, workspaceID } = - parentCollHandle.value.data + parentCollectionHandle.value.data - addRESTFolder(collectionName, collectionID) + const newCollectionName = newChildCollection.name as string + addRESTFolder(newCollectionName, collectionID) platform.analytics?.logEvent({ type: "HOPP_CREATE_COLLECTION", @@ -190,7 +204,7 @@ export class PersonalWorkspaceProviderService providerID, workspaceID, collectionID, - name: collectionName, + name: newCollectionName, }, } }) @@ -198,186 +212,111 @@ export class PersonalWorkspaceProviderService ) } - public editRESTCollection( - collHandle: HandleRef, - updatedCollection: HoppCollection - ): Promise>> { + public updateRESTCollection( + collectionHandle: HandleRef, + updatedCollection: Partial + ): Promise> { if ( - collHandle.value.type !== "ok" || - collHandle.value.data.providerID !== this.providerID || - collHandle.value.data.workspaceID !== "personal" + collectionHandle.value.type !== "ok" || + collectionHandle.value.data.providerID !== this.providerID || + collectionHandle.value.data.workspaceID !== "personal" ) { return Promise.resolve(E.left("INVALID_WORKSPACE_HANDLE" as const)) } - return Promise.resolve( - E.right( - computed(() => { - if ( - collHandle.value.type !== "ok" || - collHandle.value.data.providerID !== this.providerID || - collHandle.value.data.workspaceID !== "personal" - ) { - return { - type: "invalid" as const, - reason: "WORKSPACE_INVALIDATED" as const, - } - } + const { collectionID } = collectionHandle.value.data - const { collectionID } = collHandle.value.data - - const collection: HoppCollection | null = - navigateToFolderWithIndexPath( - this.restCollectionState.value.state, - collectionID.split("/").map((id) => parseInt(id)) - ) - - if (!collection) { - return { - type: "invalid" as const, - reason: "COLLECTION_NOT_FOUND" as const, - } - } - - const isRootCollection = collectionID.split("/").length === 1 - - if (isRootCollection) { - editRESTCollection(parseInt(collectionID), updatedCollection) - } else { - editRESTFolder(collectionID, updatedCollection) - } - - return { - type: "ok", - data: true, - } - }) - ) + const collection = navigateToFolderWithIndexPath( + this.restCollectionState.value.state, + collectionID.split("/").map((id) => parseInt(id)) ) - } - public removeRESTRootCollection( - collHandle: HandleRef - ): Promise>> { - if ( - collHandle.value.type !== "ok" || - collHandle.value.data.providerID !== this.providerID || - collHandle.value.data.workspaceID !== "personal" - ) { - return Promise.resolve(E.left("INVALID_WORKSPACE_HANDLE" as const)) + const newCollection = { + ...collection, + ...updatedCollection, } - return Promise.resolve( - E.right( - computed(() => { - if ( - collHandle.value.type !== "ok" || - collHandle.value.data.providerID !== this.providerID || - collHandle.value.data.workspaceID !== "personal" - ) { - return { - type: "invalid" as const, - reason: "WORKSPACE_INVALIDATED" as const, - } - } + const isRootCollection = collectionID.split("/").length === 1 - const { collectionID } = collHandle.value.data + if (isRootCollection) { + editRESTCollection(parseInt(collectionID), newCollection) + } else { + editRESTFolder(collectionID, newCollection) + } - const collectionIndex = parseInt(collectionID) - - const collectionToRemove = navigateToFolderWithIndexPath( - restCollectionStore.value.state, - [collectionIndex] - ) - - removeRESTCollection( - collectionIndex, - collectionToRemove ? collectionToRemove.id : undefined - ) - - resolveSaveContextOnCollectionReorder({ - lastIndex: collectionIndex, - newIndex: -1, - folderPath: "", // root collection - length: this.restCollectionState.value.state.length, - }) - - return { - type: "ok", - data: true, - } - }) - ) - ) + return Promise.resolve(E.right(undefined)) } - public removeRESTChildCollection( - parentCollHandle: HandleRef - ): Promise>> { + public removeRESTCollection( + collectionHandle: HandleRef + ): Promise> { if ( - parentCollHandle.value.type !== "ok" || - parentCollHandle.value.data.providerID !== this.providerID || - parentCollHandle.value.data.workspaceID !== "personal" + collectionHandle.value.type !== "ok" || + collectionHandle.value.data.providerID !== this.providerID || + collectionHandle.value.data.workspaceID !== "personal" ) { return Promise.resolve(E.left("INVALID_COLLECTION_HANDLE" as const)) } - return Promise.resolve( - E.right( - computed(() => { - if ( - parentCollHandle.value.type !== "ok" || - parentCollHandle.value.data.providerID !== this.providerID || - parentCollHandle.value.data.workspaceID !== "personal" - ) { - return { - type: "invalid" as const, - reason: "COLLECTION_INVALIDATED" as const, - } - } + const { collectionID } = collectionHandle.value.data - const { collectionID } = parentCollHandle.value.data + const isRootCollection = collectionID.split("/").length === 1 - const folderToRemove = path - ? navigateToFolderWithIndexPath( - restCollectionStore.value.state, - collectionID.split("/").map((id) => parseInt(id)) - ) - : undefined + if (isRootCollection) { + const collectionIndex = parseInt(collectionID) - removeRESTFolder( - collectionID, - folderToRemove ? folderToRemove.id : undefined - ) - - const parentFolder = collectionID.split("/").slice(0, -1).join("/") // remove last folder to get parent folder - resolveSaveContextOnCollectionReorder({ - lastIndex: this.pathToLastIndex(collectionID), - newIndex: -1, - folderPath: parentFolder, - length: getFoldersByPath( - this.restCollectionState.value.state, - parentFolder - ).length, - }) - - return { - type: "ok", - data: true, - } - }) + const collectionToRemove = navigateToFolderWithIndexPath( + restCollectionStore.value.state, + [collectionIndex] ) - ) + + removeRESTCollection( + collectionIndex, + collectionToRemove ? collectionToRemove.id : undefined + ) + + resolveSaveContextOnCollectionReorder({ + lastIndex: collectionIndex, + newIndex: -1, + folderPath: "", // root collection + length: this.restCollectionState.value.state.length, + }) + } else { + const folderToRemove = path + ? navigateToFolderWithIndexPath( + restCollectionStore.value.state, + collectionID.split("/").map((id) => parseInt(id)) + ) + : undefined + + removeRESTFolder( + collectionID, + folderToRemove ? folderToRemove.id : undefined + ) + + const parentFolder = collectionID.split("/").slice(0, -1).join("/") // Remove last folder to get parent folder + resolveSaveContextOnCollectionReorder({ + lastIndex: this.pathToLastIndex(collectionID), + newIndex: -1, + folderPath: parentFolder, + length: getFoldersByPath( + this.restCollectionState.value.state, + parentFolder + ).length, + }) + } + + return Promise.resolve(E.right(undefined)) } public createRESTRequest( - parentCollHandle: HandleRef, + parentCollectionHandle: HandleRef, newRequest: HoppRESTRequest ): Promise>> { if ( - parentCollHandle.value.type !== "ok" || - parentCollHandle.value.data.providerID !== this.providerID || - parentCollHandle.value.data.workspaceID !== "personal" + parentCollectionHandle.value.type !== "ok" || + parentCollectionHandle.value.data.providerID !== this.providerID || + parentCollectionHandle.value.data.workspaceID !== "personal" ) { return Promise.resolve(E.left("INVALID_COLLECTION_HANDLE" as const)) } @@ -386,9 +325,9 @@ export class PersonalWorkspaceProviderService E.right( computed(() => { if ( - parentCollHandle.value.type !== "ok" || - parentCollHandle.value.data.providerID !== this.providerID || - parentCollHandle.value.data.workspaceID !== "personal" + parentCollectionHandle.value.type !== "ok" || + parentCollectionHandle.value.data.providerID !== this.providerID || + parentCollectionHandle.value.data.workspaceID !== "personal" ) { return { type: "invalid" as const, @@ -397,7 +336,7 @@ export class PersonalWorkspaceProviderService } const { collectionID, providerID, workspaceID } = - parentCollHandle.value.data + parentCollectionHandle.value.data const insertionIndex = saveRESTRequestAs(collectionID, newRequest) @@ -427,7 +366,7 @@ export class PersonalWorkspaceProviderService public removeRESTRequest( requestHandle: HandleRef - ): Promise>> { + ): Promise> { if ( requestHandle.value.type !== "ok" || requestHandle.value.data.providerID !== this.providerID || @@ -436,43 +375,23 @@ export class PersonalWorkspaceProviderService return Promise.resolve(E.left("INVALID_REQUEST_HANDLE" as const)) } - return Promise.resolve( - E.right( - computed(() => { - if ( - requestHandle.value.type !== "ok" || - requestHandle.value.data.providerID !== this.providerID || - requestHandle.value.data.workspaceID !== "personal" - ) { - return { - type: "invalid" as const, - reason: "REQUEST_INVALIDATED" as const, - } - } + const { collectionID, requestID } = requestHandle.value.data + const requestIndex = parseInt(requestID.split("/").slice(-1)[0]) - const { collectionID, requestID } = requestHandle.value.data - const requestIndex = parseInt(requestID.split("/").slice(-1)[0]) + const requestToRemove = navigateToFolderWithIndexPath( + restCollectionStore.value.state, + collectionID.split("/").map((id) => parseInt(id)) + )?.requests[requestIndex] - const requestToRemove = navigateToFolderWithIndexPath( - restCollectionStore.value.state, - collectionID.split("/").map((id) => parseInt(id)) - )?.requests[requestIndex] + removeRESTRequest(collectionID, requestIndex, requestToRemove?.id) - removeRESTRequest(collectionID, requestIndex, requestToRemove?.id) - - return { - type: "ok", - data: true, - } - }) - ) - ) + return Promise.resolve(E.right(undefined)) } public updateRESTRequest( requestHandle: HandleRef, - updatedRequest: HoppRESTRequest - ): Promise>> { + updatedRequest: Partial + ): Promise["value"]>> { if ( requestHandle.value.type !== "ok" || requestHandle.value.data.providerID !== this.providerID || @@ -481,45 +400,36 @@ export class PersonalWorkspaceProviderService return Promise.resolve(E.left("INVALID_REQUEST_HANDLE" as const)) } - return Promise.resolve( - E.right( - computed(() => { - if ( - requestHandle.value.type !== "ok" || - requestHandle.value.data.providerID !== this.providerID || - requestHandle.value.data.workspaceID !== "personal" - ) { - return { - type: "invalid" as const, - reason: "REQUEST_INVALIDATED" as const, - } - } + const { collectionID, requestID, request } = requestHandle.value.data - const { collectionID, requestID } = requestHandle.value.data + try { + const newRequest: HoppRESTRequest = { + ...request, + ...updatedRequest, + } + const requestIndex = parseInt(requestID) + editRESTRequest(collectionID, requestIndex, newRequest) - try { - const requestIndex = parseInt(requestID) - editRESTRequest(collectionID, requestIndex, updatedRequest) - - platform.analytics?.logEvent({ - type: "HOPP_SAVE_REQUEST", - platform: "rest", - createdNow: false, - workspaceType: "personal", - }) - } catch (err) { - return { - type: "invalid" as const, - reason: "REQUEST_PATH_NOT_FOUND" as const, - } - } - - return { - type: "ok", - data: true, - } + platform.analytics?.logEvent({ + type: "HOPP_SAVE_REQUEST", + platform: "rest", + createdNow: false, + workspaceType: "personal", + }) + } catch (err) { + return Promise.resolve( + E.right({ + type: "invalid" as const, + reason: "REQUEST_PATH_NOT_FOUND" as const, }) ) + } + + return Promise.resolve( + E.right({ + type: "ok", + data: true, + }) ) } @@ -766,6 +676,117 @@ export class PersonalWorkspaceProviderService ) } + public getRESTCollectionLevelAuthHeadersView( + collectionHandle: HandleRef + ): Promise>> { + return Promise.resolve( + E.right( + computed(() => { + if ( + collectionHandle.value.type === "invalid" || + collectionHandle.value.data.providerID !== this.providerID || + collectionHandle.value.data.workspaceID !== "personal" + ) { + return { + type: "invalid" as const, + reason: "INVALID_COLLECTION_HANDLE" as const, + } + } + + const { collectionID } = collectionHandle.value.data + + let auth: HoppInheritedProperty["auth"] = { + parentID: collectionID ?? "", + parentName: "", + inheritedAuth: { + authType: "none", + authActive: true, + }, + } + const headers: HoppInheritedProperty["headers"] = [] + + if (!collectionID) return { type: "ok", data: { auth, headers } } + + const path = collectionID.split("/").map((i) => parseInt(i)) + + // Check if the path is empty or invalid + if (!path || path.length === 0) { + console.error("Invalid path:", collectionID) + return { type: "ok", data: { auth, headers } } + } + + // Loop through the path and get the last parent folder with authType other than 'inherit' + for (let i = 0; i < path.length; i++) { + const parentFolder = navigateToFolderWithIndexPath( + this.restCollectionState.value.state, + [...path.slice(0, i + 1)] // Create a copy of the path array + ) + + // Check if parentFolder is undefined or null + if (!parentFolder) { + console.error("Parent folder not found for path:", path) + return { type: "ok", data: { auth, headers } } + } + + const parentFolderAuth = parentFolder.auth as + | HoppRESTAuth + | HoppGQLAuth + const parentFolderHeaders = parentFolder.headers as + | HoppRESTHeaders + | HoppGQLHeader[] + + // check if the parent folder has authType 'inherit' and if it is the root folder + if ( + parentFolderAuth?.authType === "inherit" && + [...path.slice(0, i + 1)].length === 1 + ) { + auth = { + parentID: [...path.slice(0, i + 1)].join("/"), + parentName: parentFolder.name, + inheritedAuth: auth.inheritedAuth, + } + } + + if (parentFolderAuth?.authType !== "inherit") { + auth = { + parentID: [...path.slice(0, i + 1)].join("/"), + parentName: parentFolder.name, + inheritedAuth: parentFolderAuth, + } + } + + // Update headers, overwriting duplicates by key + if (parentFolderHeaders) { + const activeHeaders = parentFolderHeaders.filter((h) => h.active) + activeHeaders.forEach((header) => { + const index = headers.findIndex( + (h) => h.inheritedHeader?.key === header.key + ) + const currentPath = [...path.slice(0, i + 1)].join("/") + if (index !== -1) { + // Replace the existing header with the same key + headers[index] = { + parentID: currentPath, + parentName: parentFolder.name, + inheritedHeader: header, + } + } else { + headers.push({ + parentID: currentPath, + parentName: parentFolder.name, + inheritedHeader: header, + }) + } + }) + } + } + + return { type: "ok", data: { auth, headers } } + }) + ) + ) + } + public getWorkspaceHandle( workspaceID: string ): Promise>> { diff --git a/packages/hoppscotch-common/src/services/new-workspace/view.ts b/packages/hoppscotch-common/src/services/new-workspace/view.ts index fc6a97ce9..2eaa01f9c 100644 --- a/packages/hoppscotch-common/src/services/new-workspace/view.ts +++ b/packages/hoppscotch-common/src/services/new-workspace/view.ts @@ -1,5 +1,11 @@ import { HoppRESTRequest } from "@hoppscotch/data" import { Ref } from "vue" +import { HoppInheritedRESTProperty } from "~/helpers/types/HoppInheritedProperties" + +export type RESTCollectionLevelAuthHeadersView = { + auth: HoppInheritedRESTProperty["auth"] + headers: HoppInheritedRESTProperty["headers"] +} export type RESTCollectionViewCollection = { collectionID: string