feat: extend duplicate collection to personal workspace in SH (#4368)
This commit is contained in:
@@ -102,11 +102,7 @@
|
|||||||
@keyup.r="requestAction?.$el.click()"
|
@keyup.r="requestAction?.$el.click()"
|
||||||
@keyup.n="folderAction?.$el.click()"
|
@keyup.n="folderAction?.$el.click()"
|
||||||
@keyup.e="edit?.$el.click()"
|
@keyup.e="edit?.$el.click()"
|
||||||
@keyup.d="
|
@keyup.d="duplicateAction?.$el.click()"
|
||||||
showDuplicateCollectionAction
|
|
||||||
? duplicateAction?.$el.click()
|
|
||||||
: null
|
|
||||||
"
|
|
||||||
@keyup.delete="deleteAction?.$el.click()"
|
@keyup.delete="deleteAction?.$el.click()"
|
||||||
@keyup.x="exportAction?.$el.click()"
|
@keyup.x="exportAction?.$el.click()"
|
||||||
@keyup.p="propertiesAction?.$el.click()"
|
@keyup.p="propertiesAction?.$el.click()"
|
||||||
@@ -150,7 +146,6 @@
|
|||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<HoppSmartItem
|
<HoppSmartItem
|
||||||
v-if="showDuplicateCollectionAction"
|
|
||||||
ref="duplicateAction"
|
ref="duplicateAction"
|
||||||
:icon="IconCopy"
|
:icon="IconCopy"
|
||||||
:label="t('action.duplicate')"
|
:label="t('action.duplicate')"
|
||||||
@@ -370,21 +365,6 @@ const collectionName = computed(() => {
|
|||||||
return (props.data as TeamCollection).title
|
return (props.data as TeamCollection).title
|
||||||
})
|
})
|
||||||
|
|
||||||
const showDuplicateCollectionAction = computed(() => {
|
|
||||||
// Show if the user is not logged in
|
|
||||||
if (!currentUser.value) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (props.collectionsType === "team-collections") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Duplicate collection action is disabled on SH until the issue with syncing is resolved
|
|
||||||
return !platform.platformFeatureFlags
|
|
||||||
.duplicateCollectionDisabledInPersonalWorkspace
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => [props.exportLoading, props.duplicateCollectionLoading],
|
() => [props.exportLoading, props.duplicateCollectionLoading],
|
||||||
([newExportLoadingVal, newDuplicateCollectionLoadingVal]) => {
|
([newExportLoadingVal, newDuplicateCollectionLoadingVal]) => {
|
||||||
|
|||||||
@@ -73,11 +73,7 @@
|
|||||||
@keyup.r="requestAction.$el.click()"
|
@keyup.r="requestAction.$el.click()"
|
||||||
@keyup.n="folderAction.$el.click()"
|
@keyup.n="folderAction.$el.click()"
|
||||||
@keyup.e="edit.$el.click()"
|
@keyup.e="edit.$el.click()"
|
||||||
@keyup.d="
|
@keyup.d="duplicateAction.$el.click()"
|
||||||
showDuplicateCollectionAction
|
|
||||||
? duplicateAction.$el.click()
|
|
||||||
: null
|
|
||||||
"
|
|
||||||
@keyup.delete="deleteAction.$el.click()"
|
@keyup.delete="deleteAction.$el.click()"
|
||||||
@keyup.p="propertiesAction.$el.click()"
|
@keyup.p="propertiesAction.$el.click()"
|
||||||
@keyup.escape="hide()"
|
@keyup.escape="hide()"
|
||||||
@@ -123,7 +119,6 @@
|
|||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<HoppSmartItem
|
<HoppSmartItem
|
||||||
v-if="showDuplicateCollectionAction"
|
|
||||||
ref="duplicateAction"
|
ref="duplicateAction"
|
||||||
:icon="IconCopy"
|
:icon="IconCopy"
|
||||||
:label="t('action.duplicate')"
|
:label="t('action.duplicate')"
|
||||||
@@ -355,17 +350,6 @@ const collectionIcon = computed(() => {
|
|||||||
return IconFolder
|
return IconFolder
|
||||||
})
|
})
|
||||||
|
|
||||||
const showDuplicateCollectionAction = computed(() => {
|
|
||||||
// Show if the user is not logged in
|
|
||||||
if (!currentUser.value) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Duplicate collection action is disabled on SH until the issue with syncing is resolved
|
|
||||||
return !platform.platformFeatureFlags
|
|
||||||
.duplicateCollectionDisabledInPersonalWorkspace
|
|
||||||
})
|
|
||||||
|
|
||||||
const pick = () => {
|
const pick = () => {
|
||||||
emit("select", {
|
emit("select", {
|
||||||
pickedType: "gql-my-collection",
|
pickedType: "gql-my-collection",
|
||||||
|
|||||||
@@ -70,11 +70,7 @@
|
|||||||
@keyup.r="requestAction.$el.click()"
|
@keyup.r="requestAction.$el.click()"
|
||||||
@keyup.n="folderAction.$el.click()"
|
@keyup.n="folderAction.$el.click()"
|
||||||
@keyup.e="edit.$el.click()"
|
@keyup.e="edit.$el.click()"
|
||||||
@keyup.d="
|
@keyup.d="duplicateAction.$el.click()"
|
||||||
showDuplicateCollectionAction
|
|
||||||
? duplicateAction.$el.click()
|
|
||||||
: null
|
|
||||||
"
|
|
||||||
@keyup.delete="deleteAction.$el.click()"
|
@keyup.delete="deleteAction.$el.click()"
|
||||||
@keyup.p="propertiesAction.$el.click()"
|
@keyup.p="propertiesAction.$el.click()"
|
||||||
@keyup.escape="hide()"
|
@keyup.escape="hide()"
|
||||||
@@ -116,7 +112,6 @@
|
|||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<HoppSmartItem
|
<HoppSmartItem
|
||||||
v-if="showDuplicateCollectionAction"
|
|
||||||
ref="duplicateAction"
|
ref="duplicateAction"
|
||||||
:icon="IconCopy"
|
:icon="IconCopy"
|
||||||
:label="t('action.duplicate')"
|
:label="t('action.duplicate')"
|
||||||
@@ -319,17 +314,6 @@ const collectionIcon = computed(() => {
|
|||||||
return IconFolder
|
return IconFolder
|
||||||
})
|
})
|
||||||
|
|
||||||
const showDuplicateCollectionAction = computed(() => {
|
|
||||||
// Show if the user is not logged in
|
|
||||||
if (!currentUser.value) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Duplicate collection action is disabled on SH until the issue with syncing is resolved
|
|
||||||
return !platform.platformFeatureFlags
|
|
||||||
.duplicateCollectionDisabledInPersonalWorkspace
|
|
||||||
})
|
|
||||||
|
|
||||||
const pick = () => {
|
const pick = () => {
|
||||||
emit("select", {
|
emit("select", {
|
||||||
pickedType: "gql-my-folder",
|
pickedType: "gql-my-folder",
|
||||||
|
|||||||
@@ -53,12 +53,6 @@ export type PlatformDef = {
|
|||||||
* Whether to show the A/B testing workspace switcher click login flow or not
|
* Whether to show the A/B testing workspace switcher click login flow or not
|
||||||
*/
|
*/
|
||||||
workspaceSwitcherLogin?: Ref<boolean>
|
workspaceSwitcherLogin?: Ref<boolean>
|
||||||
|
|
||||||
/**
|
|
||||||
* There's an active issue wrt syncing in personal workspace under SH while duplicating a collection
|
|
||||||
* This is a temporary flag to disable the same
|
|
||||||
*/
|
|
||||||
duplicateCollectionDisabledInPersonalWorkspace?: boolean
|
|
||||||
}
|
}
|
||||||
infra?: InfraPlatformDef
|
infra?: InfraPlatformDef
|
||||||
experiments?: ExperimentsPlatformDef
|
experiments?: ExperimentsPlatformDef
|
||||||
|
|||||||
@@ -6,5 +6,6 @@ subscription UserCollectionCreated {
|
|||||||
id
|
id
|
||||||
title
|
title
|
||||||
type
|
type
|
||||||
|
data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
subscription UserCollectionDuplicated {
|
||||||
|
userCollectionDuplicated {
|
||||||
|
id
|
||||||
|
parentID
|
||||||
|
title
|
||||||
|
type
|
||||||
|
data
|
||||||
|
childCollections
|
||||||
|
requests {
|
||||||
|
id
|
||||||
|
request
|
||||||
|
collectionID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,67 +4,68 @@ import {
|
|||||||
runMutation,
|
runMutation,
|
||||||
} from "@hoppscotch/common/helpers/backend/GQLClient"
|
} from "@hoppscotch/common/helpers/backend/GQLClient"
|
||||||
import {
|
import {
|
||||||
|
CreateGqlChildUserCollectionDocument,
|
||||||
|
CreateGqlChildUserCollectionMutation,
|
||||||
|
CreateGqlChildUserCollectionMutationVariables,
|
||||||
|
CreateGqlRootUserCollectionDocument,
|
||||||
|
CreateGqlRootUserCollectionMutation,
|
||||||
|
CreateGqlRootUserCollectionMutationVariables,
|
||||||
|
CreateGqlUserRequestDocument,
|
||||||
|
CreateGqlUserRequestMutation,
|
||||||
|
CreateGqlUserRequestMutationVariables,
|
||||||
|
CreateRestChildUserCollectionDocument,
|
||||||
|
CreateRestChildUserCollectionMutation,
|
||||||
|
CreateRestChildUserCollectionMutationVariables,
|
||||||
CreateRestRootUserCollectionDocument,
|
CreateRestRootUserCollectionDocument,
|
||||||
CreateRestRootUserCollectionMutation,
|
CreateRestRootUserCollectionMutation,
|
||||||
CreateRestRootUserCollectionMutationVariables,
|
CreateRestRootUserCollectionMutationVariables,
|
||||||
|
CreateRestUserRequestDocument,
|
||||||
CreateRestUserRequestMutation,
|
CreateRestUserRequestMutation,
|
||||||
CreateRestUserRequestMutationVariables,
|
CreateRestUserRequestMutationVariables,
|
||||||
CreateRestUserRequestDocument,
|
DeleteUserCollectionDocument,
|
||||||
CreateRestChildUserCollectionMutation,
|
|
||||||
CreateRestChildUserCollectionMutationVariables,
|
|
||||||
CreateRestChildUserCollectionDocument,
|
|
||||||
DeleteUserCollectionMutation,
|
DeleteUserCollectionMutation,
|
||||||
DeleteUserCollectionMutationVariables,
|
DeleteUserCollectionMutationVariables,
|
||||||
DeleteUserCollectionDocument,
|
DeleteUserRequestDocument,
|
||||||
RenameUserCollectionMutation,
|
|
||||||
RenameUserCollectionMutationVariables,
|
|
||||||
RenameUserCollectionDocument,
|
|
||||||
MoveUserCollectionMutation,
|
|
||||||
MoveUserCollectionMutationVariables,
|
|
||||||
MoveUserCollectionDocument,
|
|
||||||
DeleteUserRequestMutation,
|
DeleteUserRequestMutation,
|
||||||
DeleteUserRequestMutationVariables,
|
DeleteUserRequestMutationVariables,
|
||||||
DeleteUserRequestDocument,
|
ExportUserCollectionsToJsonDocument,
|
||||||
|
ExportUserCollectionsToJsonQuery,
|
||||||
|
ExportUserCollectionsToJsonQueryVariables,
|
||||||
|
GetGqlRootUserCollectionsDocument,
|
||||||
|
GetGqlRootUserCollectionsQuery,
|
||||||
|
GetGqlRootUserCollectionsQueryVariables,
|
||||||
|
GetUserRootCollectionsDocument,
|
||||||
|
GetUserRootCollectionsQuery,
|
||||||
|
GetUserRootCollectionsQueryVariables,
|
||||||
|
MoveUserCollectionDocument,
|
||||||
|
MoveUserCollectionMutation,
|
||||||
|
MoveUserCollectionMutationVariables,
|
||||||
MoveUserRequestDocument,
|
MoveUserRequestDocument,
|
||||||
MoveUserRequestMutation,
|
MoveUserRequestMutation,
|
||||||
MoveUserRequestMutationVariables,
|
MoveUserRequestMutationVariables,
|
||||||
UpdateUserCollectionOrderMutation,
|
RenameUserCollectionDocument,
|
||||||
UpdateUserCollectionOrderMutationVariables,
|
RenameUserCollectionMutation,
|
||||||
UpdateUserCollectionOrderDocument,
|
RenameUserCollectionMutationVariables,
|
||||||
GetUserRootCollectionsQuery,
|
ReqType,
|
||||||
GetUserRootCollectionsQueryVariables,
|
UpdateGqlUserRequestDocument,
|
||||||
GetUserRootCollectionsDocument,
|
|
||||||
UserCollectionCreatedDocument,
|
|
||||||
UserCollectionUpdatedDocument,
|
|
||||||
UserCollectionRemovedDocument,
|
|
||||||
UserCollectionMovedDocument,
|
|
||||||
UserCollectionOrderUpdatedDocument,
|
|
||||||
ExportUserCollectionsToJsonQuery,
|
|
||||||
ExportUserCollectionsToJsonQueryVariables,
|
|
||||||
ExportUserCollectionsToJsonDocument,
|
|
||||||
UserRequestCreatedDocument,
|
|
||||||
UserRequestUpdatedDocument,
|
|
||||||
UserRequestMovedDocument,
|
|
||||||
UserRequestDeletedDocument,
|
|
||||||
UpdateRestUserRequestMutation,
|
|
||||||
UpdateRestUserRequestMutationVariables,
|
|
||||||
UpdateRestUserRequestDocument,
|
|
||||||
CreateGqlRootUserCollectionMutation,
|
|
||||||
CreateGqlRootUserCollectionMutationVariables,
|
|
||||||
CreateGqlRootUserCollectionDocument,
|
|
||||||
CreateGqlUserRequestMutation,
|
|
||||||
CreateGqlUserRequestMutationVariables,
|
|
||||||
CreateGqlUserRequestDocument,
|
|
||||||
CreateGqlChildUserCollectionMutation,
|
|
||||||
CreateGqlChildUserCollectionMutationVariables,
|
|
||||||
CreateGqlChildUserCollectionDocument,
|
|
||||||
UpdateGqlUserRequestMutation,
|
UpdateGqlUserRequestMutation,
|
||||||
UpdateGqlUserRequestMutationVariables,
|
UpdateGqlUserRequestMutationVariables,
|
||||||
UpdateGqlUserRequestDocument,
|
UpdateRestUserRequestDocument,
|
||||||
GetGqlRootUserCollectionsQuery,
|
UpdateRestUserRequestMutation,
|
||||||
GetGqlRootUserCollectionsQueryVariables,
|
UpdateRestUserRequestMutationVariables,
|
||||||
GetGqlRootUserCollectionsDocument,
|
UpdateUserCollectionOrderDocument,
|
||||||
ReqType,
|
UpdateUserCollectionOrderMutation,
|
||||||
|
UpdateUserCollectionOrderMutationVariables,
|
||||||
|
UserCollectionCreatedDocument,
|
||||||
|
UserCollectionDuplicatedDocument,
|
||||||
|
UserCollectionMovedDocument,
|
||||||
|
UserCollectionOrderUpdatedDocument,
|
||||||
|
UserCollectionRemovedDocument,
|
||||||
|
UserCollectionUpdatedDocument,
|
||||||
|
UserRequestCreatedDocument,
|
||||||
|
UserRequestDeletedDocument,
|
||||||
|
UserRequestMovedDocument,
|
||||||
|
UserRequestUpdatedDocument,
|
||||||
} from "../../api/generated/graphql"
|
} from "../../api/generated/graphql"
|
||||||
|
|
||||||
export const createRESTRootUserCollection = (title: string) =>
|
export const createRESTRootUserCollection = (title: string) =>
|
||||||
@@ -292,6 +293,12 @@ export const runUserCollectionOrderUpdatedSubscription = () =>
|
|||||||
variables: {},
|
variables: {},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const runUserCollectionDuplicatedSubscription = () =>
|
||||||
|
runGQLSubscription({
|
||||||
|
query: UserCollectionDuplicatedDocument,
|
||||||
|
variables: {},
|
||||||
|
})
|
||||||
|
|
||||||
export const runUserRequestCreatedSubscription = () =>
|
export const runUserRequestCreatedSubscription = () =>
|
||||||
runGQLSubscription({ query: UserRequestCreatedDocument, variables: {} })
|
runGQLSubscription({ query: UserRequestCreatedDocument, variables: {} })
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { authEvents$, def as platformAuth } from "@platform/auth"
|
|
||||||
import { CollectionsPlatformDef } from "@hoppscotch/common/platform/collections"
|
import { CollectionsPlatformDef } from "@hoppscotch/common/platform/collections"
|
||||||
|
import { authEvents$, def as platformAuth } from "@platform/auth"
|
||||||
import { runDispatchWithOutSyncing } from "../../lib/sync"
|
import { runDispatchWithOutSyncing } from "../../lib/sync"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
exportUserCollectionsToJSON,
|
exportUserCollectionsToJSON,
|
||||||
runUserCollectionCreatedSubscription,
|
runUserCollectionCreatedSubscription,
|
||||||
|
runUserCollectionDuplicatedSubscription,
|
||||||
runUserCollectionMovedSubscription,
|
runUserCollectionMovedSubscription,
|
||||||
runUserCollectionOrderUpdatedSubscription,
|
runUserCollectionOrderUpdatedSubscription,
|
||||||
runUserCollectionRemovedSubscription,
|
runUserCollectionRemovedSubscription,
|
||||||
@@ -16,44 +17,51 @@ import {
|
|||||||
} from "./collections.api"
|
} from "./collections.api"
|
||||||
import { collectionsSyncer, getStoreByCollectionType } from "./collections.sync"
|
import { collectionsSyncer, getStoreByCollectionType } from "./collections.sync"
|
||||||
|
|
||||||
import * as E from "fp-ts/Either"
|
|
||||||
import {
|
|
||||||
addRESTCollection,
|
|
||||||
setRESTCollections,
|
|
||||||
editRESTCollection,
|
|
||||||
removeRESTCollection,
|
|
||||||
moveRESTFolder,
|
|
||||||
updateRESTCollectionOrder,
|
|
||||||
saveRESTRequestAs,
|
|
||||||
navigateToFolderWithIndexPath,
|
|
||||||
editRESTRequest,
|
|
||||||
removeRESTRequest,
|
|
||||||
moveRESTRequest,
|
|
||||||
updateRESTRequestOrder,
|
|
||||||
addRESTFolder,
|
|
||||||
editRESTFolder,
|
|
||||||
removeRESTFolder,
|
|
||||||
addGraphqlFolder,
|
|
||||||
addGraphqlCollection,
|
|
||||||
editGraphqlFolder,
|
|
||||||
editGraphqlCollection,
|
|
||||||
removeGraphqlFolder,
|
|
||||||
removeGraphqlCollection,
|
|
||||||
saveGraphqlRequestAs,
|
|
||||||
editGraphqlRequest,
|
|
||||||
moveGraphqlRequest,
|
|
||||||
removeGraphqlRequest,
|
|
||||||
setGraphqlCollections,
|
|
||||||
restCollectionStore,
|
|
||||||
} from "@hoppscotch/common/newstore/collections"
|
|
||||||
import { runGQLSubscription } from "@hoppscotch/common/helpers/backend/GQLClient"
|
import { runGQLSubscription } from "@hoppscotch/common/helpers/backend/GQLClient"
|
||||||
import {
|
import {
|
||||||
|
addGraphqlCollection,
|
||||||
|
addGraphqlFolder,
|
||||||
|
addRESTCollection,
|
||||||
|
addRESTFolder,
|
||||||
|
editGraphqlCollection,
|
||||||
|
editGraphqlFolder,
|
||||||
|
editGraphqlRequest,
|
||||||
|
editRESTCollection,
|
||||||
|
editRESTFolder,
|
||||||
|
editRESTRequest,
|
||||||
|
moveGraphqlRequest,
|
||||||
|
moveRESTFolder,
|
||||||
|
moveRESTRequest,
|
||||||
|
navigateToFolderWithIndexPath,
|
||||||
|
removeGraphqlCollection,
|
||||||
|
removeGraphqlFolder,
|
||||||
|
removeGraphqlRequest,
|
||||||
|
removeRESTCollection,
|
||||||
|
removeRESTFolder,
|
||||||
|
removeRESTRequest,
|
||||||
|
restCollectionStore,
|
||||||
|
saveGraphqlRequestAs,
|
||||||
|
saveRESTRequestAs,
|
||||||
|
setGraphqlCollections,
|
||||||
|
setRESTCollections,
|
||||||
|
updateRESTCollectionOrder,
|
||||||
|
updateRESTRequestOrder,
|
||||||
|
} from "@hoppscotch/common/newstore/collections"
|
||||||
|
import {
|
||||||
|
GQLHeader,
|
||||||
HoppCollection,
|
HoppCollection,
|
||||||
HoppGQLRequest,
|
HoppGQLRequest,
|
||||||
|
HoppRESTHeaders,
|
||||||
|
HoppRESTParam,
|
||||||
HoppRESTRequest,
|
HoppRESTRequest,
|
||||||
} from "@hoppscotch/data"
|
} from "@hoppscotch/data"
|
||||||
|
import * as E from "fp-ts/Either"
|
||||||
|
import {
|
||||||
|
ReqType,
|
||||||
|
UserCollectionDuplicatedData,
|
||||||
|
UserRequest,
|
||||||
|
} from "../../api/generated/graphql"
|
||||||
import { gqlCollectionsSyncer } from "./gqlCollections.sync"
|
import { gqlCollectionsSyncer } from "./gqlCollections.sync"
|
||||||
import { ReqType } from "../../api/generated/graphql"
|
|
||||||
|
|
||||||
function initCollectionsSync() {
|
function initCollectionsSync() {
|
||||||
const currentUser$ = platformAuth.getCurrentUserStream()
|
const currentUser$ = platformAuth.getCurrentUserStream()
|
||||||
@@ -89,6 +97,7 @@ type ExportedUserCollectionREST = {
|
|||||||
folders: ExportedUserCollectionREST[]
|
folders: ExportedUserCollectionREST[]
|
||||||
requests: Array<HoppRESTRequest & { id: string }>
|
requests: Array<HoppRESTRequest & { id: string }>
|
||||||
name: string
|
name: string
|
||||||
|
data: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExportedUserCollectionGQL = {
|
type ExportedUserCollectionGQL = {
|
||||||
@@ -96,6 +105,16 @@ type ExportedUserCollectionGQL = {
|
|||||||
folders: ExportedUserCollectionGQL[]
|
folders: ExportedUserCollectionGQL[]
|
||||||
requests: Array<HoppGQLRequest & { id: string }>
|
requests: Array<HoppGQLRequest & { id: string }>
|
||||||
name: string
|
name: string
|
||||||
|
data: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function addDescriptionField(
|
||||||
|
candidate: HoppRESTHeaders | GQLHeader[] | HoppRESTParam[]
|
||||||
|
) {
|
||||||
|
return candidate.map((item) => ({
|
||||||
|
...item,
|
||||||
|
description: "description" in item ? item.description : "",
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
function exportedCollectionToHoppCollection(
|
function exportedCollectionToHoppCollection(
|
||||||
@@ -105,9 +124,17 @@ function exportedCollectionToHoppCollection(
|
|||||||
if (collectionType == "REST") {
|
if (collectionType == "REST") {
|
||||||
const restCollection = collection as ExportedUserCollectionREST
|
const restCollection = collection as ExportedUserCollectionREST
|
||||||
|
|
||||||
|
const data =
|
||||||
|
restCollection.data && restCollection.data !== "null"
|
||||||
|
? JSON.parse(restCollection.data)
|
||||||
|
: {
|
||||||
|
auth: { authType: "inherit", authActive: false },
|
||||||
|
headers: [],
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: restCollection.id,
|
id: restCollection.id,
|
||||||
v: 1,
|
v: 4,
|
||||||
name: restCollection.name,
|
name: restCollection.name,
|
||||||
folders: restCollection.folders.map((folder) =>
|
folders: restCollection.folders.map((folder) =>
|
||||||
exportedCollectionToHoppCollection(folder, collectionType)
|
exportedCollectionToHoppCollection(folder, collectionType)
|
||||||
@@ -133,42 +160,70 @@ function exportedCollectionToHoppCollection(
|
|||||||
requestVariables,
|
requestVariables,
|
||||||
responses,
|
responses,
|
||||||
} = request
|
} = request
|
||||||
|
|
||||||
|
const resolvedParams = addDescriptionField(params)
|
||||||
|
const resolvedHeaders = addDescriptionField(headers)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
v,
|
v,
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
endpoint,
|
endpoint,
|
||||||
method,
|
method,
|
||||||
params,
|
params: resolvedParams,
|
||||||
|
requestVariables,
|
||||||
auth,
|
auth,
|
||||||
headers,
|
headers: resolvedHeaders,
|
||||||
body,
|
body,
|
||||||
preRequestScript,
|
preRequestScript,
|
||||||
testScript,
|
testScript,
|
||||||
requestVariables,
|
|
||||||
responses,
|
responses,
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
auth: data.auth,
|
||||||
|
headers: addDescriptionField(data.headers),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const gqlCollection = collection as ExportedUserCollectionGQL
|
const gqlCollection = collection as ExportedUserCollectionGQL
|
||||||
|
|
||||||
|
const data =
|
||||||
|
gqlCollection.data && gqlCollection.data !== "null"
|
||||||
|
? JSON.parse(gqlCollection.data)
|
||||||
|
: {
|
||||||
|
auth: { authType: "inherit", authActive: false },
|
||||||
|
headers: [],
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: gqlCollection.id,
|
id: gqlCollection.id,
|
||||||
v: 1,
|
v: 4,
|
||||||
name: gqlCollection.name,
|
name: gqlCollection.name,
|
||||||
folders: gqlCollection.folders.map((folder) =>
|
folders: gqlCollection.folders.map((folder) =>
|
||||||
exportedCollectionToHoppCollection(folder, collectionType)
|
exportedCollectionToHoppCollection(folder, collectionType)
|
||||||
),
|
),
|
||||||
requests: gqlCollection.requests.map(
|
requests: gqlCollection.requests.map((request) => {
|
||||||
({ v, auth, headers, name, id }) => ({
|
const requestParsedResult = HoppGQLRequest.safeParse(request)
|
||||||
|
if (requestParsedResult.type === "ok") {
|
||||||
|
return requestParsedResult.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const { v, auth, headers, name, id, query, url, variables } = request
|
||||||
|
|
||||||
|
const resolvedHeaders = addDescriptionField(headers)
|
||||||
|
|
||||||
|
return {
|
||||||
id,
|
id,
|
||||||
v,
|
v,
|
||||||
auth,
|
auth,
|
||||||
headers,
|
headers: resolvedHeaders,
|
||||||
name,
|
name,
|
||||||
})
|
query,
|
||||||
) as HoppGQLRequest[],
|
url,
|
||||||
|
variables,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
auth: data.auth,
|
||||||
|
headers: addDescriptionField(data.headers),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,7 +233,6 @@ async function loadUserCollections(collectionType: "REST" | "GQL") {
|
|||||||
undefined,
|
undefined,
|
||||||
collectionType == "REST" ? ReqType.Rest : ReqType.Gql
|
collectionType == "REST" ? ReqType.Rest : ReqType.Gql
|
||||||
)
|
)
|
||||||
|
|
||||||
if (E.isRight(res)) {
|
if (E.isRight(res)) {
|
||||||
const collectionsJSONString =
|
const collectionsJSONString =
|
||||||
res.right.exportUserCollectionsToJSON.exportedCollection
|
res.right.exportUserCollectionsToJSON.exportedCollection
|
||||||
@@ -187,7 +241,6 @@ async function loadUserCollections(collectionType: "REST" | "GQL") {
|
|||||||
ExportedUserCollectionGQL | ExportedUserCollectionREST
|
ExportedUserCollectionGQL | ExportedUserCollectionREST
|
||||||
>
|
>
|
||||||
).map((collection) => ({ v: 1, ...collection }))
|
).map((collection) => ({ v: 1, ...collection }))
|
||||||
|
|
||||||
runDispatchWithOutSyncing(() => {
|
runDispatchWithOutSyncing(() => {
|
||||||
collectionType == "REST"
|
collectionType == "REST"
|
||||||
? setRESTCollections(
|
? setRESTCollections(
|
||||||
@@ -221,6 +274,9 @@ function setupSubscriptions() {
|
|||||||
const userCollectionMovedSub = setupUserCollectionMovedSubscription()
|
const userCollectionMovedSub = setupUserCollectionMovedSubscription()
|
||||||
const userCollectionOrderUpdatedSub =
|
const userCollectionOrderUpdatedSub =
|
||||||
setupUserCollectionOrderUpdatedSubscription()
|
setupUserCollectionOrderUpdatedSubscription()
|
||||||
|
const userCollectionDuplicatedSub =
|
||||||
|
setupUserCollectionDuplicatedSubscription()
|
||||||
|
|
||||||
const userRequestCreatedSub = setupUserRequestCreatedSubscription()
|
const userRequestCreatedSub = setupUserRequestCreatedSubscription()
|
||||||
const userRequestUpdatedSub = setupUserRequestUpdatedSubscription()
|
const userRequestUpdatedSub = setupUserRequestUpdatedSubscription()
|
||||||
const userRequestDeletedSub = setupUserRequestDeletedSubscription()
|
const userRequestDeletedSub = setupUserRequestDeletedSubscription()
|
||||||
@@ -232,6 +288,7 @@ function setupSubscriptions() {
|
|||||||
userCollectionRemovedSub,
|
userCollectionRemovedSub,
|
||||||
userCollectionMovedSub,
|
userCollectionMovedSub,
|
||||||
userCollectionOrderUpdatedSub,
|
userCollectionOrderUpdatedSub,
|
||||||
|
userCollectionDuplicatedSub,
|
||||||
userRequestCreatedSub,
|
userRequestCreatedSub,
|
||||||
userRequestUpdatedSub,
|
userRequestUpdatedSub,
|
||||||
userRequestDeletedSub,
|
userRequestDeletedSub,
|
||||||
@@ -302,19 +359,32 @@ function setupUserCollectionCreatedSubscription() {
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// root collections won't have parentCollectionID
|
// root collections won't have parentCollectionID
|
||||||
|
const data =
|
||||||
|
res.right.userCollectionCreated.data &&
|
||||||
|
res.right.userCollectionCreated.data != "null"
|
||||||
|
? JSON.parse(res.right.userCollectionCreated.data)
|
||||||
|
: {
|
||||||
|
auth: { authType: "inherit", authActive: false },
|
||||||
|
headers: [],
|
||||||
|
}
|
||||||
|
|
||||||
runDispatchWithOutSyncing(() => {
|
runDispatchWithOutSyncing(() => {
|
||||||
collectionType == "GQL"
|
collectionType == "GQL"
|
||||||
? addGraphqlCollection({
|
? addGraphqlCollection({
|
||||||
name: res.right.userCollectionCreated.title,
|
name: res.right.userCollectionCreated.title,
|
||||||
folders: [],
|
folders: [],
|
||||||
requests: [],
|
requests: [],
|
||||||
v: 1,
|
v: 4,
|
||||||
|
auth: data.auth,
|
||||||
|
headers: addDescriptionField(data.headers),
|
||||||
})
|
})
|
||||||
: addRESTCollection({
|
: addRESTCollection({
|
||||||
name: res.right.userCollectionCreated.title,
|
name: res.right.userCollectionCreated.title,
|
||||||
folders: [],
|
folders: [],
|
||||||
requests: [],
|
requests: [],
|
||||||
v: 1,
|
v: 4,
|
||||||
|
auth: data.auth,
|
||||||
|
headers: addDescriptionField(data.headers),
|
||||||
})
|
})
|
||||||
|
|
||||||
const localIndex = collectionStore.value.state.length - 1
|
const localIndex = collectionStore.value.state.length - 1
|
||||||
@@ -491,6 +561,147 @@ function setupUserCollectionOrderUpdatedSubscription() {
|
|||||||
return userCollectionOrderUpdatedSub
|
return userCollectionOrderUpdatedSub
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setupUserCollectionDuplicatedSubscription() {
|
||||||
|
const [userCollectionDuplicated$, userCollectionDuplicatedSub] =
|
||||||
|
runUserCollectionDuplicatedSubscription()
|
||||||
|
|
||||||
|
userCollectionDuplicated$.subscribe((res) => {
|
||||||
|
if (E.isRight(res)) {
|
||||||
|
const {
|
||||||
|
childCollections: childCollectionsJSONStr,
|
||||||
|
data,
|
||||||
|
id,
|
||||||
|
parentID: parentCollectionID,
|
||||||
|
requests: userRequests,
|
||||||
|
title: name,
|
||||||
|
type: collectionType,
|
||||||
|
} = res.right.userCollectionDuplicated
|
||||||
|
|
||||||
|
const { collectionStore } = getStoreByCollectionType(collectionType)
|
||||||
|
|
||||||
|
const parentCollectionPath =
|
||||||
|
parentCollectionID &&
|
||||||
|
getCollectionPathFromCollectionID(
|
||||||
|
parentCollectionID,
|
||||||
|
collectionStore.value.state
|
||||||
|
)
|
||||||
|
|
||||||
|
// Incoming data transformed to the respective internal representations
|
||||||
|
const { auth, headers } =
|
||||||
|
data && data != "null"
|
||||||
|
? JSON.parse(data)
|
||||||
|
: {
|
||||||
|
auth: { authType: "inherit", authActive: false },
|
||||||
|
headers: [],
|
||||||
|
}
|
||||||
|
|
||||||
|
const folders = transformDuplicatedCollections(childCollectionsJSONStr)
|
||||||
|
|
||||||
|
const requests = transformDuplicatedCollectionRequests(
|
||||||
|
userRequests as UserRequest[]
|
||||||
|
)
|
||||||
|
|
||||||
|
// New collection to be added to store with the transformed data
|
||||||
|
const effectiveDuplicatedCollection: HoppCollection = {
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
folders,
|
||||||
|
requests,
|
||||||
|
v: 4,
|
||||||
|
auth,
|
||||||
|
headers: addDescriptionField(headers),
|
||||||
|
}
|
||||||
|
|
||||||
|
// only folders will have parent collection id
|
||||||
|
if (parentCollectionID && parentCollectionPath) {
|
||||||
|
const collectionCreatedFromStoreIDSuffix = "-duplicate-collection"
|
||||||
|
|
||||||
|
const parentCollection = navigateToFolderWithIndexPath(
|
||||||
|
collectionStore.value.state,
|
||||||
|
parentCollectionPath
|
||||||
|
.split("/")
|
||||||
|
.map((pathIndex) => parseInt(pathIndex))
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!parentCollection) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab the child collection inserted via store update with the ID suffix
|
||||||
|
const collectionInsertedViaStoreUpdateIdx =
|
||||||
|
parentCollection.folders.findIndex(({ id }) =>
|
||||||
|
id?.endsWith(collectionCreatedFromStoreIDSuffix)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (collectionInsertedViaStoreUpdateIdx === -1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const collectionInsertedViaStoreUpdateIndexPath = `${parentCollectionPath}/${collectionInsertedViaStoreUpdateIdx}`
|
||||||
|
|
||||||
|
runDispatchWithOutSyncing(() => {
|
||||||
|
/**
|
||||||
|
* Step 1. Remove the collection inserted via store update with the ID suffix
|
||||||
|
* Step 2. Add the duplicated collection received from the GQL subscription
|
||||||
|
* Step 3. Update the duplicated collection with the relevant data
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (collectionType === "GQL") {
|
||||||
|
removeGraphqlFolder(collectionInsertedViaStoreUpdateIndexPath)
|
||||||
|
|
||||||
|
addGraphqlFolder(name, parentCollectionPath)
|
||||||
|
|
||||||
|
editGraphqlFolder(
|
||||||
|
collectionInsertedViaStoreUpdateIndexPath,
|
||||||
|
effectiveDuplicatedCollection
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
removeRESTFolder(collectionInsertedViaStoreUpdateIndexPath)
|
||||||
|
|
||||||
|
addRESTFolder(name, parentCollectionPath)
|
||||||
|
|
||||||
|
editRESTFolder(
|
||||||
|
collectionInsertedViaStoreUpdateIndexPath,
|
||||||
|
effectiveDuplicatedCollection
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// root collections won't have `parentCollectionID`
|
||||||
|
const collectionCreatedFromStoreIDSuffix = "-duplicate-collection"
|
||||||
|
|
||||||
|
// Grab the child collection inserted via store update with the ID suffix
|
||||||
|
const collectionInsertedViaStoreUpdateIdx =
|
||||||
|
collectionStore.value.state.findIndex(({ id }) =>
|
||||||
|
id?.endsWith(collectionCreatedFromStoreIDSuffix)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (collectionInsertedViaStoreUpdateIdx === -1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
runDispatchWithOutSyncing(() => {
|
||||||
|
/**
|
||||||
|
* Step 1. Remove the collection inserted via store update with the ID suffix
|
||||||
|
* Step 2. Add the duplicated collection received from the GQL subscription
|
||||||
|
*/
|
||||||
|
if (collectionType === "GQL") {
|
||||||
|
removeGraphqlCollection(collectionInsertedViaStoreUpdateIdx)
|
||||||
|
|
||||||
|
addGraphqlCollection(effectiveDuplicatedCollection)
|
||||||
|
} else {
|
||||||
|
removeRESTCollection(collectionInsertedViaStoreUpdateIdx)
|
||||||
|
|
||||||
|
addRESTCollection(effectiveDuplicatedCollection)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return userCollectionDuplicatedSub
|
||||||
|
}
|
||||||
|
|
||||||
function setupUserRequestCreatedSubscription() {
|
function setupUserRequestCreatedSubscription() {
|
||||||
const [userRequestCreated$, userRequestCreatedSub] =
|
const [userRequestCreated$, userRequestCreatedSub] =
|
||||||
runUserRequestCreatedSubscription()
|
runUserRequestCreatedSubscription()
|
||||||
@@ -797,3 +1008,52 @@ function getRequestIndex(
|
|||||||
|
|
||||||
return requestIndex
|
return requestIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function transformDuplicatedCollections(
|
||||||
|
collectionsJSONStr: string
|
||||||
|
): HoppCollection[] {
|
||||||
|
const parsedCollections: UserCollectionDuplicatedData[] =
|
||||||
|
JSON.parse(collectionsJSONStr)
|
||||||
|
|
||||||
|
return parsedCollections.map(
|
||||||
|
({
|
||||||
|
childCollections: childCollectionsJSONStr,
|
||||||
|
data,
|
||||||
|
id,
|
||||||
|
requests: userRequests,
|
||||||
|
title: name,
|
||||||
|
}) => {
|
||||||
|
const { auth, headers } =
|
||||||
|
data && data !== "null"
|
||||||
|
? JSON.parse(data)
|
||||||
|
: { auth: { authType: "inherit", authActive: false }, headers: [] }
|
||||||
|
|
||||||
|
const folders = transformDuplicatedCollections(childCollectionsJSONStr)
|
||||||
|
|
||||||
|
const requests = transformDuplicatedCollectionRequests(userRequests)
|
||||||
|
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
folders,
|
||||||
|
requests,
|
||||||
|
v: 4,
|
||||||
|
auth,
|
||||||
|
headers: addDescriptionField(headers),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function transformDuplicatedCollectionRequests(
|
||||||
|
requests: UserRequest[]
|
||||||
|
): HoppRESTRequest[] | HoppGQLRequest[] {
|
||||||
|
return requests.map(({ id, request }) => {
|
||||||
|
const parsedRequest = JSON.parse(request)
|
||||||
|
|
||||||
|
return {
|
||||||
|
...parsedRequest,
|
||||||
|
id,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
subscription UserCollectionDuplicated {
|
||||||
|
userCollectionDuplicated {
|
||||||
|
id
|
||||||
|
parentID
|
||||||
|
title
|
||||||
|
type
|
||||||
|
data
|
||||||
|
childCollections
|
||||||
|
requests {
|
||||||
|
id
|
||||||
|
request
|
||||||
|
collectionID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,7 +40,6 @@ createHoppApp("#app", {
|
|||||||
platformFeatureFlags: {
|
platformFeatureFlags: {
|
||||||
exportAsGIST: false,
|
exportAsGIST: false,
|
||||||
hasTelemetry: false,
|
hasTelemetry: false,
|
||||||
duplicateCollectionDisabledInPersonalWorkspace: true,
|
|
||||||
},
|
},
|
||||||
infra: InfraPlatform,
|
infra: InfraPlatform,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import {
|
|||||||
UserCollectionRemovedDocument,
|
UserCollectionRemovedDocument,
|
||||||
UserCollectionMovedDocument,
|
UserCollectionMovedDocument,
|
||||||
UserCollectionOrderUpdatedDocument,
|
UserCollectionOrderUpdatedDocument,
|
||||||
|
UserCollectionDuplicatedDocument,
|
||||||
ExportUserCollectionsToJsonQuery,
|
ExportUserCollectionsToJsonQuery,
|
||||||
ExportUserCollectionsToJsonQueryVariables,
|
ExportUserCollectionsToJsonQueryVariables,
|
||||||
ExportUserCollectionsToJsonDocument,
|
ExportUserCollectionsToJsonDocument,
|
||||||
@@ -328,6 +329,12 @@ export const runUserCollectionOrderUpdatedSubscription = () =>
|
|||||||
variables: {},
|
variables: {},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const runUserCollectionDuplicatedSubscription = () =>
|
||||||
|
runGQLSubscription({
|
||||||
|
query: UserCollectionDuplicatedDocument,
|
||||||
|
variables: {},
|
||||||
|
})
|
||||||
|
|
||||||
export const runUserRequestCreatedSubscription = () =>
|
export const runUserRequestCreatedSubscription = () =>
|
||||||
runGQLSubscription({ query: UserRequestCreatedDocument, variables: {} })
|
runGQLSubscription({ query: UserRequestCreatedDocument, variables: {} })
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { authEvents$, def as platformAuth } from "@platform/auth/auth.platform"
|
|
||||||
import { CollectionsPlatformDef } from "@hoppscotch/common/platform/collections"
|
import { CollectionsPlatformDef } from "@hoppscotch/common/platform/collections"
|
||||||
|
import { authEvents$, def as platformAuth } from "@platform/auth/auth.platform"
|
||||||
import { runDispatchWithOutSyncing } from "../../lib/sync"
|
import { runDispatchWithOutSyncing } from "../../lib/sync"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
exportUserCollectionsToJSON,
|
exportUserCollectionsToJSON,
|
||||||
runUserCollectionCreatedSubscription,
|
runUserCollectionCreatedSubscription,
|
||||||
|
runUserCollectionDuplicatedSubscription,
|
||||||
runUserCollectionMovedSubscription,
|
runUserCollectionMovedSubscription,
|
||||||
runUserCollectionOrderUpdatedSubscription,
|
runUserCollectionOrderUpdatedSubscription,
|
||||||
runUserCollectionRemovedSubscription,
|
runUserCollectionRemovedSubscription,
|
||||||
@@ -16,37 +17,36 @@ import {
|
|||||||
} from "./collections.api"
|
} from "./collections.api"
|
||||||
import { collectionsSyncer, getStoreByCollectionType } from "./collections.sync"
|
import { collectionsSyncer, getStoreByCollectionType } from "./collections.sync"
|
||||||
|
|
||||||
import * as E from "fp-ts/Either"
|
|
||||||
import {
|
|
||||||
addRESTCollection,
|
|
||||||
setRESTCollections,
|
|
||||||
editRESTCollection,
|
|
||||||
removeRESTCollection,
|
|
||||||
moveRESTFolder,
|
|
||||||
updateRESTCollectionOrder,
|
|
||||||
saveRESTRequestAs,
|
|
||||||
navigateToFolderWithIndexPath,
|
|
||||||
editRESTRequest,
|
|
||||||
removeRESTRequest,
|
|
||||||
moveRESTRequest,
|
|
||||||
updateRESTRequestOrder,
|
|
||||||
addRESTFolder,
|
|
||||||
editRESTFolder,
|
|
||||||
removeRESTFolder,
|
|
||||||
addGraphqlFolder,
|
|
||||||
addGraphqlCollection,
|
|
||||||
editGraphqlFolder,
|
|
||||||
editGraphqlCollection,
|
|
||||||
removeGraphqlFolder,
|
|
||||||
removeGraphqlCollection,
|
|
||||||
saveGraphqlRequestAs,
|
|
||||||
editGraphqlRequest,
|
|
||||||
moveGraphqlRequest,
|
|
||||||
removeGraphqlRequest,
|
|
||||||
setGraphqlCollections,
|
|
||||||
restCollectionStore,
|
|
||||||
} from "@hoppscotch/common/newstore/collections"
|
|
||||||
import { runGQLSubscription } from "@hoppscotch/common/helpers/backend/GQLClient"
|
import { runGQLSubscription } from "@hoppscotch/common/helpers/backend/GQLClient"
|
||||||
|
import {
|
||||||
|
addGraphqlCollection,
|
||||||
|
addGraphqlFolder,
|
||||||
|
addRESTCollection,
|
||||||
|
addRESTFolder,
|
||||||
|
editGraphqlCollection,
|
||||||
|
editGraphqlFolder,
|
||||||
|
editGraphqlRequest,
|
||||||
|
editRESTCollection,
|
||||||
|
editRESTFolder,
|
||||||
|
editRESTRequest,
|
||||||
|
moveGraphqlRequest,
|
||||||
|
moveRESTFolder,
|
||||||
|
moveRESTRequest,
|
||||||
|
navigateToFolderWithIndexPath,
|
||||||
|
removeGraphqlCollection,
|
||||||
|
removeGraphqlFolder,
|
||||||
|
removeGraphqlRequest,
|
||||||
|
removeRESTCollection,
|
||||||
|
removeRESTFolder,
|
||||||
|
removeRESTRequest,
|
||||||
|
restCollectionStore,
|
||||||
|
saveGraphqlRequestAs,
|
||||||
|
saveRESTRequestAs,
|
||||||
|
setGraphqlCollections,
|
||||||
|
setRESTCollections,
|
||||||
|
updateRESTCollectionOrder,
|
||||||
|
updateRESTRequestOrder,
|
||||||
|
} from "@hoppscotch/common/newstore/collections"
|
||||||
import {
|
import {
|
||||||
GQLHeader,
|
GQLHeader,
|
||||||
HoppCollection,
|
HoppCollection,
|
||||||
@@ -55,8 +55,13 @@ import {
|
|||||||
HoppRESTParam,
|
HoppRESTParam,
|
||||||
HoppRESTRequest,
|
HoppRESTRequest,
|
||||||
} from "@hoppscotch/data"
|
} from "@hoppscotch/data"
|
||||||
|
import * as E from "fp-ts/Either"
|
||||||
|
import {
|
||||||
|
ReqType,
|
||||||
|
UserCollectionDuplicatedData,
|
||||||
|
UserRequest,
|
||||||
|
} from "../../api/generated/graphql"
|
||||||
import { gqlCollectionsSyncer } from "./gqlCollections.sync"
|
import { gqlCollectionsSyncer } from "./gqlCollections.sync"
|
||||||
import { ReqType } from "../../api/generated/graphql"
|
|
||||||
|
|
||||||
function initCollectionsSync() {
|
function initCollectionsSync() {
|
||||||
const currentUser$ = platformAuth.getCurrentUserStream()
|
const currentUser$ = platformAuth.getCurrentUserStream()
|
||||||
@@ -269,6 +274,9 @@ function setupSubscriptions() {
|
|||||||
const userCollectionMovedSub = setupUserCollectionMovedSubscription()
|
const userCollectionMovedSub = setupUserCollectionMovedSubscription()
|
||||||
const userCollectionOrderUpdatedSub =
|
const userCollectionOrderUpdatedSub =
|
||||||
setupUserCollectionOrderUpdatedSubscription()
|
setupUserCollectionOrderUpdatedSubscription()
|
||||||
|
const userCollectionDuplicatedSub =
|
||||||
|
setupUserCollectionDuplicatedSubscription()
|
||||||
|
|
||||||
const userRequestCreatedSub = setupUserRequestCreatedSubscription()
|
const userRequestCreatedSub = setupUserRequestCreatedSubscription()
|
||||||
const userRequestUpdatedSub = setupUserRequestUpdatedSubscription()
|
const userRequestUpdatedSub = setupUserRequestUpdatedSubscription()
|
||||||
const userRequestDeletedSub = setupUserRequestDeletedSubscription()
|
const userRequestDeletedSub = setupUserRequestDeletedSubscription()
|
||||||
@@ -280,6 +288,7 @@ function setupSubscriptions() {
|
|||||||
userCollectionRemovedSub,
|
userCollectionRemovedSub,
|
||||||
userCollectionMovedSub,
|
userCollectionMovedSub,
|
||||||
userCollectionOrderUpdatedSub,
|
userCollectionOrderUpdatedSub,
|
||||||
|
userCollectionDuplicatedSub,
|
||||||
userRequestCreatedSub,
|
userRequestCreatedSub,
|
||||||
userRequestUpdatedSub,
|
userRequestUpdatedSub,
|
||||||
userRequestDeletedSub,
|
userRequestDeletedSub,
|
||||||
@@ -314,20 +323,6 @@ function setupUserCollectionCreatedSubscription() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// While duplicating a collection, the new entry added to the store has an ID with a suffix to be updated after the backend ID is received from the GQL subscription
|
|
||||||
// This is to prevent the new entry from being added to the store again when the GQL subscription
|
|
||||||
// The boolean return value indicates if the GQL subscription was fired because of a duplicate collection action and whether the collection should be added to the store
|
|
||||||
const shouldCreateCollection = issueBackendIDToDuplicatedCollection(
|
|
||||||
collectionStore,
|
|
||||||
collectionType,
|
|
||||||
userCollectionBackendID,
|
|
||||||
parentCollectionID
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!shouldCreateCollection) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const parentCollectionPath =
|
const parentCollectionPath =
|
||||||
parentCollectionID &&
|
parentCollectionID &&
|
||||||
getCollectionPathFromCollectionID(
|
getCollectionPathFromCollectionID(
|
||||||
@@ -566,6 +561,147 @@ function setupUserCollectionOrderUpdatedSubscription() {
|
|||||||
return userCollectionOrderUpdatedSub
|
return userCollectionOrderUpdatedSub
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setupUserCollectionDuplicatedSubscription() {
|
||||||
|
const [userCollectionDuplicated$, userCollectionDuplicatedSub] =
|
||||||
|
runUserCollectionDuplicatedSubscription()
|
||||||
|
|
||||||
|
userCollectionDuplicated$.subscribe((res) => {
|
||||||
|
if (E.isRight(res)) {
|
||||||
|
const {
|
||||||
|
childCollections: childCollectionsJSONStr,
|
||||||
|
data,
|
||||||
|
id,
|
||||||
|
parentID: parentCollectionID,
|
||||||
|
requests: userRequests,
|
||||||
|
title: name,
|
||||||
|
type: collectionType,
|
||||||
|
} = res.right.userCollectionDuplicated
|
||||||
|
|
||||||
|
const { collectionStore } = getStoreByCollectionType(collectionType)
|
||||||
|
|
||||||
|
const parentCollectionPath =
|
||||||
|
parentCollectionID &&
|
||||||
|
getCollectionPathFromCollectionID(
|
||||||
|
parentCollectionID,
|
||||||
|
collectionStore.value.state
|
||||||
|
)
|
||||||
|
|
||||||
|
// Incoming data transformed to the respective internal representations
|
||||||
|
const { auth, headers } =
|
||||||
|
data && data != "null"
|
||||||
|
? JSON.parse(data)
|
||||||
|
: {
|
||||||
|
auth: { authType: "inherit", authActive: false },
|
||||||
|
headers: [],
|
||||||
|
}
|
||||||
|
|
||||||
|
const folders = transformDuplicatedCollections(childCollectionsJSONStr)
|
||||||
|
|
||||||
|
const requests = transformDuplicatedCollectionRequests(
|
||||||
|
userRequests as UserRequest[]
|
||||||
|
)
|
||||||
|
|
||||||
|
// New collection to be added to store with the transformed data
|
||||||
|
const effectiveDuplicatedCollection: HoppCollection = {
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
folders,
|
||||||
|
requests,
|
||||||
|
v: 3,
|
||||||
|
auth,
|
||||||
|
headers: addDescriptionField(headers),
|
||||||
|
}
|
||||||
|
|
||||||
|
// only folders will have parent collection id
|
||||||
|
if (parentCollectionID && parentCollectionPath) {
|
||||||
|
const collectionCreatedFromStoreIDSuffix = "-duplicate-collection"
|
||||||
|
|
||||||
|
const parentCollection = navigateToFolderWithIndexPath(
|
||||||
|
collectionStore.value.state,
|
||||||
|
parentCollectionPath
|
||||||
|
.split("/")
|
||||||
|
.map((pathIndex) => parseInt(pathIndex))
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!parentCollection) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab the child collection inserted via store update with the ID suffix
|
||||||
|
const collectionInsertedViaStoreUpdateIdx =
|
||||||
|
parentCollection.folders.findIndex(({ id }) =>
|
||||||
|
id?.endsWith(collectionCreatedFromStoreIDSuffix)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (collectionInsertedViaStoreUpdateIdx === -1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const collectionInsertedViaStoreUpdateIndexPath = `${parentCollectionPath}/${collectionInsertedViaStoreUpdateIdx}`
|
||||||
|
|
||||||
|
runDispatchWithOutSyncing(() => {
|
||||||
|
/**
|
||||||
|
* Step 1. Remove the collection inserted via store update with the ID suffix
|
||||||
|
* Step 2. Add the duplicated collection received from the GQL subscription
|
||||||
|
* Step 3. Update the duplicated collection with the relevant data
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (collectionType === "GQL") {
|
||||||
|
removeGraphqlFolder(collectionInsertedViaStoreUpdateIndexPath)
|
||||||
|
|
||||||
|
addGraphqlFolder(name, parentCollectionPath)
|
||||||
|
|
||||||
|
editGraphqlFolder(
|
||||||
|
collectionInsertedViaStoreUpdateIndexPath,
|
||||||
|
effectiveDuplicatedCollection
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
removeRESTFolder(collectionInsertedViaStoreUpdateIndexPath)
|
||||||
|
|
||||||
|
addRESTFolder(name, parentCollectionPath)
|
||||||
|
|
||||||
|
editRESTFolder(
|
||||||
|
collectionInsertedViaStoreUpdateIndexPath,
|
||||||
|
effectiveDuplicatedCollection
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// root collections won't have `parentCollectionID`
|
||||||
|
const collectionCreatedFromStoreIDSuffix = "-duplicate-collection"
|
||||||
|
|
||||||
|
// Grab the child collection inserted via store update with the ID suffix
|
||||||
|
const collectionInsertedViaStoreUpdateIdx =
|
||||||
|
collectionStore.value.state.findIndex(({ id }) =>
|
||||||
|
id?.endsWith(collectionCreatedFromStoreIDSuffix)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (collectionInsertedViaStoreUpdateIdx === -1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
runDispatchWithOutSyncing(() => {
|
||||||
|
/**
|
||||||
|
* Step 1. Remove the collection inserted via store update with the ID suffix
|
||||||
|
* Step 2. Add the duplicated collection received from the GQL subscription
|
||||||
|
*/
|
||||||
|
if (collectionType === "GQL") {
|
||||||
|
removeGraphqlCollection(collectionInsertedViaStoreUpdateIdx)
|
||||||
|
|
||||||
|
addGraphqlCollection(effectiveDuplicatedCollection)
|
||||||
|
} else {
|
||||||
|
removeRESTCollection(collectionInsertedViaStoreUpdateIdx)
|
||||||
|
|
||||||
|
addRESTCollection(effectiveDuplicatedCollection)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return userCollectionDuplicatedSub
|
||||||
|
}
|
||||||
|
|
||||||
function setupUserRequestCreatedSubscription() {
|
function setupUserRequestCreatedSubscription() {
|
||||||
const [userRequestCreated$, userRequestCreatedSub] =
|
const [userRequestCreated$, userRequestCreatedSub] =
|
||||||
runUserRequestCreatedSubscription()
|
runUserRequestCreatedSubscription()
|
||||||
@@ -873,104 +1009,51 @@ function getRequestIndex(
|
|||||||
return requestIndex
|
return requestIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
function issueBackendIDToDuplicatedCollection(
|
function transformDuplicatedCollections(
|
||||||
collectionStore: ReturnType<
|
collectionsJSONStr: string
|
||||||
typeof getStoreByCollectionType
|
): HoppCollection[] {
|
||||||
>["collectionStore"],
|
const parsedCollections: UserCollectionDuplicatedData[] =
|
||||||
collectionType: ReqType,
|
JSON.parse(collectionsJSONStr)
|
||||||
userCollectionBackendID: string,
|
|
||||||
parentCollectionID?: string
|
|
||||||
): boolean {
|
|
||||||
// Collection added to store via duplicating is set an ID with a suffix to be updated after the backend ID is received from the GQL subscription
|
|
||||||
const collectionCreatedFromStoreIDSuffix = "-duplicate-collection"
|
|
||||||
|
|
||||||
// Duplicating a child collection
|
return parsedCollections.map(
|
||||||
if (parentCollectionID) {
|
({
|
||||||
// Get the index path for the parent collection
|
childCollections: childCollectionsJSONStr,
|
||||||
const parentCollectionPath = getCollectionPathFromCollectionID(
|
data,
|
||||||
parentCollectionID,
|
id,
|
||||||
collectionStore.value.state
|
requests: userRequests,
|
||||||
|
title: name,
|
||||||
|
}) => {
|
||||||
|
const { auth, headers } =
|
||||||
|
data && data !== "null"
|
||||||
|
? JSON.parse(data)
|
||||||
|
: { auth: { authType: "inherit", authActive: false }, headers: [] }
|
||||||
|
|
||||||
|
const folders = transformDuplicatedCollections(childCollectionsJSONStr)
|
||||||
|
|
||||||
|
const requests = transformDuplicatedCollectionRequests(userRequests)
|
||||||
|
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
folders,
|
||||||
|
requests,
|
||||||
|
v: 3,
|
||||||
|
auth,
|
||||||
|
headers: addDescriptionField(headers),
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!parentCollectionPath) {
|
|
||||||
// Indicates the collection received from the GQL subscription should be created in the store
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const parentCollection = navigateToFolderWithIndexPath(
|
function transformDuplicatedCollectionRequests(
|
||||||
collectionStore.value.state,
|
requests: UserRequest[]
|
||||||
parentCollectionPath.split("/").map((index) => parseInt(index))
|
): HoppRESTRequest[] | HoppGQLRequest[] {
|
||||||
)
|
return requests.map(({ id, request }) => {
|
||||||
|
const parsedRequest = JSON.parse(request)
|
||||||
|
|
||||||
if (!parentCollection) {
|
return {
|
||||||
// Indicates the collection received from the GQL subscription should be created in the store
|
...parsedRequest,
|
||||||
return true
|
id,
|
||||||
}
|
|
||||||
|
|
||||||
// Grab the child collection inserted via store update with the ID suffix
|
|
||||||
const collectionInsertedViaStoreUpdateIdx =
|
|
||||||
parentCollection.folders.findIndex(({ id }) =>
|
|
||||||
id?.endsWith(collectionCreatedFromStoreIDSuffix)
|
|
||||||
)
|
|
||||||
|
|
||||||
// No entry indicates the GQL subscription was fired not because of a duplicate collection action
|
|
||||||
if (collectionInsertedViaStoreUpdateIdx === -1) {
|
|
||||||
// Indicates the collection received from the GQL subscription should be created in the store
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
const collectionInsertedViaStoreUpdate =
|
|
||||||
parentCollection.folders[collectionInsertedViaStoreUpdateIdx]
|
|
||||||
|
|
||||||
const childCollectionPath = `${parentCollectionPath}/${collectionInsertedViaStoreUpdateIdx}`
|
|
||||||
|
|
||||||
// Update the ID for the child collection already existing in store with the backend ID
|
|
||||||
runDispatchWithOutSyncing(() => {
|
|
||||||
if (collectionType == ReqType.Rest) {
|
|
||||||
editRESTFolder(childCollectionPath, {
|
|
||||||
...collectionInsertedViaStoreUpdate,
|
|
||||||
id: userCollectionBackendID,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
editGraphqlFolder(childCollectionPath, {
|
|
||||||
...collectionInsertedViaStoreUpdate,
|
|
||||||
id: userCollectionBackendID,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// Duplicating a root collection
|
|
||||||
|
|
||||||
// Grab the collection inserted via store update with the ID suffix
|
|
||||||
const collectionInsertedViaStoreUpdateIdx =
|
|
||||||
collectionStore.value.state.findIndex(({ id }) =>
|
|
||||||
id?.endsWith(collectionCreatedFromStoreIDSuffix)
|
|
||||||
)
|
|
||||||
|
|
||||||
// No entry indicates the GQL subscription was fired not because of a duplicate collection action
|
|
||||||
if (collectionInsertedViaStoreUpdateIdx === -1) {
|
|
||||||
// Indicates the collection received from the GQL subscription should be created in the store
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
const collectionInsertedViaStoreUpdate =
|
|
||||||
collectionStore.value.state[collectionInsertedViaStoreUpdateIdx]
|
|
||||||
|
|
||||||
// Update the ID for the collection already existing in store with the backend ID
|
|
||||||
runDispatchWithOutSyncing(() => {
|
|
||||||
if (collectionType == ReqType.Rest) {
|
|
||||||
editRESTCollection(collectionInsertedViaStoreUpdateIdx, {
|
|
||||||
...collectionInsertedViaStoreUpdate,
|
|
||||||
id: userCollectionBackendID,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
editGraphqlCollection(collectionInsertedViaStoreUpdateIdx, {
|
|
||||||
...collectionInsertedViaStoreUpdate,
|
|
||||||
id: userCollectionBackendID,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent adding the collection received from GQL subscription to the store
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user