refactor: refactor collection to not use mapper (#80)
This commit is contained in:
@@ -1,456 +0,0 @@
|
||||
import {
|
||||
graphqlCollectionStore,
|
||||
navigateToFolderWithIndexPath,
|
||||
restCollectionStore,
|
||||
} from "@hoppscotch/common/newstore/collections"
|
||||
import { createMapper } from "../../lib/sync/mapper"
|
||||
import {
|
||||
restCollectionsMapper,
|
||||
collectionReorderOrMovingOperations,
|
||||
restRequestsMapper,
|
||||
} from "./collections.sync"
|
||||
import { gqlCollectionsMapper, gqlRequestsMapper } from "./gqlCollections.sync"
|
||||
|
||||
function reorderItems(array: unknown[], from: number, to: number) {
|
||||
const item = array.splice(from, 1)[0]
|
||||
if (from < to) {
|
||||
array.splice(to - 1, 0, item)
|
||||
} else {
|
||||
array.splice(to, 0, item)
|
||||
}
|
||||
}
|
||||
|
||||
type RequestType = "REST" | "GQL"
|
||||
|
||||
export function moveCollectionInMapper(
|
||||
folderPath: string,
|
||||
destinationPath?: string,
|
||||
collectionType: RequestType = "REST"
|
||||
) {
|
||||
const indexes = folderPath.split("/")
|
||||
indexes.pop()
|
||||
const collectionPath = indexes.join("/")
|
||||
|
||||
const { collectionsMapper, requestsMapper, collectionStore } =
|
||||
getMappersAndStoreByType(collectionType)
|
||||
|
||||
// Store the backend id of the folder to move for adding it to the destinationPath
|
||||
const collectionToMoveBackendID =
|
||||
collectionsMapper.getBackendIDByLocalID(folderPath)
|
||||
|
||||
// Remove the request from its current position
|
||||
collectionsMapper.removeEntry(undefined, folderPath)
|
||||
|
||||
// We are assuming moveRequestInMapper is called after the item is moved in the store,
|
||||
// so we'll fetch the index of the last added item + 1 to add to the mapper
|
||||
// but in the case of the same parent, the destinationPath will change
|
||||
// eg:
|
||||
// 0. Collection 0
|
||||
// 1. Collection 1
|
||||
// in the above example, if we move Collection 0 to Collection 1 ( folderPath: 0, destinationPath: 1 ),
|
||||
// the effective index of Collection 1, when using navigateToFolderWithIndexPath will be 0
|
||||
// so we check if the moving is between same parent folders / collections and adds a workaround for this
|
||||
const isSameParentPath =
|
||||
getParentPathFromPath(folderPath) == getParentPathFromPath(destinationPath)
|
||||
|
||||
let changedDestinationPath: string | undefined
|
||||
|
||||
if (isSameParentPath) {
|
||||
const lastFolderPathIndex = folderPath.split("/").pop()
|
||||
const folderIndex = lastFolderPathIndex && parseInt(lastFolderPathIndex)
|
||||
|
||||
const lastDestinationPathIndex =
|
||||
destinationPath && destinationPath.split("/").pop()
|
||||
const destinationIndex =
|
||||
destinationPath &&
|
||||
lastDestinationPathIndex &&
|
||||
parseInt(lastDestinationPathIndex)
|
||||
|
||||
if (
|
||||
(folderIndex == 0 || folderIndex) &&
|
||||
(destinationIndex == 0 || destinationIndex) &&
|
||||
folderIndex < destinationIndex
|
||||
) {
|
||||
const destinationParentPath = getParentPathFromPath(destinationPath)
|
||||
changedDestinationPath = destinationParentPath
|
||||
? `${destinationParentPath}/${destinationIndex - 1}`
|
||||
: `${destinationIndex - 1}`
|
||||
}
|
||||
}
|
||||
|
||||
const destinationFolder =
|
||||
changedDestinationPath &&
|
||||
navigateToFolderWithIndexPath(
|
||||
collectionStore.value.state,
|
||||
changedDestinationPath.split("/").map((pathIndex) => parseInt(pathIndex))
|
||||
)
|
||||
|
||||
const destinationCollectionID =
|
||||
destinationPath && collectionsMapper.getBackendIDByLocalID(destinationPath)
|
||||
|
||||
if (destinationFolder && collectionToMoveBackendID) {
|
||||
const destinationIndex = destinationFolder.folders.length
|
||||
|
||||
const newPath = `${destinationPath}/${destinationIndex}`
|
||||
collectionsMapper.addEntry(newPath, collectionToMoveBackendID)
|
||||
|
||||
changeParentForAllChildrenFromMapper(folderPath, newPath, collectionType)
|
||||
|
||||
collectionToMoveBackendID &&
|
||||
collectionReorderOrMovingOperations.push({
|
||||
sourceCollectionID: collectionToMoveBackendID,
|
||||
destinationCollectionID,
|
||||
reorderOperation: {
|
||||
fromPath: folderPath,
|
||||
toPath: `${changedDestinationPath}/${destinationIndex}`,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// destinationPath won't be there, when moving to the root
|
||||
if (!destinationPath && collectionToMoveBackendID) {
|
||||
const destinationIndex = collectionStore.value.state.length
|
||||
const newPath = `${destinationIndex}`
|
||||
|
||||
collectionsMapper.addEntry(newPath, collectionToMoveBackendID)
|
||||
|
||||
changeParentForAllChildrenFromMapper(folderPath, newPath, collectionType)
|
||||
}
|
||||
|
||||
reorderIndexesAfterEntryRemoval(
|
||||
collectionPath,
|
||||
collectionsMapper,
|
||||
collectionType
|
||||
)
|
||||
reorderIndexesAfterEntryRemoval(
|
||||
collectionPath,
|
||||
requestsMapper,
|
||||
collectionType
|
||||
)
|
||||
}
|
||||
|
||||
export function moveRequestInMapper(
|
||||
requestIndex: number,
|
||||
path: string,
|
||||
destinationPath: string,
|
||||
requestType: RequestType
|
||||
) {
|
||||
const { collectionStore, requestsMapper } =
|
||||
getMappersAndStoreByType(requestType)
|
||||
|
||||
// Store the backend id of the request to move for adding it to the destinationPath
|
||||
const requestToMoveBackendID = requestsMapper.getBackendIDByLocalID(
|
||||
`${path}/${requestIndex}`
|
||||
)
|
||||
|
||||
// Remove the request from its current position
|
||||
requestsMapper.removeEntry(undefined, `${path}/${requestIndex}`)
|
||||
reorderIndexesAfterEntryRemoval(path, requestsMapper, requestType)
|
||||
|
||||
// We are assuming moveRequestInMapper is called after the item is moved in the store,
|
||||
// so we'll fetch the index of the last added item + 1 to add to the mapper
|
||||
const destinationFolder = navigateToFolderWithIndexPath(
|
||||
collectionStore.value.state,
|
||||
destinationPath.split("/").map((pathIndex) => parseInt(pathIndex))
|
||||
)
|
||||
|
||||
if (destinationFolder && requestToMoveBackendID) {
|
||||
const destinationIndex = destinationFolder.requests.length
|
||||
|
||||
requestsMapper.addEntry(
|
||||
`${destinationPath}/${destinationIndex}`,
|
||||
requestToMoveBackendID
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// we allow reordering in the same parent collection right now
|
||||
export function reorderRequestsMapper(
|
||||
requestIndex: number,
|
||||
path: string,
|
||||
nextRequestIndex: number,
|
||||
requestType: RequestType
|
||||
) {
|
||||
const { requestsMapper } = getMappersAndStoreByType(requestType)
|
||||
|
||||
const directChildren = getDirectChildrenEntriesFromMapper(
|
||||
path,
|
||||
requestsMapper
|
||||
)
|
||||
|
||||
reorderItems(directChildren, requestIndex, nextRequestIndex)
|
||||
|
||||
directChildren.forEach((item, index) => {
|
||||
item[1] && requestsMapper.addEntry(`${path}/${index}`, item[1])
|
||||
})
|
||||
}
|
||||
// we allow reordering in the same parent collection right now
|
||||
|
||||
export function reorderCollectionsInMapper(
|
||||
collectionPath: string,
|
||||
destinationCollectionPath: string,
|
||||
requestType: RequestType
|
||||
) {
|
||||
const { requestsMapper, collectionsMapper } =
|
||||
getMappersAndStoreByType(requestType)
|
||||
|
||||
const indexes = collectionPath.split("/")
|
||||
indexes.pop()
|
||||
const parentCollectionPath = indexes.join("/")
|
||||
|
||||
const directChildren = getDirectChildrenEntriesFromMapper(
|
||||
parentCollectionPath,
|
||||
collectionsMapper
|
||||
)
|
||||
|
||||
const collectionIndex = collectionPath.split("/").pop()
|
||||
const destinationIndex = destinationCollectionPath.split("/").pop()
|
||||
|
||||
collectionIndex &&
|
||||
destinationIndex &&
|
||||
reorderItems(
|
||||
directChildren,
|
||||
parentCollectionPath
|
||||
? parseInt(collectionIndex)
|
||||
: parseInt(collectionPath),
|
||||
parentCollectionPath
|
||||
? parseInt(destinationIndex)
|
||||
: parseInt(destinationCollectionPath)
|
||||
)
|
||||
|
||||
const previousCollectionEntries: Record<
|
||||
string,
|
||||
[string, string | undefined][]
|
||||
> = {}
|
||||
|
||||
const previousRequestEntries: Record<string, [string, string | undefined][]> =
|
||||
{}
|
||||
|
||||
directChildren.forEach(([path, backendID], index) => {
|
||||
const newPath = parentCollectionPath
|
||||
? `${parentCollectionPath}/${index}`
|
||||
: `${index}`
|
||||
|
||||
const indexes = path.split("/")
|
||||
const childIndex = indexes.pop()
|
||||
|
||||
if (childIndex && index != parseInt(childIndex)) {
|
||||
backendID && collectionsMapper.addEntry(newPath, backendID)
|
||||
|
||||
const existingCollectionsOnNewPath = getChildrenEntriesFromMapper(
|
||||
newPath,
|
||||
collectionsMapper
|
||||
)
|
||||
|
||||
const existingRequestsOnNewPath = getChildrenEntriesFromMapper(
|
||||
newPath,
|
||||
requestsMapper
|
||||
)
|
||||
|
||||
previousCollectionEntries[newPath] = existingCollectionsOnNewPath
|
||||
previousRequestEntries[newPath] = existingRequestsOnNewPath
|
||||
|
||||
removeAllChildCollectionsFromMapper(newPath, requestType)
|
||||
removeAllChildRequestsFromMapper(newPath, requestType)
|
||||
|
||||
if (path in previousCollectionEntries && path in previousRequestEntries) {
|
||||
previousCollectionEntries[path].forEach(([previousPath, backendID]) => {
|
||||
const pattern = new RegExp(`^(${path})\/`)
|
||||
|
||||
const updatedPath = previousPath.replace(pattern, `${newPath}/`)
|
||||
|
||||
backendID && collectionsMapper.addEntry(updatedPath, backendID)
|
||||
})
|
||||
|
||||
previousRequestEntries[path].forEach(([previousPath, backendID]) => {
|
||||
const pattern = new RegExp(`^(${path})\/`)
|
||||
|
||||
const updatedPath = previousPath.replace(pattern, `${newPath}/`)
|
||||
|
||||
backendID && requestsMapper.addEntry(updatedPath, backendID)
|
||||
})
|
||||
} else {
|
||||
changeParentForAllChildrenFromMapper(path, newPath, requestType)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function removeAndReorderEntries(
|
||||
localIndex: string,
|
||||
collectionType: RequestType
|
||||
) {
|
||||
const { collectionsMapper, requestsMapper } =
|
||||
getMappersAndStoreByType(collectionType)
|
||||
|
||||
// get the collectionPath from the localIndex
|
||||
const indexes = localIndex.split("/")
|
||||
indexes.pop()
|
||||
const collectionPath = indexes.join("/")
|
||||
|
||||
collectionsMapper.removeEntry(undefined, localIndex)
|
||||
|
||||
removeAllChildCollectionsFromMapper(localIndex, collectionType)
|
||||
removeAllChildRequestsFromMapper(localIndex, collectionType)
|
||||
|
||||
reorderIndexesAfterEntryRemoval(
|
||||
collectionPath,
|
||||
collectionsMapper,
|
||||
collectionType
|
||||
)
|
||||
reorderIndexesAfterEntryRemoval(
|
||||
collectionPath,
|
||||
requestsMapper,
|
||||
collectionType
|
||||
)
|
||||
}
|
||||
|
||||
export function removeAllChildRequestsFromMapper(
|
||||
collectionPath: string,
|
||||
requestType: RequestType
|
||||
) {
|
||||
const { requestsMapper } = getMappersAndStoreByType(requestType)
|
||||
|
||||
const childRequestMapperEntries = getChildrenEntriesFromMapper(
|
||||
collectionPath,
|
||||
requestsMapper
|
||||
)
|
||||
|
||||
childRequestMapperEntries.forEach(([path]) => {
|
||||
typeof path == "string" && requestsMapper.removeEntry(undefined, path)
|
||||
})
|
||||
}
|
||||
|
||||
export function removeAllChildCollectionsFromMapper(
|
||||
collectionPath: string,
|
||||
collectionType: RequestType
|
||||
) {
|
||||
const { collectionsMapper } = getMappersAndStoreByType(collectionType)
|
||||
|
||||
const childCollectionMapperEntries = getChildrenEntriesFromMapper(
|
||||
collectionPath,
|
||||
collectionsMapper
|
||||
)
|
||||
|
||||
childCollectionMapperEntries.forEach(([path]) => {
|
||||
typeof path == "string" && collectionsMapper.removeEntry(undefined, path)
|
||||
})
|
||||
}
|
||||
|
||||
export function changeParentForAllChildrenFromMapper(
|
||||
currentParentPath: string,
|
||||
newParentPath: string,
|
||||
collectionType: RequestType
|
||||
) {
|
||||
const { collectionsMapper, requestsMapper } =
|
||||
getMappersAndStoreByType(collectionType)
|
||||
|
||||
const childCollectionsMapperEntries = getChildrenEntriesFromMapper(
|
||||
currentParentPath,
|
||||
collectionsMapper
|
||||
)
|
||||
|
||||
const childRequestsMapperEntries = getChildrenEntriesFromMapper(
|
||||
currentParentPath,
|
||||
requestsMapper
|
||||
)
|
||||
|
||||
const pattern = new RegExp(`^(${currentParentPath})`)
|
||||
|
||||
childCollectionsMapperEntries.forEach(([path, backendID]) => {
|
||||
const newPath =
|
||||
typeof path == "string" && path.replace(pattern, newParentPath)
|
||||
|
||||
if (newPath && typeof backendID == "string") {
|
||||
collectionsMapper.removeEntry(undefined, path)
|
||||
collectionsMapper.addEntry(newPath, backendID)
|
||||
}
|
||||
})
|
||||
|
||||
childRequestsMapperEntries.forEach(([path, backendID]) => {
|
||||
const newPath =
|
||||
typeof path == "string" && path.replace(pattern, newParentPath)
|
||||
|
||||
if (newPath && typeof backendID == "string") {
|
||||
requestsMapper.removeEntry(undefined, path)
|
||||
requestsMapper.addEntry(newPath, backendID)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getChildrenEntriesFromMapper(
|
||||
path: string,
|
||||
mapper: ReturnType<typeof createMapper<string, string>>
|
||||
) {
|
||||
let mapperEntries = Array.from(mapper.getValue().entries())
|
||||
|
||||
// if there are no path( eg: "" ), all the entries are children, so return the entire mapperEntries without filtering
|
||||
if (!path) return mapperEntries
|
||||
|
||||
mapperEntries = mapperEntries.filter((entry) => {
|
||||
const pattern = new RegExp(`^${path}\/(\\w+)\/?.*$`)
|
||||
|
||||
return !!(typeof entry[0] == "string" && entry[0].match(pattern))
|
||||
})
|
||||
|
||||
return mapperEntries
|
||||
}
|
||||
|
||||
export function getDirectChildrenEntriesFromMapper(
|
||||
path: string,
|
||||
mapper: ReturnType<typeof createMapper<string, string>>
|
||||
) {
|
||||
let mapperEntries = Array.from(mapper.getValue().entries())
|
||||
|
||||
mapperEntries = mapperEntries.filter((entry) => {
|
||||
const pattern = new RegExp(path ? `^${path}\/\\d+$` : `^\\d+$`)
|
||||
|
||||
return !!(typeof entry[0] == "string" && entry[0].match(pattern))
|
||||
})
|
||||
|
||||
return mapperEntries
|
||||
}
|
||||
|
||||
export function reorderIndexesAfterEntryRemoval(
|
||||
pathToReorder: string,
|
||||
mapper: ReturnType<typeof createMapper<string, string>>,
|
||||
requestType: RequestType
|
||||
) {
|
||||
const directChildren = getDirectChildrenEntriesFromMapper(
|
||||
pathToReorder,
|
||||
mapper
|
||||
)
|
||||
|
||||
directChildren.forEach(([path, backendID], index) => {
|
||||
const indexes = path.split("/").map((index) => parseInt(index))
|
||||
const childIndex = indexes.pop()
|
||||
const collectionPath = indexes.join("/")
|
||||
|
||||
if (childIndex != index && backendID) {
|
||||
const newPath = collectionPath ? `${collectionPath}/${index}` : `${index}`
|
||||
|
||||
mapper.removeEntry(undefined, path)
|
||||
mapper.addEntry(newPath, backendID)
|
||||
changeParentForAllChildrenFromMapper(path, newPath, requestType)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function getParentPathFromPath(path: string | undefined) {
|
||||
const indexes = path ? path.split("/") : []
|
||||
indexes.pop()
|
||||
|
||||
return indexes.join("/")
|
||||
}
|
||||
|
||||
export function getMappersAndStoreByType(type: "GQL" | "REST") {
|
||||
const isGQL = type == "GQL"
|
||||
|
||||
const collectionsMapper = isGQL ? gqlCollectionsMapper : restCollectionsMapper
|
||||
|
||||
const requestsMapper = isGQL ? gqlRequestsMapper : restRequestsMapper
|
||||
|
||||
const collectionStore = isGQL ? graphqlCollectionStore : restCollectionStore
|
||||
|
||||
return { collectionsMapper, requestsMapper, collectionStore }
|
||||
}
|
||||
@@ -14,20 +14,7 @@ import {
|
||||
runUserRequestMovedSubscription,
|
||||
runUserRequestUpdatedSubscription,
|
||||
} from "./collections.api"
|
||||
import {
|
||||
collectionReorderOrMovingOperations,
|
||||
collectionsSyncer,
|
||||
restCollectionsOperations,
|
||||
restCollectionsMapper,
|
||||
restRequestsMapper,
|
||||
} from "./collections.sync"
|
||||
import {
|
||||
moveCollectionInMapper,
|
||||
removeAndReorderEntries,
|
||||
reorderIndexesAfterEntryRemoval,
|
||||
reorderCollectionsInMapper,
|
||||
getMappersAndStoreByType,
|
||||
} from "./collections.mapper"
|
||||
import { collectionsSyncer, getStoreByCollectionType } from "./collections.sync"
|
||||
|
||||
import * as E from "fp-ts/Either"
|
||||
import {
|
||||
@@ -57,6 +44,7 @@ import {
|
||||
moveGraphqlRequest,
|
||||
removeGraphqlRequest,
|
||||
setGraphqlCollections,
|
||||
restCollectionStore,
|
||||
} from "@hoppscotch/common/newstore/collections"
|
||||
import { runGQLSubscription } from "@hoppscotch/common/helpers/backend/GQLClient"
|
||||
import {
|
||||
@@ -64,10 +52,7 @@ import {
|
||||
HoppGQLRequest,
|
||||
HoppRESTRequest,
|
||||
} from "@hoppscotch/data"
|
||||
import {
|
||||
gqlCollectionsOperations,
|
||||
gqlCollectionsSyncer,
|
||||
} from "./gqlCollections.sync"
|
||||
import { gqlCollectionsSyncer } from "./gqlCollections.sync"
|
||||
import { ReqType } from "../../api/generated/graphql"
|
||||
|
||||
function initCollectionsSync() {
|
||||
@@ -77,14 +62,14 @@ function initCollectionsSync() {
|
||||
|
||||
gqlCollectionsSyncer.startStoreSync()
|
||||
|
||||
loadUserRootCollections("REST")
|
||||
loadUserRootCollections("GQL")
|
||||
loadUserCollections("REST")
|
||||
loadUserCollections("GQL")
|
||||
|
||||
// TODO: test & make sure the auth thing is working properly
|
||||
currentUser$.subscribe(async (user) => {
|
||||
if (user) {
|
||||
loadUserRootCollections("REST")
|
||||
loadUserRootCollections("GQL")
|
||||
loadUserCollections("REST")
|
||||
loadUserCollections("GQL")
|
||||
}
|
||||
})
|
||||
|
||||
@@ -121,6 +106,7 @@ function exportedCollectionToHoppCollection(
|
||||
const restCollection = collection as ExportedUserCollectionREST
|
||||
|
||||
return {
|
||||
id: restCollection.id,
|
||||
v: 1,
|
||||
name: restCollection.name,
|
||||
folders: restCollection.folders.map((folder) =>
|
||||
@@ -128,6 +114,7 @@ function exportedCollectionToHoppCollection(
|
||||
),
|
||||
requests: restCollection.requests.map(
|
||||
({
|
||||
id,
|
||||
v,
|
||||
auth,
|
||||
body,
|
||||
@@ -139,6 +126,7 @@ function exportedCollectionToHoppCollection(
|
||||
preRequestScript,
|
||||
testScript,
|
||||
}) => ({
|
||||
id,
|
||||
v,
|
||||
auth,
|
||||
body,
|
||||
@@ -156,49 +144,26 @@ function exportedCollectionToHoppCollection(
|
||||
const gqlCollection = collection as ExportedUserCollectionGQL
|
||||
|
||||
return {
|
||||
id: gqlCollection.id,
|
||||
v: 1,
|
||||
name: gqlCollection.name,
|
||||
folders: gqlCollection.folders.map((folder) =>
|
||||
exportedCollectionToHoppCollection(folder, collectionType)
|
||||
),
|
||||
requests: gqlCollection.requests.map(({ v, auth, headers, name }) => ({
|
||||
v,
|
||||
auth,
|
||||
headers,
|
||||
name,
|
||||
})) as HoppGQLRequest[],
|
||||
requests: gqlCollection.requests.map(
|
||||
({ v, auth, headers, name, id }) => ({
|
||||
id,
|
||||
v,
|
||||
auth,
|
||||
headers,
|
||||
name,
|
||||
})
|
||||
) as HoppGQLRequest[],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addMapperEntriesForExportedCollection(
|
||||
collection: ExportedUserCollectionREST | ExportedUserCollectionGQL,
|
||||
localPath: string,
|
||||
collectionType: "REST" | "GQL"
|
||||
) {
|
||||
const { collectionsMapper, requestsMapper } =
|
||||
getMappersAndStoreByType(collectionType)
|
||||
|
||||
if (collection.id) {
|
||||
collectionsMapper.addEntry(localPath, collection.id)
|
||||
|
||||
collection.folders.forEach((folder, index) => {
|
||||
addMapperEntriesForExportedCollection(
|
||||
folder,
|
||||
`${localPath}/${index}`,
|
||||
collectionType
|
||||
)
|
||||
})
|
||||
|
||||
collection.requests.forEach((request, index) => {
|
||||
const requestID = request.id
|
||||
|
||||
requestID && requestsMapper.addEntry(`${localPath}/${index}`, requestID)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async function loadUserRootCollections(collectionType: "REST" | "GQL") {
|
||||
async function loadUserCollections(collectionType: "REST" | "GQL") {
|
||||
const res = await exportUserCollectionsToJSON(
|
||||
undefined,
|
||||
collectionType == "REST" ? ReqType.Rest : ReqType.Gql
|
||||
@@ -233,14 +198,6 @@ async function loadUserRootCollections(collectionType: "REST" | "GQL") {
|
||||
) as HoppCollection<HoppGQLRequest>
|
||||
)
|
||||
)
|
||||
|
||||
exportedCollections.forEach((collection, index) =>
|
||||
addMapperEntriesForExportedCollection(
|
||||
collection,
|
||||
`${index}`,
|
||||
collectionType
|
||||
)
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -284,14 +241,14 @@ function setupUserCollectionCreatedSubscription() {
|
||||
if (E.isRight(res)) {
|
||||
const collectionType = res.right.userCollectionCreated.type
|
||||
|
||||
const { collectionsMapper, collectionStore } =
|
||||
getMappersAndStoreByType(collectionType)
|
||||
const { collectionStore } = getStoreByCollectionType(collectionType)
|
||||
|
||||
const userCollectionBackendID = res.right.userCollectionCreated.id
|
||||
const parentCollectionID = res.right.userCollectionCreated.parent?.id
|
||||
|
||||
const userCollectionLocalID = collectionsMapper.getLocalIDByBackendID(
|
||||
userCollectionBackendID
|
||||
const userCollectionLocalID = getCollectionPathFromCollectionID(
|
||||
userCollectionBackendID,
|
||||
collectionStore.value.state
|
||||
)
|
||||
|
||||
// collection already exists in store ( this instance created it )
|
||||
@@ -301,7 +258,10 @@ function setupUserCollectionCreatedSubscription() {
|
||||
|
||||
const parentCollectionPath =
|
||||
parentCollectionID &&
|
||||
collectionsMapper.getLocalIDByBackendID(parentCollectionID)
|
||||
getCollectionPathFromCollectionID(
|
||||
parentCollectionID,
|
||||
collectionStore.value.state
|
||||
)
|
||||
|
||||
// only folders will have parent collection id
|
||||
if (parentCollectionID && parentCollectionPath) {
|
||||
@@ -325,10 +285,9 @@ function setupUserCollectionCreatedSubscription() {
|
||||
|
||||
if (parentCollection) {
|
||||
const folderIndex = parentCollection.folders.length - 1
|
||||
collectionsMapper.addEntry(
|
||||
`${parentCollectionPath}/${folderIndex}`,
|
||||
userCollectionBackendID
|
||||
)
|
||||
|
||||
const addedFolder = parentCollection.folders[folderIndex]
|
||||
addedFolder.id = userCollectionBackendID
|
||||
}
|
||||
})
|
||||
} else {
|
||||
@@ -349,7 +308,9 @@ function setupUserCollectionCreatedSubscription() {
|
||||
})
|
||||
|
||||
const localIndex = collectionStore.value.state.length - 1
|
||||
collectionsMapper.addEntry(`${localIndex}`, userCollectionBackendID)
|
||||
|
||||
const addedCollection = collectionStore.value.state[localIndex]
|
||||
addedCollection.id = userCollectionBackendID
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -366,11 +327,13 @@ function setupUserCollectionUpdatedSubscription() {
|
||||
if (E.isRight(res)) {
|
||||
const collectionType = res.right.userCollectionUpdated.type
|
||||
|
||||
const { collectionsMapper } = getMappersAndStoreByType(collectionType)
|
||||
const { collectionStore } = getStoreByCollectionType(collectionType)
|
||||
|
||||
const updatedCollectionBackendID = res.right.userCollectionUpdated.id
|
||||
const updatedCollectionLocalPath =
|
||||
collectionsMapper.getLocalIDByBackendID(updatedCollectionBackendID)
|
||||
const updatedCollectionLocalPath = getCollectionPathFromCollectionID(
|
||||
updatedCollectionBackendID,
|
||||
collectionStore.value.state
|
||||
)
|
||||
|
||||
const isFolder =
|
||||
updatedCollectionLocalPath &&
|
||||
@@ -415,37 +378,25 @@ function setupUserCollectionMovedSubscription() {
|
||||
if (E.isRight(res)) {
|
||||
const movedMetadata = res.right.userCollectionMoved
|
||||
|
||||
const sourcePath = restCollectionsMapper.getLocalIDByBackendID(
|
||||
movedMetadata.id
|
||||
const sourcePath = getCollectionPathFromCollectionID(
|
||||
movedMetadata.id,
|
||||
restCollectionStore.value.state
|
||||
)
|
||||
|
||||
let destinationPath: string | undefined
|
||||
|
||||
if (movedMetadata.parent?.id) {
|
||||
destinationPath = restCollectionsMapper.getLocalIDByBackendID(
|
||||
movedMetadata.parent?.id
|
||||
)
|
||||
destinationPath =
|
||||
getCollectionPathFromCollectionID(
|
||||
movedMetadata.parent?.id,
|
||||
restCollectionStore.value.state
|
||||
) ?? undefined
|
||||
}
|
||||
|
||||
const hasAlreadyHappened = hasReorderingOrMovingAlreadyHappened(
|
||||
{
|
||||
sourceCollectionID: movedMetadata.id,
|
||||
destinationCollectionID: movedMetadata.parent?.id,
|
||||
sourcePath,
|
||||
destinationPath,
|
||||
},
|
||||
"MOVING"
|
||||
)
|
||||
|
||||
if (!hasAlreadyHappened) {
|
||||
sourcePath &&
|
||||
runDispatchWithOutSyncing(() => {
|
||||
moveRESTFolder(sourcePath, destinationPath ?? null)
|
||||
})
|
||||
|
||||
sourcePath &&
|
||||
moveCollectionInMapper(sourcePath, destinationPath, "REST")
|
||||
}
|
||||
sourcePath &&
|
||||
runDispatchWithOutSyncing(() => {
|
||||
moveRESTFolder(sourcePath, destinationPath ?? null)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -461,28 +412,13 @@ function setupUserCollectionRemovedSubscription() {
|
||||
const removedCollectionBackendID = res.right.userCollectionRemoved.id
|
||||
const collectionType = res.right.userCollectionRemoved.type
|
||||
|
||||
const { collectionsMapper } = getMappersAndStoreByType(collectionType)
|
||||
const { collectionStore } = getStoreByCollectionType(collectionType)
|
||||
|
||||
const collectionsOperations =
|
||||
collectionType == "REST"
|
||||
? restCollectionsOperations
|
||||
: gqlCollectionsOperations
|
||||
|
||||
const removedCollectionLocalPath =
|
||||
collectionsMapper.getLocalIDByBackendID(removedCollectionBackendID)
|
||||
|
||||
// TODO: seperate operations for rest and gql
|
||||
const isInOperations = !!collectionsOperations.find(
|
||||
(operation) =>
|
||||
operation.type == "COLLECTION_REMOVED" &&
|
||||
operation.collectionBackendID == removedCollectionBackendID
|
||||
const removedCollectionLocalPath = getCollectionPathFromCollectionID(
|
||||
removedCollectionBackendID,
|
||||
collectionStore.value.state
|
||||
)
|
||||
|
||||
// the collection is already removed
|
||||
if (!removedCollectionLocalPath || isInOperations) {
|
||||
return
|
||||
}
|
||||
|
||||
const isFolder =
|
||||
removedCollectionLocalPath &&
|
||||
removedCollectionLocalPath.split("/").length > 1
|
||||
@@ -502,9 +438,6 @@ function setupUserCollectionRemovedSubscription() {
|
||||
: removeGraphqlCollection(parseInt(removedCollectionLocalPath))
|
||||
})
|
||||
}
|
||||
|
||||
removedCollectionLocalPath &&
|
||||
removeAndReorderEntries(removedCollectionLocalPath, collectionType)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -523,40 +456,25 @@ function setupUserCollectionOrderUpdatedSubscription() {
|
||||
const sourceCollectionID = userCollection.id
|
||||
const destinationCollectionID = nextUserCollection?.id
|
||||
|
||||
const sourcePath =
|
||||
restCollectionsMapper.getLocalIDByBackendID(sourceCollectionID)
|
||||
const sourcePath = getCollectionPathFromCollectionID(
|
||||
sourceCollectionID,
|
||||
restCollectionStore.value.state
|
||||
)
|
||||
|
||||
let destinationPath: string | undefined
|
||||
let destinationPath: string | null | undefined
|
||||
|
||||
if (destinationCollectionID) {
|
||||
destinationPath = restCollectionsMapper.getLocalIDByBackendID(
|
||||
destinationCollectionID
|
||||
destinationPath = getCollectionPathFromCollectionID(
|
||||
destinationCollectionID,
|
||||
restCollectionStore.value.state
|
||||
)
|
||||
}
|
||||
|
||||
const hasAlreadyHappened = hasReorderingOrMovingAlreadyHappened(
|
||||
{
|
||||
sourceCollectionID,
|
||||
destinationCollectionID,
|
||||
sourcePath,
|
||||
destinationPath,
|
||||
},
|
||||
"REORDERING"
|
||||
)
|
||||
|
||||
if (!hasAlreadyHappened) {
|
||||
runDispatchWithOutSyncing(() => {
|
||||
if (
|
||||
sourcePath &&
|
||||
destinationPath &&
|
||||
sourceCollectionID &&
|
||||
destinationCollectionID
|
||||
) {
|
||||
updateRESTCollectionOrder(sourcePath, destinationPath)
|
||||
reorderCollectionsInMapper(sourcePath, destinationPath, "REST")
|
||||
}
|
||||
})
|
||||
}
|
||||
runDispatchWithOutSyncing(() => {
|
||||
if (sourcePath) {
|
||||
updateRESTCollectionOrder(sourcePath, destinationPath ?? null)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -575,18 +493,21 @@ function setupUserRequestCreatedSubscription() {
|
||||
|
||||
const requestType = res.right.userRequestCreated.type
|
||||
|
||||
const { collectionsMapper, requestsMapper, collectionStore } =
|
||||
getMappersAndStoreByType(requestType)
|
||||
const { collectionStore } = getStoreByCollectionType(requestType)
|
||||
|
||||
const hasAlreadyHappened =
|
||||
!!requestsMapper.getLocalIDByBackendID(requestID)
|
||||
const hasAlreadyHappened = getRequestPathFromRequestID(
|
||||
requestID,
|
||||
collectionStore.value.state
|
||||
)
|
||||
|
||||
if (hasAlreadyHappened) {
|
||||
if (!!hasAlreadyHappened) {
|
||||
return
|
||||
}
|
||||
|
||||
const collectionPath =
|
||||
collectionsMapper.getLocalIDByBackendID(collectionID)
|
||||
const collectionPath = getCollectionPathFromCollectionID(
|
||||
collectionID,
|
||||
collectionStore.value.state
|
||||
)
|
||||
|
||||
if (collectionID && collectionPath) {
|
||||
runDispatchWithOutSyncing(() => {
|
||||
@@ -599,10 +520,11 @@ function setupUserRequestCreatedSubscription() {
|
||||
collectionPath.split("/").map((index) => parseInt(index))
|
||||
)
|
||||
|
||||
const requestPath =
|
||||
target && `${collectionPath}/${target?.requests.length - 1}`
|
||||
const targetRequest = target?.requests[target?.requests.length - 1]
|
||||
|
||||
requestPath && requestsMapper.addEntry(requestPath, requestID)
|
||||
if (targetRequest) {
|
||||
targetRequest.id = requestID
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -619,31 +541,28 @@ function setupUserRequestUpdatedSubscription() {
|
||||
if (E.isRight(res)) {
|
||||
const requestType = res.right.userRequestUpdated.type
|
||||
|
||||
const { requestsMapper, collectionsMapper } =
|
||||
getMappersAndStoreByType(requestType)
|
||||
const { collectionStore } = getStoreByCollectionType(requestType)
|
||||
|
||||
const requestPath = requestsMapper.getLocalIDByBackendID(
|
||||
res.right.userRequestUpdated.id
|
||||
const requestPath = getRequestPathFromRequestID(
|
||||
res.right.userRequestUpdated.id,
|
||||
collectionStore.value.state
|
||||
)
|
||||
|
||||
const indexes = requestPath?.split("/")
|
||||
const requestIndex = indexes && indexes[indexes?.length - 1]
|
||||
const requestParentPath = collectionsMapper.getLocalIDByBackendID(
|
||||
res.right.userRequestUpdated.collectionID
|
||||
)
|
||||
const collectionPath = requestPath?.collectionPath
|
||||
const requestIndex = requestPath?.requestIndex
|
||||
|
||||
requestIndex &&
|
||||
requestParentPath &&
|
||||
;(requestIndex || requestIndex == 0) &&
|
||||
collectionPath &&
|
||||
runDispatchWithOutSyncing(() => {
|
||||
requestType == "REST"
|
||||
? editRESTRequest(
|
||||
requestParentPath,
|
||||
parseInt(requestIndex),
|
||||
collectionPath,
|
||||
requestIndex,
|
||||
JSON.parse(res.right.userRequestUpdated.request)
|
||||
)
|
||||
: editGraphqlRequest(
|
||||
requestParentPath,
|
||||
parseInt(requestIndex),
|
||||
collectionPath,
|
||||
requestIndex,
|
||||
JSON.parse(res.right.userRequestUpdated.request)
|
||||
)
|
||||
})
|
||||
@@ -659,40 +578,58 @@ function setupUserRequestMovedSubscription() {
|
||||
|
||||
userRequestMoved$.subscribe((res) => {
|
||||
if (E.isRight(res)) {
|
||||
const requestType = res.right.userRequestMoved.request.type
|
||||
const { request, nextRequest } = res.right.userRequestMoved
|
||||
|
||||
const { collectionsMapper } = getMappersAndStoreByType(requestType)
|
||||
const {
|
||||
collectionID: destinationCollectionID,
|
||||
id: sourceRequestID,
|
||||
type: requestType,
|
||||
} = request
|
||||
|
||||
const requestID = res.right.userRequestMoved.request.id
|
||||
const requestIndex = getRequestIndexFromRequestID(requestID)
|
||||
const { collectionStore } = getStoreByCollectionType(requestType)
|
||||
|
||||
const sourceCollectionPath = getCollectionPathFromRequestID(requestID)
|
||||
|
||||
const destinationCollectionID =
|
||||
res.right.userRequestMoved.request.collectionID
|
||||
const destinationCollectionPath = collectionsMapper.getLocalIDByBackendID(
|
||||
destinationCollectionID
|
||||
const sourceRequestPath = getRequestPathFromRequestID(
|
||||
sourceRequestID,
|
||||
collectionStore.value.state
|
||||
)
|
||||
|
||||
const nextRequest = res.right.userRequestMoved.nextRequest
|
||||
const destinationCollectionPath = getCollectionPathFromCollectionID(
|
||||
destinationCollectionID,
|
||||
collectionStore.value.state
|
||||
)
|
||||
|
||||
const destinationRequestIndex = destinationCollectionPath
|
||||
? (() => {
|
||||
const requestsLength = navigateToFolderWithIndexPath(
|
||||
collectionStore.value.state,
|
||||
destinationCollectionPath
|
||||
.split("/")
|
||||
.map((index) => parseInt(index))
|
||||
)?.requests.length
|
||||
|
||||
return requestsLength || requestsLength == 0
|
||||
? requestsLength - 1
|
||||
: undefined
|
||||
})()
|
||||
: undefined
|
||||
|
||||
// there is no nextRequest, so request is moved
|
||||
if (
|
||||
requestIndex &&
|
||||
sourceCollectionPath &&
|
||||
(destinationRequestIndex || destinationRequestIndex == 0) &&
|
||||
destinationCollectionPath &&
|
||||
sourceRequestPath &&
|
||||
!nextRequest
|
||||
) {
|
||||
runDispatchWithOutSyncing(() => {
|
||||
requestType == "REST"
|
||||
? moveRESTRequest(
|
||||
sourceCollectionPath,
|
||||
parseInt(requestIndex),
|
||||
sourceRequestPath.collectionPath,
|
||||
sourceRequestPath.requestIndex,
|
||||
destinationCollectionPath
|
||||
)
|
||||
: moveGraphqlRequest(
|
||||
sourceCollectionPath,
|
||||
parseInt(requestIndex),
|
||||
sourceRequestPath.collectionPath,
|
||||
sourceRequestPath.requestIndex,
|
||||
destinationCollectionPath
|
||||
)
|
||||
})
|
||||
@@ -700,21 +637,37 @@ function setupUserRequestMovedSubscription() {
|
||||
|
||||
// there is nextRequest, so request is reordered
|
||||
if (
|
||||
requestIndex &&
|
||||
sourceCollectionPath &&
|
||||
(destinationRequestIndex || destinationRequestIndex == 0) &&
|
||||
destinationCollectionPath &&
|
||||
nextRequest &&
|
||||
// we don't have request reordering for graphql yet
|
||||
requestType == "REST"
|
||||
) {
|
||||
const nextRequestIndex = getRequestIndexFromRequestID(nextRequest.id)
|
||||
const { collectionID: nextCollectionID, id: nextRequestID } =
|
||||
nextRequest
|
||||
|
||||
const nextCollectionPath =
|
||||
getCollectionPathFromCollectionID(
|
||||
nextCollectionID,
|
||||
collectionStore.value.state
|
||||
) ?? undefined
|
||||
|
||||
const nextRequestIndex = nextCollectionPath
|
||||
? getRequestIndex(
|
||||
nextRequestID,
|
||||
nextCollectionPath,
|
||||
collectionStore.value.state
|
||||
)
|
||||
: undefined
|
||||
|
||||
nextRequestIndex &&
|
||||
nextCollectionPath &&
|
||||
sourceRequestPath &&
|
||||
runDispatchWithOutSyncing(() => {
|
||||
updateRESTRequestOrder(
|
||||
parseInt(requestIndex),
|
||||
parseInt(nextRequestIndex),
|
||||
destinationCollectionPath
|
||||
sourceRequestPath?.requestIndex,
|
||||
nextRequestIndex,
|
||||
nextCollectionPath
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -732,33 +685,27 @@ function setupUserRequestDeletedSubscription() {
|
||||
if (E.isRight(res)) {
|
||||
const requestType = res.right.userRequestDeleted.type
|
||||
|
||||
const { requestsMapper, collectionsMapper } =
|
||||
getMappersAndStoreByType(requestType)
|
||||
const { collectionStore } = getStoreByCollectionType(requestType)
|
||||
|
||||
const deletedRequestPath = requestsMapper.getLocalIDByBackendID(
|
||||
res.right.userRequestDeleted.id
|
||||
const deletedRequestPath = getRequestPathFromRequestID(
|
||||
res.right.userRequestDeleted.id,
|
||||
collectionStore.value.state
|
||||
)
|
||||
|
||||
const indexes = deletedRequestPath?.split("/")
|
||||
const requestIndex = indexes && indexes[indexes?.length - 1]
|
||||
const requestParentPath = collectionsMapper.getLocalIDByBackendID(
|
||||
res.right.userRequestDeleted.collectionID
|
||||
)
|
||||
|
||||
requestIndex &&
|
||||
requestParentPath &&
|
||||
;(deletedRequestPath?.requestIndex ||
|
||||
deletedRequestPath?.requestIndex == 0) &&
|
||||
deletedRequestPath.collectionPath &&
|
||||
runDispatchWithOutSyncing(() => {
|
||||
requestType == "REST"
|
||||
? removeRESTRequest(requestParentPath, parseInt(requestIndex))
|
||||
: removeGraphqlRequest(requestParentPath, parseInt(requestIndex))
|
||||
? removeRESTRequest(
|
||||
deletedRequestPath.collectionPath,
|
||||
deletedRequestPath.requestIndex
|
||||
)
|
||||
: removeGraphqlRequest(
|
||||
deletedRequestPath.collectionPath,
|
||||
deletedRequestPath.requestIndex
|
||||
)
|
||||
})
|
||||
|
||||
deletedRequestPath &&
|
||||
reorderIndexesAfterEntryRemoval(
|
||||
deletedRequestPath,
|
||||
requestsMapper,
|
||||
requestType
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -769,56 +716,74 @@ export const def: CollectionsPlatformDef = {
|
||||
initCollectionsSync,
|
||||
}
|
||||
|
||||
function getRequestIndexFromRequestID(requestID: string) {
|
||||
const requestPath = restRequestsMapper.getLocalIDByBackendID(requestID)
|
||||
function getCollectionPathFromCollectionID(
|
||||
collectionID: string,
|
||||
collections: HoppCollection<HoppRESTRequest | HoppGQLRequest>[],
|
||||
parentPath?: string
|
||||
): string | null {
|
||||
for (const collectionIndex in collections) {
|
||||
if (collections[collectionIndex].id == collectionID) {
|
||||
return parentPath
|
||||
? `${parentPath}/${collectionIndex}`
|
||||
: `${collectionIndex}`
|
||||
} else {
|
||||
const collectionPath = getCollectionPathFromCollectionID(
|
||||
collectionID,
|
||||
collections[collectionIndex].folders,
|
||||
parentPath ? `${parentPath}/${collectionIndex}` : `${collectionIndex}`
|
||||
)
|
||||
|
||||
/**
|
||||
* requestPath is in the form collectionPath/requestIndex,
|
||||
* so to get requestIndex we just split the requestPath with / and get the last element
|
||||
*/
|
||||
const requestPathIndexes = requestPath?.split("/")
|
||||
const requestIndex =
|
||||
requestPathIndexes && requestPathIndexes[requestPathIndexes?.length - 1]
|
||||
if (collectionPath) return collectionPath
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function getRequestPathFromRequestID(
|
||||
requestID: string,
|
||||
collections: HoppCollection<HoppRESTRequest | HoppGQLRequest>[],
|
||||
parentPath?: string
|
||||
): { collectionPath: string; requestIndex: number } | null {
|
||||
for (const collectionIndex in collections) {
|
||||
const requestIndex = collections[collectionIndex].requests.findIndex(
|
||||
(request) => request.id == requestID
|
||||
)
|
||||
|
||||
if (requestIndex != -1) {
|
||||
return {
|
||||
collectionPath: parentPath
|
||||
? `${parentPath}/${collectionIndex}`
|
||||
: `${collectionIndex}`,
|
||||
requestIndex,
|
||||
}
|
||||
} else {
|
||||
const requestPath = getRequestPathFromRequestID(
|
||||
requestID,
|
||||
collections[collectionIndex].folders,
|
||||
parentPath ? `${parentPath}/${collectionIndex}` : `${collectionIndex}`
|
||||
)
|
||||
|
||||
if (requestPath) return requestPath
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function getRequestIndex(
|
||||
requestID: string,
|
||||
parentCollectionPath: string,
|
||||
collections: HoppCollection<HoppRESTRequest | HoppGQLRequest>[]
|
||||
) {
|
||||
const collection = navigateToFolderWithIndexPath(
|
||||
collections,
|
||||
parentCollectionPath?.split("/").map((index) => parseInt(index))
|
||||
)
|
||||
|
||||
const requestIndex = collection?.requests.findIndex(
|
||||
(request) => request.id == requestID
|
||||
)
|
||||
|
||||
return requestIndex
|
||||
}
|
||||
|
||||
function getCollectionPathFromRequestID(requestID: string) {
|
||||
const requestPath = restRequestsMapper.getLocalIDByBackendID(requestID)
|
||||
const requestPathIndexes = requestPath?.split("/")
|
||||
|
||||
// requestIndex will be the last element, remove it
|
||||
requestPathIndexes?.pop()
|
||||
|
||||
return requestPathIndexes?.join("/")
|
||||
}
|
||||
|
||||
function hasReorderingOrMovingAlreadyHappened(
|
||||
incomingOperation: {
|
||||
sourceCollectionID: string
|
||||
destinationCollectionID: string | undefined
|
||||
sourcePath: string | undefined
|
||||
destinationPath: string | undefined
|
||||
},
|
||||
type: "REORDERING" | "MOVING"
|
||||
) {
|
||||
const {
|
||||
sourcePath,
|
||||
sourceCollectionID,
|
||||
destinationCollectionID,
|
||||
destinationPath,
|
||||
} = incomingOperation
|
||||
|
||||
// TODO: implement this as a module
|
||||
// Something like, SyncOperations.hasAlreadyHappened( type: "REORDER_COLLECTIONS", payload )
|
||||
return !!collectionReorderOrMovingOperations.find((reorderOperation) =>
|
||||
reorderOperation.sourceCollectionID == sourceCollectionID &&
|
||||
reorderOperation.destinationCollectionID == destinationCollectionID &&
|
||||
type == "MOVING"
|
||||
? reorderOperation.reorderOperation.fromPath == destinationPath
|
||||
: reorderOperation.reorderOperation.fromPath == sourcePath &&
|
||||
type == "MOVING"
|
||||
? reorderOperation.reorderOperation.toPath == sourcePath
|
||||
: reorderOperation.reorderOperation.toPath == destinationPath
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import {
|
||||
graphqlCollectionStore,
|
||||
navigateToFolderWithIndexPath,
|
||||
removeGraphqlCollection,
|
||||
removeRESTCollection,
|
||||
removeRESTRequest,
|
||||
removeDuplicateRESTCollectionOrFolder,
|
||||
restCollectionStore,
|
||||
} from "@hoppscotch/common/newstore/collections"
|
||||
import {
|
||||
@@ -12,7 +11,7 @@ import {
|
||||
|
||||
import { HoppCollection, HoppRESTRequest } from "@hoppscotch/data"
|
||||
|
||||
import { getSyncInitFunction, runDispatchWithOutSyncing } from "../../lib/sync"
|
||||
import { getSyncInitFunction } from "../../lib/sync"
|
||||
|
||||
import { StoreSyncDefinitionOf } from "../../lib/sync"
|
||||
import { createMapper } from "../../lib/sync/mapper"
|
||||
@@ -30,15 +29,6 @@ import {
|
||||
} from "./collections.api"
|
||||
|
||||
import * as E from "fp-ts/Either"
|
||||
import {
|
||||
removeAndReorderEntries,
|
||||
moveCollectionInMapper,
|
||||
reorderIndexesAfterEntryRemoval,
|
||||
reorderCollectionsInMapper,
|
||||
reorderRequestsMapper,
|
||||
moveRequestInMapper,
|
||||
} from "./collections.mapper"
|
||||
import { gqlCollectionsMapper } from "./gqlCollections.sync"
|
||||
|
||||
// restCollectionsMapper uses the collectionPath as the local identifier
|
||||
export const restCollectionsMapper = createMapper<string, string>()
|
||||
@@ -61,7 +51,9 @@ const recursivelySyncCollections = async (
|
||||
|
||||
if (E.isRight(res)) {
|
||||
parentCollectionID = res.right.createRESTRootUserCollection.id
|
||||
restCollectionsMapper.addEntry(collectionPath, parentCollectionID)
|
||||
|
||||
collection.id = parentCollectionID
|
||||
removeDuplicateRESTCollectionOrFolder(parentCollectionID, collectionPath)
|
||||
} else {
|
||||
parentCollectionID = undefined
|
||||
}
|
||||
@@ -74,13 +66,19 @@ const recursivelySyncCollections = async (
|
||||
|
||||
if (E.isRight(res)) {
|
||||
const childCollectionId = res.right.createRESTChildUserCollection.id
|
||||
restCollectionsMapper.addEntry(collectionPath, childCollectionId)
|
||||
|
||||
collection.id = childCollectionId
|
||||
|
||||
removeDuplicateRESTCollectionOrFolder(
|
||||
childCollectionId,
|
||||
`${collectionPath}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// create the requests
|
||||
if (parentCollectionID) {
|
||||
collection.requests.forEach(async (request, index) => {
|
||||
collection.requests.forEach(async (request) => {
|
||||
const res =
|
||||
parentCollectionID &&
|
||||
(await createRESTUserRequest(
|
||||
@@ -91,7 +89,8 @@ const recursivelySyncCollections = async (
|
||||
|
||||
if (res && E.isRight(res)) {
|
||||
const requestId = res.right.createRESTUserRequest.id
|
||||
restRequestsMapper.addEntry(`${collectionPath}/${index}`, requestId)
|
||||
|
||||
request.id = requestId
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -143,109 +142,101 @@ export const storeSyncDefinition: StoreSyncDefinitionOf<
|
||||
const lastCreatedCollectionIndex =
|
||||
restCollectionStore.value.state.length - 1
|
||||
|
||||
await recursivelySyncCollections(
|
||||
collection,
|
||||
`${lastCreatedCollectionIndex}`
|
||||
)
|
||||
|
||||
removeDuplicateCollectionsFromStore("REST")
|
||||
recursivelySyncCollections(collection, `${lastCreatedCollectionIndex}`)
|
||||
},
|
||||
async removeCollection({ collectionIndex }) {
|
||||
const backendIdentifier = restCollectionsMapper.getBackendIDByLocalID(
|
||||
`${collectionIndex}`
|
||||
)
|
||||
|
||||
if (backendIdentifier) {
|
||||
restCollectionsOperations.push({
|
||||
collectionBackendID: backendIdentifier,
|
||||
type: "COLLECTION_REMOVED",
|
||||
status: "pending",
|
||||
})
|
||||
await deleteUserCollection(backendIdentifier)
|
||||
removeAndReorderEntries(`${collectionIndex}`, "REST")
|
||||
async removeCollection({ collectionID }) {
|
||||
if (collectionID) {
|
||||
await deleteUserCollection(collectionID)
|
||||
}
|
||||
},
|
||||
editCollection({ partialCollection: collection, collectionIndex }) {
|
||||
const backendIdentifier = restCollectionsMapper.getBackendIDByLocalID(
|
||||
`${collectionIndex}`
|
||||
)
|
||||
const collectionID = navigateToFolderWithIndexPath(
|
||||
restCollectionStore.value.state,
|
||||
[collectionIndex]
|
||||
)?.id
|
||||
|
||||
if (backendIdentifier && collection.name) {
|
||||
renameUserCollection(backendIdentifier, collection.name)
|
||||
if (collectionID && collection.name) {
|
||||
renameUserCollection(collectionID, collection.name)
|
||||
}
|
||||
},
|
||||
async addFolder({ name, path }) {
|
||||
const parentCollectionBackendID =
|
||||
restCollectionsMapper.getBackendIDByLocalID(path)
|
||||
const parentCollection = navigateToFolderWithIndexPath(
|
||||
restCollectionStore.value.state,
|
||||
path.split("/").map((index) => parseInt(index))
|
||||
)
|
||||
|
||||
const parentCollectionBackendID = parentCollection?.id
|
||||
|
||||
if (parentCollectionBackendID) {
|
||||
// TODO: remove this replaceAll thing when updating the mapper
|
||||
const foldersLength = parentCollection.folders.length
|
||||
|
||||
const res = await createRESTChildUserCollection(
|
||||
name,
|
||||
parentCollectionBackendID
|
||||
)
|
||||
|
||||
// after the folder is created add the path of the folder with its backend id to the mapper
|
||||
if (E.isRight(res)) {
|
||||
const folderBackendID = res.right.createRESTChildUserCollection.id
|
||||
const parentCollection = navigateToFolderWithIndexPath(
|
||||
restCollectionStore.value.state,
|
||||
path.split("/").map((index) => parseInt(index))
|
||||
)
|
||||
const { id } = res.right.createRESTChildUserCollection
|
||||
|
||||
if (parentCollection && parentCollection.folders.length > 0) {
|
||||
const folderIndex = parentCollection.folders.length - 1
|
||||
restCollectionsMapper.addEntry(
|
||||
`${path}/${folderIndex}`,
|
||||
folderBackendID
|
||||
if (foldersLength) {
|
||||
parentCollection.folders[foldersLength - 1].id = id
|
||||
removeDuplicateRESTCollectionOrFolder(
|
||||
id,
|
||||
`${path}/${foldersLength - 1}`
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
editFolder({ folder, path }) {
|
||||
const folderBackendId = restCollectionsMapper.getBackendIDByLocalID(
|
||||
`${path}`
|
||||
)
|
||||
const folderID = navigateToFolderWithIndexPath(
|
||||
restCollectionStore.value.state,
|
||||
path.split("/").map((index) => parseInt(index))
|
||||
)?.id
|
||||
|
||||
const folderName = folder.name
|
||||
|
||||
if (folderBackendId && folderName) {
|
||||
renameUserCollection(folderBackendId, folderName)
|
||||
if (folderID && folderName) {
|
||||
renameUserCollection(folderID, folderName)
|
||||
}
|
||||
},
|
||||
async removeFolder({ path }) {
|
||||
const folderBackendId = restCollectionsMapper.getBackendIDByLocalID(
|
||||
`${path}`
|
||||
)
|
||||
|
||||
if (folderBackendId) {
|
||||
await deleteUserCollection(folderBackendId)
|
||||
removeAndReorderEntries(path, "REST")
|
||||
async removeFolder({ folderID }) {
|
||||
if (folderID) {
|
||||
await deleteUserCollection(folderID)
|
||||
}
|
||||
},
|
||||
async moveFolder({ destinationPath, path }) {
|
||||
const sourceCollectionBackendID =
|
||||
restCollectionsMapper.getBackendIDByLocalID(path)
|
||||
const { newSourcePath, newDestinationPath } = getPathsAfterMoving(
|
||||
path,
|
||||
destinationPath ?? undefined
|
||||
)
|
||||
|
||||
const destinationCollectionBackendID = destinationPath
|
||||
? restCollectionsMapper.getBackendIDByLocalID(destinationPath)
|
||||
: undefined
|
||||
if (newSourcePath) {
|
||||
const sourceCollectionID = navigateToFolderWithIndexPath(
|
||||
restCollectionStore.value.state,
|
||||
newSourcePath.split("/").map((index) => parseInt(index))
|
||||
)?.id
|
||||
|
||||
if (sourceCollectionBackendID) {
|
||||
await moveUserCollection(
|
||||
sourceCollectionBackendID,
|
||||
destinationCollectionBackendID
|
||||
)
|
||||
const destinationCollectionID = destinationPath
|
||||
? newDestinationPath &&
|
||||
navigateToFolderWithIndexPath(
|
||||
restCollectionStore.value.state,
|
||||
newDestinationPath.split("/").map((index) => parseInt(index))
|
||||
)?.id
|
||||
: undefined
|
||||
|
||||
moveCollectionInMapper(path, destinationPath ?? undefined, "REST")
|
||||
if (sourceCollectionID) {
|
||||
await moveUserCollection(sourceCollectionID, destinationCollectionID)
|
||||
}
|
||||
}
|
||||
},
|
||||
editRequest({ path, requestIndex, requestNew }) {
|
||||
const requestPath = `${path}/${requestIndex}`
|
||||
const request = navigateToFolderWithIndexPath(
|
||||
restCollectionStore.value.state,
|
||||
path.split("/").map((index) => parseInt(index))
|
||||
)?.requests[requestIndex]
|
||||
|
||||
const requestBackendID =
|
||||
restRequestsMapper.getBackendIDByLocalID(requestPath)
|
||||
const requestBackendID = request?.id
|
||||
|
||||
if (requestBackendID) {
|
||||
editUserRequest(
|
||||
@@ -256,63 +247,37 @@ export const storeSyncDefinition: StoreSyncDefinitionOf<
|
||||
}
|
||||
},
|
||||
async saveRequestAs({ path, request }) {
|
||||
const parentCollectionBackendID =
|
||||
restCollectionsMapper.getBackendIDByLocalID(path)
|
||||
const folder = navigateToFolderWithIndexPath(
|
||||
restCollectionStore.value.state,
|
||||
path.split("/").map((index) => parseInt(index))
|
||||
)
|
||||
|
||||
const parentCollectionBackendID = folder?.id
|
||||
|
||||
if (parentCollectionBackendID) {
|
||||
const newRequest = folder.requests[folder.requests.length - 1]
|
||||
|
||||
const res = await createRESTUserRequest(
|
||||
(request as HoppRESTRequest).name,
|
||||
JSON.stringify(request),
|
||||
parentCollectionBackendID
|
||||
)
|
||||
|
||||
const existingPath =
|
||||
E.isRight(res) &&
|
||||
restRequestsMapper.getLocalIDByBackendID(
|
||||
res.right.createRESTUserRequest.id
|
||||
if (E.isRight(res)) {
|
||||
const { id } = res.right.createRESTUserRequest
|
||||
|
||||
newRequest.id = id
|
||||
removeDuplicateRESTCollectionOrFolder(
|
||||
id,
|
||||
`${path}/${folder.requests.length - 1}`,
|
||||
"request"
|
||||
)
|
||||
|
||||
// remove the request if it is already existing ( can happen when the subscription fired before the mutation is resolved )
|
||||
if (existingPath) {
|
||||
const indexes = existingPath.split("/")
|
||||
const existingRequestIndex = indexes.pop()
|
||||
const existingRequestParentPath = indexes.join("/")
|
||||
|
||||
runDispatchWithOutSyncing(() => {
|
||||
existingRequestIndex &&
|
||||
removeRESTRequest(
|
||||
existingRequestParentPath,
|
||||
parseInt(existingRequestIndex)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
const parentCollection = navigateToFolderWithIndexPath(
|
||||
restCollectionStore.value.state,
|
||||
path.split("/").map((index) => parseInt(index))
|
||||
)
|
||||
|
||||
if (parentCollection) {
|
||||
const lastCreatedRequestIndex = parentCollection.requests.length - 1
|
||||
|
||||
if (E.isRight(res)) {
|
||||
restRequestsMapper.addEntry(
|
||||
`${path}/${lastCreatedRequestIndex}`,
|
||||
res.right.createRESTUserRequest.id
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
async removeRequest({ path, requestIndex }) {
|
||||
const requestPath = `${path}/${requestIndex}`
|
||||
const requestBackendID =
|
||||
restRequestsMapper.getBackendIDByLocalID(requestPath)
|
||||
|
||||
if (requestBackendID) {
|
||||
await deleteUserRequest(requestBackendID)
|
||||
restRequestsMapper.removeEntry(requestPath)
|
||||
reorderIndexesAfterEntryRemoval(path, restRequestsMapper, "REST")
|
||||
async removeRequest({ requestID }) {
|
||||
if (requestID) {
|
||||
await deleteUserRequest(requestID)
|
||||
}
|
||||
},
|
||||
moveRequest({ destinationPath, path, requestIndex }) {
|
||||
@@ -331,47 +296,74 @@ export const storeSyncDefinition: StoreSyncDefinitionOf<
|
||||
requestIndex,
|
||||
destinationCollectionPath,
|
||||
destinationCollectionPath,
|
||||
destinationRequestIndex
|
||||
destinationRequestIndex ?? undefined
|
||||
)
|
||||
},
|
||||
async updateCollectionOrder({
|
||||
collectionIndex: collectionPath,
|
||||
destinationCollectionIndex: destinationCollectionPath,
|
||||
}) {
|
||||
const sourceBackendID =
|
||||
restCollectionsMapper.getBackendIDByLocalID(collectionPath)
|
||||
const collections = restCollectionStore.value.state
|
||||
|
||||
const destinationBackendID = restCollectionsMapper.getBackendIDByLocalID(
|
||||
destinationCollectionPath
|
||||
)
|
||||
const sourcePathIndexes = getParentPathIndexesFromPath(collectionPath)
|
||||
const sourceCollectionIndex = getCollectionIndexFromPath(collectionPath)
|
||||
|
||||
if (sourceBackendID) {
|
||||
collectionReorderOrMovingOperations.push({
|
||||
sourceCollectionID: sourceBackendID,
|
||||
destinationCollectionID: destinationBackendID,
|
||||
reorderOperation: {
|
||||
fromPath: `${parseInt(destinationCollectionPath) - 1}`,
|
||||
toPath: destinationCollectionPath,
|
||||
},
|
||||
})
|
||||
const destinationCollectionIndex = !!destinationCollectionPath
|
||||
? getCollectionIndexFromPath(destinationCollectionPath)
|
||||
: undefined
|
||||
|
||||
await updateUserCollectionOrder(sourceBackendID, destinationBackendID)
|
||||
let updatedCollectionIndexs:
|
||||
| [newSourceIndex: number, newDestinationIndex: number | undefined]
|
||||
| undefined
|
||||
|
||||
const currentSourcePath =
|
||||
restCollectionsMapper.getLocalIDByBackendID(sourceBackendID)
|
||||
|
||||
const hasAlreadyHappened = !!(
|
||||
currentSourcePath == `${parseInt(destinationCollectionPath) - 1}`
|
||||
if (
|
||||
(sourceCollectionIndex || sourceCollectionIndex == 0) &&
|
||||
(destinationCollectionIndex || destinationCollectionIndex == 0)
|
||||
) {
|
||||
updatedCollectionIndexs = getIndexesAfterReorder(
|
||||
sourceCollectionIndex,
|
||||
destinationCollectionIndex
|
||||
)
|
||||
} else if (sourceCollectionIndex || sourceCollectionIndex == 0) {
|
||||
if (sourcePathIndexes.length == 0) {
|
||||
// we're reordering root collections
|
||||
updatedCollectionIndexs = [collections.length - 1, undefined]
|
||||
} else {
|
||||
const sourceCollection = navigateToFolderWithIndexPath(collections, [
|
||||
...sourcePathIndexes,
|
||||
])
|
||||
|
||||
if (!hasAlreadyHappened) {
|
||||
reorderCollectionsInMapper(
|
||||
collectionPath,
|
||||
destinationCollectionPath,
|
||||
"REST"
|
||||
)
|
||||
if (sourceCollection && sourceCollection.folders.length > 0) {
|
||||
updatedCollectionIndexs = [
|
||||
sourceCollection.folders.length - 1,
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const sourceCollectionID =
|
||||
updatedCollectionIndexs &&
|
||||
navigateToFolderWithIndexPath(collections, [
|
||||
...sourcePathIndexes,
|
||||
updatedCollectionIndexs[0],
|
||||
])?.id
|
||||
|
||||
const destinationCollectionID =
|
||||
updatedCollectionIndexs &&
|
||||
(updatedCollectionIndexs[1] || updatedCollectionIndexs[1] == 0)
|
||||
? navigateToFolderWithIndexPath(collections, [
|
||||
...sourcePathIndexes,
|
||||
updatedCollectionIndexs[1],
|
||||
])?.id
|
||||
: undefined
|
||||
|
||||
if (sourceCollectionID) {
|
||||
await updateUserCollectionOrder(
|
||||
sourceCollectionID,
|
||||
destinationCollectionID
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -382,28 +374,51 @@ export const collectionsSyncer = getSyncInitFunction(
|
||||
getSettingSubject("syncCollections")
|
||||
)
|
||||
|
||||
async function moveOrReorderRequests(
|
||||
export async function moveOrReorderRequests(
|
||||
requestIndex: number,
|
||||
path: string,
|
||||
destinationPath: string,
|
||||
nextRequestIndex?: number
|
||||
nextRequestIndex?: number,
|
||||
requestType: "REST" | "GQL" = "REST"
|
||||
) {
|
||||
const sourceCollectionBackendID =
|
||||
restCollectionsMapper.getBackendIDByLocalID(path)
|
||||
const destinationCollectionBackendID =
|
||||
restCollectionsMapper.getBackendIDByLocalID(destinationPath)
|
||||
const { collectionStore } = getStoreByCollectionType(requestType)
|
||||
|
||||
const requestBackendID = restRequestsMapper.getBackendIDByLocalID(
|
||||
`${path}/${requestIndex}`
|
||||
const sourceCollectionBackendID = navigateToFolderWithIndexPath(
|
||||
collectionStore.value.state,
|
||||
path.split("/").map((index) => parseInt(index))
|
||||
)?.id
|
||||
|
||||
const destinationCollection = navigateToFolderWithIndexPath(
|
||||
collectionStore.value.state,
|
||||
destinationPath.split("/").map((index) => parseInt(index))
|
||||
)
|
||||
|
||||
const destinationCollectionBackendID = destinationCollection?.id
|
||||
|
||||
let requestBackendID: string | undefined
|
||||
|
||||
let nextRequestBackendID: string | undefined
|
||||
|
||||
// we only need this for reordering requests, not for moving requests
|
||||
if (nextRequestIndex) {
|
||||
nextRequestBackendID = restRequestsMapper.getBackendIDByLocalID(
|
||||
`${destinationPath}/${nextRequestIndex}`
|
||||
// reordering
|
||||
const [newRequestIndex, newDestinationIndex] = getIndexesAfterReorder(
|
||||
requestIndex,
|
||||
nextRequestIndex
|
||||
)
|
||||
|
||||
requestBackendID =
|
||||
destinationCollection?.requests[newRequestIndex]?.id ?? undefined
|
||||
|
||||
nextRequestBackendID =
|
||||
destinationCollection?.requests[newDestinationIndex]?.id ?? undefined
|
||||
} else {
|
||||
// moving
|
||||
const requests = destinationCollection?.requests
|
||||
requestBackendID =
|
||||
requests && requests.length > 0
|
||||
? requests[requests.length - 1]?.id
|
||||
: undefined
|
||||
}
|
||||
|
||||
if (
|
||||
@@ -417,46 +432,112 @@ async function moveOrReorderRequests(
|
||||
requestBackendID,
|
||||
nextRequestBackendID
|
||||
)
|
||||
|
||||
if (nextRequestBackendID && nextRequestIndex) {
|
||||
reorderRequestsMapper(requestIndex, path, nextRequestIndex, "REST")
|
||||
} else {
|
||||
moveRequestInMapper(requestIndex, path, destinationPath, "REST")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function removeDuplicateCollectionsFromStore(
|
||||
collectionType: "REST" | "GQL"
|
||||
) {
|
||||
const collectionsMapper =
|
||||
collectionType === "REST" ? restCollectionsMapper : gqlCollectionsMapper
|
||||
|
||||
const mapperEntries = Array.from(collectionsMapper.getValue().entries())
|
||||
|
||||
const seenBackendIDs = new Set<string>()
|
||||
|
||||
const localIDsToRemove = new Set<string>()
|
||||
|
||||
mapperEntries.forEach(([localID, backendID]) => {
|
||||
if (backendID && seenBackendIDs.has(backendID)) {
|
||||
localIDsToRemove.add(localID)
|
||||
} else {
|
||||
backendID && seenBackendIDs.add(backendID)
|
||||
}
|
||||
})
|
||||
|
||||
localIDsToRemove.forEach((localID) => {
|
||||
collectionType === "REST"
|
||||
? removeRESTCollection(parseInt(localID))
|
||||
: removeGraphqlCollection(parseInt(localID))
|
||||
|
||||
collectionsMapper.removeEntry(undefined, localID)
|
||||
|
||||
const indexes = localID.split("/")
|
||||
indexes.pop()
|
||||
const parentPath = indexes.join("/")
|
||||
|
||||
reorderIndexesAfterEntryRemoval(parentPath, collectionsMapper, "REST")
|
||||
})
|
||||
function getParentPathIndexesFromPath(path: string) {
|
||||
const indexes = path.split("/")
|
||||
indexes.pop()
|
||||
return indexes.map((index) => parseInt(index))
|
||||
}
|
||||
|
||||
export function getCollectionIndexFromPath(collectionPath: string) {
|
||||
const sourceCollectionIndexString = collectionPath.split("/").pop()
|
||||
const sourceCollectionIndex = sourceCollectionIndexString
|
||||
? parseInt(sourceCollectionIndexString)
|
||||
: undefined
|
||||
|
||||
return sourceCollectionIndex
|
||||
}
|
||||
|
||||
/**
|
||||
* the sync function is called after the reordering has happened on the store
|
||||
* because of this we need to find the new source and destination indexes after the reordering
|
||||
*/
|
||||
function getIndexesAfterReorder(
|
||||
oldSourceIndex: number,
|
||||
oldDestinationIndex: number
|
||||
): [newSourceIndex: number, newDestinationIndex: number] {
|
||||
// Source Becomes Destination -1
|
||||
// Destination Remains Same
|
||||
if (oldSourceIndex < oldDestinationIndex) {
|
||||
return [oldDestinationIndex - 1, oldDestinationIndex]
|
||||
}
|
||||
|
||||
// Source Becomes The Destination
|
||||
// Destintion Becomes Source + 1
|
||||
if (oldSourceIndex > oldDestinationIndex) {
|
||||
return [oldDestinationIndex, oldDestinationIndex + 1]
|
||||
}
|
||||
|
||||
throw new Error("Source and Destination are the same")
|
||||
}
|
||||
|
||||
/**
|
||||
* the sync function is called after moving a folder has happened on the store,
|
||||
* because of this the source index given to the sync function is not the live one
|
||||
* we need to find the new source index after the moving
|
||||
*/
|
||||
function getPathsAfterMoving(sourcePath: string, destinationPath?: string) {
|
||||
if (!destinationPath) {
|
||||
return {
|
||||
newSourcePath: `${restCollectionStore.value.state.length - 1}`,
|
||||
newDestinationPath: destinationPath,
|
||||
}
|
||||
}
|
||||
|
||||
const sourceParentPath = getParentPathFromPath(sourcePath)
|
||||
const destinationParentPath = getParentPathFromPath(destinationPath)
|
||||
|
||||
const isSameParentPath = sourceParentPath === destinationParentPath
|
||||
|
||||
let newDestinationPath: string
|
||||
|
||||
if (isSameParentPath) {
|
||||
const sourceIndex = getCollectionIndexFromPath(sourcePath)
|
||||
const destinationIndex = getCollectionIndexFromPath(destinationPath)
|
||||
|
||||
if (
|
||||
(sourceIndex || sourceIndex == 0) &&
|
||||
(destinationIndex || destinationIndex == 0) &&
|
||||
sourceIndex < destinationIndex
|
||||
) {
|
||||
newDestinationPath = destinationParentPath
|
||||
? `${destinationParentPath}/${destinationIndex - 1}`
|
||||
: `${destinationIndex - 1}`
|
||||
} else {
|
||||
newDestinationPath = destinationPath
|
||||
}
|
||||
} else {
|
||||
newDestinationPath = destinationPath
|
||||
}
|
||||
|
||||
const destinationFolder = navigateToFolderWithIndexPath(
|
||||
restCollectionStore.value.state,
|
||||
newDestinationPath.split("/").map((index) => parseInt(index))
|
||||
)
|
||||
|
||||
const newSourcePath = destinationFolder
|
||||
? `${newDestinationPath}/${destinationFolder?.folders.length - 1}`
|
||||
: undefined
|
||||
|
||||
return {
|
||||
newSourcePath,
|
||||
newDestinationPath,
|
||||
}
|
||||
}
|
||||
|
||||
function getParentPathFromPath(path: string | undefined) {
|
||||
const indexes = path ? path.split("/") : []
|
||||
indexes.pop()
|
||||
|
||||
return indexes.join("/")
|
||||
}
|
||||
|
||||
export function getStoreByCollectionType(type: "GQL" | "REST") {
|
||||
const isGQL = type == "GQL"
|
||||
|
||||
const collectionStore = isGQL ? graphqlCollectionStore : restCollectionStore
|
||||
|
||||
return { collectionStore }
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
graphqlCollectionStore,
|
||||
navigateToFolderWithIndexPath,
|
||||
removeGraphqlRequest,
|
||||
removeDuplicateGraphqlCollectionOrFolder,
|
||||
} from "@hoppscotch/common/newstore/collections"
|
||||
import {
|
||||
getSettingSubject,
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
|
||||
import { HoppCollection, HoppRESTRequest } from "@hoppscotch/data"
|
||||
|
||||
import { getSyncInitFunction, runDispatchWithOutSyncing } from "../../lib/sync"
|
||||
import { getSyncInitFunction } from "../../lib/sync"
|
||||
|
||||
import { StoreSyncDefinitionOf } from "../../lib/sync"
|
||||
import { createMapper } from "../../lib/sync/mapper"
|
||||
@@ -21,18 +21,11 @@ import {
|
||||
deleteUserCollection,
|
||||
deleteUserRequest,
|
||||
editGQLUserRequest,
|
||||
moveUserRequest,
|
||||
renameUserCollection,
|
||||
} from "./collections.api"
|
||||
|
||||
import * as E from "fp-ts/Either"
|
||||
import {
|
||||
moveRequestInMapper,
|
||||
removeAndReorderEntries,
|
||||
reorderIndexesAfterEntryRemoval,
|
||||
reorderRequestsMapper,
|
||||
} from "./collections.mapper"
|
||||
import { removeDuplicateCollectionsFromStore } from "./collections.sync"
|
||||
import { moveOrReorderRequests } from "./collections.sync"
|
||||
|
||||
// gqlCollectionsMapper uses the collectionPath as the local identifier
|
||||
export const gqlCollectionsMapper = createMapper<string, string>()
|
||||
@@ -55,7 +48,12 @@ const recursivelySyncCollections = async (
|
||||
|
||||
if (E.isRight(res)) {
|
||||
parentCollectionID = res.right.createGQLRootUserCollection.id
|
||||
gqlCollectionsMapper.addEntry(collectionPath, parentCollectionID)
|
||||
|
||||
collection.id = parentCollectionID
|
||||
removeDuplicateGraphqlCollectionOrFolder(
|
||||
parentCollectionID,
|
||||
collectionPath
|
||||
)
|
||||
} else {
|
||||
parentCollectionID = undefined
|
||||
}
|
||||
@@ -68,13 +66,19 @@ const recursivelySyncCollections = async (
|
||||
|
||||
if (E.isRight(res)) {
|
||||
const childCollectionId = res.right.createGQLChildUserCollection.id
|
||||
gqlCollectionsMapper.addEntry(collectionPath, childCollectionId)
|
||||
|
||||
collection.id = childCollectionId
|
||||
|
||||
removeDuplicateGraphqlCollectionOrFolder(
|
||||
childCollectionId,
|
||||
`${collectionPath}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// create the requests
|
||||
if (parentCollectionID) {
|
||||
collection.requests.forEach(async (request, index) => {
|
||||
collection.requests.forEach(async (request) => {
|
||||
const res =
|
||||
parentCollectionID &&
|
||||
(await createGQLUserRequest(
|
||||
@@ -85,7 +89,8 @@ const recursivelySyncCollections = async (
|
||||
|
||||
if (res && E.isRight(res)) {
|
||||
const requestId = res.right.createGQLUserRequest.id
|
||||
gqlRequestsMapper.addEntry(`${collectionPath}/${index}`, requestId)
|
||||
|
||||
request.id = requestId
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -141,86 +146,73 @@ export const storeSyncDefinition: StoreSyncDefinitionOf<
|
||||
collection,
|
||||
`${lastCreatedCollectionIndex}`
|
||||
)
|
||||
|
||||
removeDuplicateCollectionsFromStore("GQL")
|
||||
},
|
||||
async removeCollection({ collectionIndex }) {
|
||||
const backendIdentifier = gqlCollectionsMapper.getBackendIDByLocalID(
|
||||
`${collectionIndex}`
|
||||
)
|
||||
|
||||
if (backendIdentifier) {
|
||||
gqlCollectionsOperations.push({
|
||||
collectionBackendID: backendIdentifier,
|
||||
type: "COLLECTION_REMOVED",
|
||||
status: "pending",
|
||||
})
|
||||
await deleteUserCollection(backendIdentifier)
|
||||
removeAndReorderEntries(`${collectionIndex}`, "GQL")
|
||||
async removeCollection({ collectionID }) {
|
||||
if (collectionID) {
|
||||
await deleteUserCollection(collectionID)
|
||||
}
|
||||
},
|
||||
editCollection({ collection, collectionIndex }) {
|
||||
const backendIdentifier = gqlCollectionsMapper.getBackendIDByLocalID(
|
||||
`${collectionIndex}`
|
||||
)
|
||||
const collectionID = navigateToFolderWithIndexPath(
|
||||
graphqlCollectionStore.value.state,
|
||||
[collectionIndex]
|
||||
)?.id
|
||||
|
||||
if (backendIdentifier && collection.name) {
|
||||
renameUserCollection(backendIdentifier, collection.name)
|
||||
if (collectionID && collection.name) {
|
||||
renameUserCollection(collectionID, collection.name)
|
||||
}
|
||||
},
|
||||
async addFolder({ name, path }) {
|
||||
const parentCollectionBackendID =
|
||||
gqlCollectionsMapper.getBackendIDByLocalID(path)
|
||||
const parentCollection = navigateToFolderWithIndexPath(
|
||||
graphqlCollectionStore.value.state,
|
||||
path.split("/").map((index) => parseInt(index))
|
||||
)
|
||||
|
||||
const parentCollectionBackendID = parentCollection?.id
|
||||
|
||||
if (parentCollectionBackendID) {
|
||||
// TODO: remove this replaceAll thing when updating the mapper
|
||||
const foldersLength = parentCollection.folders.length
|
||||
|
||||
const res = await createGQLChildUserCollection(
|
||||
name,
|
||||
parentCollectionBackendID
|
||||
)
|
||||
|
||||
// after the folder is created add the path of the folder with its backend id to the mapper
|
||||
if (E.isRight(res)) {
|
||||
const folderBackendID = res.right.createGQLChildUserCollection.id
|
||||
const parentCollection = navigateToFolderWithIndexPath(
|
||||
graphqlCollectionStore.value.state,
|
||||
path.split("/").map((index) => parseInt(index))
|
||||
)
|
||||
const { id } = res.right.createGQLChildUserCollection
|
||||
|
||||
if (parentCollection && parentCollection.folders.length > 0) {
|
||||
const folderIndex = parentCollection.folders.length - 1
|
||||
gqlCollectionsMapper.addEntry(
|
||||
`${path}/${folderIndex}`,
|
||||
folderBackendID
|
||||
if (foldersLength) {
|
||||
parentCollection.folders[foldersLength - 1].id = id
|
||||
removeDuplicateGraphqlCollectionOrFolder(
|
||||
id,
|
||||
`${path}/${foldersLength - 1}`
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
editFolder({ folder, path }) {
|
||||
const folderBackendId = gqlCollectionsMapper.getBackendIDByLocalID(
|
||||
`${path}`
|
||||
)
|
||||
const folderBackendId = navigateToFolderWithIndexPath(
|
||||
graphqlCollectionStore.value.state,
|
||||
path.split("/").map((index) => parseInt(index))
|
||||
)?.id
|
||||
|
||||
if (folderBackendId) {
|
||||
if (folderBackendId && folder.name) {
|
||||
renameUserCollection(folderBackendId, folder.name)
|
||||
}
|
||||
},
|
||||
async removeFolder({ path }) {
|
||||
const folderBackendId = gqlCollectionsMapper.getBackendIDByLocalID(
|
||||
`${path}`
|
||||
)
|
||||
|
||||
if (folderBackendId) {
|
||||
await deleteUserCollection(folderBackendId)
|
||||
removeAndReorderEntries(path, "GQL")
|
||||
async removeFolder({ folderID }) {
|
||||
if (folderID) {
|
||||
await deleteUserCollection(folderID)
|
||||
}
|
||||
},
|
||||
editRequest({ path, requestIndex, requestNew }) {
|
||||
const requestPath = `${path}/${requestIndex}`
|
||||
const request = navigateToFolderWithIndexPath(
|
||||
graphqlCollectionStore.value.state,
|
||||
path.split("/").map((index) => parseInt(index))
|
||||
)?.requests[requestIndex]
|
||||
|
||||
const requestBackendID =
|
||||
gqlRequestsMapper.getBackendIDByLocalID(requestPath)
|
||||
const requestBackendID = request?.id
|
||||
|
||||
if (requestBackendID) {
|
||||
editGQLUserRequest(
|
||||
@@ -231,67 +223,41 @@ export const storeSyncDefinition: StoreSyncDefinitionOf<
|
||||
}
|
||||
},
|
||||
async saveRequestAs({ path, request }) {
|
||||
const parentCollectionBackendID =
|
||||
gqlCollectionsMapper.getBackendIDByLocalID(path)
|
||||
const folder = navigateToFolderWithIndexPath(
|
||||
graphqlCollectionStore.value.state,
|
||||
path.split("/").map((index) => parseInt(index))
|
||||
)
|
||||
|
||||
const parentCollectionBackendID = folder?.id
|
||||
|
||||
if (parentCollectionBackendID) {
|
||||
const newRequest = folder.requests[folder.requests.length - 1]
|
||||
|
||||
const res = await createGQLUserRequest(
|
||||
(request as HoppRESTRequest).name,
|
||||
JSON.stringify(request),
|
||||
parentCollectionBackendID
|
||||
)
|
||||
|
||||
const existingPath =
|
||||
E.isRight(res) &&
|
||||
gqlRequestsMapper.getLocalIDByBackendID(
|
||||
res.right.createGQLUserRequest.id
|
||||
if (E.isRight(res)) {
|
||||
const { id } = res.right.createGQLUserRequest
|
||||
|
||||
newRequest.id = id
|
||||
removeDuplicateGraphqlCollectionOrFolder(
|
||||
id,
|
||||
`${path}/${folder.requests.length - 1}`,
|
||||
"request"
|
||||
)
|
||||
|
||||
// remove the request if it is already existing ( can happen when the subscription fired before the mutation is resolved )
|
||||
if (existingPath) {
|
||||
const indexes = existingPath.split("/")
|
||||
const existingRequestIndex = indexes.pop()
|
||||
const existingRequestParentPath = indexes.join("/")
|
||||
|
||||
runDispatchWithOutSyncing(() => {
|
||||
existingRequestIndex &&
|
||||
removeGraphqlRequest(
|
||||
existingRequestParentPath,
|
||||
parseInt(existingRequestIndex)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
const parentCollection = navigateToFolderWithIndexPath(
|
||||
graphqlCollectionStore.value.state,
|
||||
path.split("/").map((index) => parseInt(index))
|
||||
)
|
||||
|
||||
if (parentCollection) {
|
||||
const lastCreatedRequestIndex = parentCollection.requests.length - 1
|
||||
|
||||
if (E.isRight(res)) {
|
||||
gqlRequestsMapper.addEntry(
|
||||
`${path}/${lastCreatedRequestIndex}`,
|
||||
res.right.createGQLUserRequest.id
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
async removeRequest({ path, requestIndex }) {
|
||||
const requestPath = `${path}/${requestIndex}`
|
||||
const requestBackendID =
|
||||
gqlRequestsMapper.getBackendIDByLocalID(requestPath)
|
||||
|
||||
if (requestBackendID) {
|
||||
await deleteUserRequest(requestBackendID)
|
||||
gqlRequestsMapper.removeEntry(requestPath)
|
||||
reorderIndexesAfterEntryRemoval(path, gqlRequestsMapper, "GQL")
|
||||
async removeRequest({ requestID }) {
|
||||
if (requestID) {
|
||||
await deleteUserRequest(requestID)
|
||||
}
|
||||
},
|
||||
moveRequest({ destinationPath, path, requestIndex }) {
|
||||
moveOrReorderRequests(requestIndex, path, destinationPath)
|
||||
moveOrReorderRequests(requestIndex, path, destinationPath, undefined, "GQL")
|
||||
},
|
||||
}
|
||||
|
||||
@@ -301,47 +267,3 @@ export const gqlCollectionsSyncer = getSyncInitFunction(
|
||||
() => settingsStore.value.syncCollections,
|
||||
getSettingSubject("syncCollections")
|
||||
)
|
||||
|
||||
async function moveOrReorderRequests(
|
||||
requestIndex: number,
|
||||
path: string,
|
||||
destinationPath: string,
|
||||
nextRequestIndex?: number
|
||||
) {
|
||||
const sourceCollectionBackendID =
|
||||
gqlCollectionsMapper.getBackendIDByLocalID(path)
|
||||
const destinationCollectionBackendID =
|
||||
gqlCollectionsMapper.getBackendIDByLocalID(destinationPath)
|
||||
|
||||
const requestBackendID = gqlRequestsMapper.getBackendIDByLocalID(
|
||||
`${path}/${requestIndex}`
|
||||
)
|
||||
|
||||
let nextRequestBackendID: string | undefined
|
||||
|
||||
// we only need this for reordering requests, not for moving requests
|
||||
if (nextRequestIndex) {
|
||||
nextRequestBackendID = gqlRequestsMapper.getBackendIDByLocalID(
|
||||
`${destinationPath}/${nextRequestIndex}`
|
||||
)
|
||||
}
|
||||
|
||||
if (
|
||||
sourceCollectionBackendID &&
|
||||
destinationCollectionBackendID &&
|
||||
requestBackendID
|
||||
) {
|
||||
await moveUserRequest(
|
||||
sourceCollectionBackendID,
|
||||
destinationCollectionBackendID,
|
||||
requestBackendID,
|
||||
nextRequestBackendID
|
||||
)
|
||||
|
||||
if (nextRequestBackendID && nextRequestIndex) {
|
||||
reorderRequestsMapper(requestIndex, path, nextRequestIndex, "GQL")
|
||||
} else {
|
||||
moveRequestInMapper(requestIndex, path, destinationPath, "GQL")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,12 +192,6 @@ function setupUserEnvironmentDeletedSubscription() {
|
||||
runDispatchWithOutSyncing(() => {
|
||||
deleteEnvironment(localIndex)
|
||||
})
|
||||
} else {
|
||||
console.log("could not find the localIndex")
|
||||
// TODO:
|
||||
// handle order of events
|
||||
// eg: update coming before create
|
||||
// skipping for this release
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -26,7 +26,6 @@ async function loadTabStateFromSync(): Promise<PersistableRESTTabState | null> {
|
||||
|
||||
return currentRESTSession ? JSON.parse(currentRESTSession) : null
|
||||
} else {
|
||||
console.log(res)
|
||||
}
|
||||
|
||||
return null
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user