|
|
|
|
@@ -1,10 +1,11 @@
|
|
|
|
|
import { authEvents$, def as platformAuth } from "@platform/auth/auth.platform"
|
|
|
|
|
import { CollectionsPlatformDef } from "@hoppscotch/common/platform/collections"
|
|
|
|
|
import { authEvents$, def as platformAuth } from "@platform/auth/auth.platform"
|
|
|
|
|
import { runDispatchWithOutSyncing } from "../../lib/sync"
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
exportUserCollectionsToJSON,
|
|
|
|
|
runUserCollectionCreatedSubscription,
|
|
|
|
|
runUserCollectionDuplicatedSubscription,
|
|
|
|
|
runUserCollectionMovedSubscription,
|
|
|
|
|
runUserCollectionOrderUpdatedSubscription,
|
|
|
|
|
runUserCollectionRemovedSubscription,
|
|
|
|
|
@@ -16,37 +17,36 @@ import {
|
|
|
|
|
} from "./collections.api"
|
|
|
|
|
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 {
|
|
|
|
|
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,
|
|
|
|
|
@@ -55,8 +55,13 @@ import {
|
|
|
|
|
HoppRESTParam,
|
|
|
|
|
HoppRESTRequest,
|
|
|
|
|
} from "@hoppscotch/data"
|
|
|
|
|
import * as E from "fp-ts/Either"
|
|
|
|
|
import {
|
|
|
|
|
ReqType,
|
|
|
|
|
UserCollectionDuplicatedData,
|
|
|
|
|
UserRequest,
|
|
|
|
|
} from "../../api/generated/graphql"
|
|
|
|
|
import { gqlCollectionsSyncer } from "./gqlCollections.sync"
|
|
|
|
|
import { ReqType } from "../../api/generated/graphql"
|
|
|
|
|
|
|
|
|
|
function initCollectionsSync() {
|
|
|
|
|
const currentUser$ = platformAuth.getCurrentUserStream()
|
|
|
|
|
@@ -269,6 +274,9 @@ function setupSubscriptions() {
|
|
|
|
|
const userCollectionMovedSub = setupUserCollectionMovedSubscription()
|
|
|
|
|
const userCollectionOrderUpdatedSub =
|
|
|
|
|
setupUserCollectionOrderUpdatedSubscription()
|
|
|
|
|
const userCollectionDuplicatedSub =
|
|
|
|
|
setupUserCollectionDuplicatedSubscription()
|
|
|
|
|
|
|
|
|
|
const userRequestCreatedSub = setupUserRequestCreatedSubscription()
|
|
|
|
|
const userRequestUpdatedSub = setupUserRequestUpdatedSubscription()
|
|
|
|
|
const userRequestDeletedSub = setupUserRequestDeletedSubscription()
|
|
|
|
|
@@ -280,6 +288,7 @@ function setupSubscriptions() {
|
|
|
|
|
userCollectionRemovedSub,
|
|
|
|
|
userCollectionMovedSub,
|
|
|
|
|
userCollectionOrderUpdatedSub,
|
|
|
|
|
userCollectionDuplicatedSub,
|
|
|
|
|
userRequestCreatedSub,
|
|
|
|
|
userRequestUpdatedSub,
|
|
|
|
|
userRequestDeletedSub,
|
|
|
|
|
@@ -314,20 +323,6 @@ function setupUserCollectionCreatedSubscription() {
|
|
|
|
|
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 =
|
|
|
|
|
parentCollectionID &&
|
|
|
|
|
getCollectionPathFromCollectionID(
|
|
|
|
|
@@ -566,6 +561,147 @@ function setupUserCollectionOrderUpdatedSubscription() {
|
|
|
|
|
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() {
|
|
|
|
|
const [userRequestCreated$, userRequestCreatedSub] =
|
|
|
|
|
runUserRequestCreatedSubscription()
|
|
|
|
|
@@ -873,104 +1009,51 @@ function getRequestIndex(
|
|
|
|
|
return requestIndex
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function issueBackendIDToDuplicatedCollection(
|
|
|
|
|
collectionStore: ReturnType<
|
|
|
|
|
typeof getStoreByCollectionType
|
|
|
|
|
>["collectionStore"],
|
|
|
|
|
collectionType: ReqType,
|
|
|
|
|
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"
|
|
|
|
|
function transformDuplicatedCollections(
|
|
|
|
|
collectionsJSONStr: string
|
|
|
|
|
): HoppCollection[] {
|
|
|
|
|
const parsedCollections: UserCollectionDuplicatedData[] =
|
|
|
|
|
JSON.parse(collectionsJSONStr)
|
|
|
|
|
|
|
|
|
|
// Duplicating a child collection
|
|
|
|
|
if (parentCollectionID) {
|
|
|
|
|
// Get the index path for the parent collection
|
|
|
|
|
const parentCollectionPath = getCollectionPathFromCollectionID(
|
|
|
|
|
parentCollectionID,
|
|
|
|
|
collectionStore.value.state
|
|
|
|
|
)
|
|
|
|
|
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: [] }
|
|
|
|
|
|
|
|
|
|
if (!parentCollectionPath) {
|
|
|
|
|
// Indicates the collection received from the GQL subscription should be created in the store
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
const folders = transformDuplicatedCollections(childCollectionsJSONStr)
|
|
|
|
|
|
|
|
|
|
const parentCollection = navigateToFolderWithIndexPath(
|
|
|
|
|
collectionStore.value.state,
|
|
|
|
|
parentCollectionPath.split("/").map((index) => parseInt(index))
|
|
|
|
|
)
|
|
|
|
|
const requests = transformDuplicatedCollectionRequests(userRequests)
|
|
|
|
|
|
|
|
|
|
if (!parentCollection) {
|
|
|
|
|
// Indicates the collection received from the GQL subscription should be created in the store
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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,
|
|
|
|
|
})
|
|
|
|
|
return {
|
|
|
|
|
id,
|
|
|
|
|
name,
|
|
|
|
|
folders,
|
|
|
|
|
requests,
|
|
|
|
|
v: 3,
|
|
|
|
|
auth,
|
|
|
|
|
headers: addDescriptionField(headers),
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
} 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
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function transformDuplicatedCollectionRequests(
|
|
|
|
|
requests: UserRequest[]
|
|
|
|
|
): HoppRESTRequest[] | HoppGQLRequest[] {
|
|
|
|
|
return requests.map(({ id, request }) => {
|
|
|
|
|
const parsedRequest = JSON.parse(request)
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
...parsedRequest,
|
|
|
|
|
id,
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|