refactor: handle based updates post collection move

This commit is contained in:
jamesgeorge007
2024-05-09 21:03:56 +05:30
parent 141652ffb6
commit e342e53db1
4 changed files with 213 additions and 38 deletions

View File

@@ -1569,10 +1569,10 @@ const dropToRoot = async ({ dataTransfer }: DragEvent) => {
restCollectionState.value.length - 1 restCollectionState.value.length - 1
).toString() ).toString()
updateSaveContextForAffectedRequests( // updateSaveContextForAffectedRequests(
draggedCollectionIndex, // draggedCollectionIndex,
destinationRootCollectionIndex // destinationRootCollectionIndex
) // )
const destinationRootCollectionHandleResult = const destinationRootCollectionHandleResult =
await workspaceService.getCollectionHandle( await workspaceService.getCollectionHandle(
@@ -1808,43 +1808,43 @@ const dropCollection = async (payload: {
// Hence, we need to reduce the destination root collection index by 1 // Hence, we need to reduce the destination root collection index by 1
// This only applies to the case when the destination collection lies below the dragged collection // This only applies to the case when the destination collection lies below the dragged collection
let resolvedDestinationCollectionIndex = destinationCollectionIndex // let resolvedDestinationCollectionIndex = destinationCollectionIndex
const draggedRootCollectionIndex = parseInt( // const draggedRootCollectionIndex = parseInt(
pathToIndex(draggedCollectionIndex)[0] // pathToIndex(draggedCollectionIndex)[0]
) // )
const destinationRootCollectionIndex = parseInt( // const destinationRootCollectionIndex = parseInt(
pathToIndex(destinationCollectionIndex)[0] // pathToIndex(destinationCollectionIndex)[0]
) // )
if ( // if (
isAlreadyInRoot(draggedCollectionIndex) && // isAlreadyInRoot(draggedCollectionIndex) &&
destinationRootCollectionIndex > draggedRootCollectionIndex // destinationRootCollectionIndex > draggedRootCollectionIndex
) { // ) {
resolvedDestinationCollectionIndex = `${ // resolvedDestinationCollectionIndex = `${
destinationRootCollectionIndex - 1 // destinationRootCollectionIndex - 1
}/${pathToIndex(destinationCollectionIndex).slice(1).join("/")}` // }/${pathToIndex(destinationCollectionIndex).slice(1).join("/")}`
resolvedDestinationCollectionIndex = // resolvedDestinationCollectionIndex =
resolvedDestinationCollectionIndex.endsWith("/") // resolvedDestinationCollectionIndex.endsWith("/")
? resolvedDestinationCollectionIndex.slice(0, -1) // ? resolvedDestinationCollectionIndex.slice(0, -1)
: resolvedDestinationCollectionIndex // : resolvedDestinationCollectionIndex
} // }
resolveSaveContextOnCollectionReorder({ // resolveSaveContextOnCollectionReorder({
lastIndex: pathToLastIndex(draggedCollectionIndex), // lastIndex: pathToLastIndex(draggedCollectionIndex),
newIndex: -1, // newIndex: -1,
folderPath: draggedParentCollectionIndex, // folderPath: draggedParentCollectionIndex,
length: getFoldersByPath( // length: getFoldersByPath(
restCollectionState.value, // restCollectionState.value,
draggedParentCollectionIndex // draggedParentCollectionIndex
).length, // ).length,
}) // })
updateSaveContextForAffectedRequests( // updateSaveContextForAffectedRequests(
draggedCollectionIndex, // draggedCollectionIndex,
`${resolvedDestinationCollectionIndex}/${totalChildCollectionsInDestinationCollection}` // `${resolvedDestinationCollectionIndex}/${totalChildCollectionsInDestinationCollection}`
) // )
const destinationCollectionHandleResult = const destinationCollectionHandleResult =
await workspaceService.getCollectionHandle( await workspaceService.getCollectionHandle(

View File

@@ -12,6 +12,7 @@ export type HoppRESTSaveContext =
* The origin source of the request * The origin source of the request
*/ */
// TODO: Make this `user-collection` after porting all usages // TODO: Make this `user-collection` after porting all usages
// Future TODO: Keep separate types for the IDs (specific to persistence) & `requestHandle` (only existing at runtime)
originLocation: "workspace-user-collection" originLocation: "workspace-user-collection"
/** /**
* ID of the workspace * ID of the workspace

View File

@@ -295,7 +295,7 @@ const onResolveConfirmSaveTab = () => {
if ( if (
!saveContext || !saveContext ||
(saveContext.originLocation === "workspace-user-collection" && (saveContext.originLocation === "workspace-user-collection" &&
saveContext.requestHandle?.value.type === "invalid") saveContext.requestHandle?.get().value.type === "invalid")
) { ) {
return (savingRequest.value = true) return (savingRequest.value = true)
} }
@@ -331,7 +331,7 @@ const getTabDirtyStatus = (tab: HoppTab<HoppRESTDocument>) => {
return ( return (
tab.document.saveContext?.originLocation === "workspace-user-collection" && tab.document.saveContext?.originLocation === "workspace-user-collection" &&
tab.document.saveContext.requestHandle?.value.type === "invalid" tab.document.saveContext.requestHandle?.get().value.type === "invalid"
) )
} }

View File

@@ -120,6 +120,8 @@ export class PersonalWorkspaceProviderService
this.workspaceService.registerWorkspaceProvider(this) this.workspaceService.registerWorkspaceProvider(this)
} }
// TODO: Move the below out of provider definitions as generic helper functions
/** /**
* Used to get the index of the request from the path * Used to get the index of the request from the path
* @param path The path of the request * @param path The path of the request
@@ -130,6 +132,25 @@ export class PersonalWorkspaceProviderService
return parseInt(pathArr[pathArr.length - 1]) return parseInt(pathArr[pathArr.length - 1])
} }
/**
* @param path The path of the collection or request
* @returns The index of the collection or request
*/
private pathToIndex(path: string) {
const pathArr = path.split("/")
return pathArr
}
/**
* Checks if the collection is already in the root
* @param id - path of the collection
* @returns boolean - true if the collection is already in the root
*/
private isAlreadyInRoot(id: string) {
const indexPath = this.pathToIndex(id)
return indexPath.length === 1
}
public createRESTRootCollection( public createRESTRootCollection(
workspaceHandle: Handle<Workspace>, workspaceHandle: Handle<Workspace>,
newCollection: Partial<Exclude<HoppCollection, "id">> & { name: string } newCollection: Partial<Exclude<HoppCollection, "id">> & { name: string }
@@ -665,12 +686,165 @@ export class PersonalWorkspaceProviderService
) { ) {
return Promise.resolve(E.left("INVALID_COLLECTION_HANDLE" as const)) return Promise.resolve(E.left("INVALID_COLLECTION_HANDLE" as const))
} }
const { collectionID: draggedCollectionID } = collectionHandleRef.value.data
const draggedParentCollectionID = this.isAlreadyInRoot(draggedCollectionID)
? draggedCollectionID
: draggedCollectionID.split("/").slice(0, -1).join("/")
const isMoveToSiblingCollection = this.isAlreadyInRoot(draggedCollectionID)
? this.isAlreadyInRoot(
destinationCollectionID === null
? // Move to root
this.restCollectionState.value.state.length.toString()
: destinationCollectionID
)
: !!destinationCollectionID?.startsWith(draggedParentCollectionID)
const draggedCollectionIndexPos = this.pathToLastIndex(draggedCollectionID)
let resolvedDestinationCollectionID = ""
if (destinationCollectionID === null) {
// destinationCollectionID` being `null` indicates moving to root
// New ID will be the length of the root nodes at this point (before the store update)
resolvedDestinationCollectionID =
this.restCollectionState.value.state.length.toString()
} else {
// Move to an inner-level collection
const destinationCollectionIndexPos = this.pathToLastIndex(
destinationCollectionID
)
// The count of child collections within the destination collection will be the new index position
// Appended to the `resolvedDestinationCollectionID`
const resolvedDestinationCollectionIndexPos = getFoldersByPath(
this.restCollectionState.value.state,
destinationCollectionID
).length
// Indicates a move from a collection at the top to a sibling collection below it
if (
isMoveToSiblingCollection &&
destinationCollectionIndexPos > draggedCollectionIndexPos
) {
const draggedCollectionIDStrLength =
draggedCollectionID.split("/").length
// Obtain a subset of the destination collection ID till the dragged collection ID string length
// Only update the index position at the level of the dragged collection
// This ensures moves to deeply any nested collections are accounted
const destinationCollectionIDSubset = destinationCollectionID
.split("/")
.slice(0, draggedCollectionIDStrLength)
.join("/")
// Reduce `1` from the index position to account for the dragged collection
// Dragged collection doesn't exist anymore at the previous level
const collectionIDSubsetIndexPos = Number(
this.pathToLastIndex(destinationCollectionIDSubset) - 1
)
// Replace the destination collection ID with `1` reduced from the index position
const replacedDestinationCollectionID = destinationCollectionID.replace(
destinationCollectionIDSubset,
`${destinationCollectionIDSubset
.split("/")
.slice(0, -1)
.join("/")}/${collectionIDSubsetIndexPos}`
)
const resolvedDestinationCollectionIDPrefix = this.isAlreadyInRoot(
draggedCollectionID
)
? collectionIDSubsetIndexPos
: replacedDestinationCollectionID
resolvedDestinationCollectionID = `${resolvedDestinationCollectionIDPrefix}/${resolvedDestinationCollectionIndexPos}`
} else {
resolvedDestinationCollectionID = `${destinationCollectionID}/${resolvedDestinationCollectionIndexPos}`
}
}
const draggedParentCollectionSize = this.isAlreadyInRoot(
draggedCollectionID
)
? this.restCollectionState.value.state.length
: getFoldersByPath(
this.restCollectionState.value.state,
draggedParentCollectionID
).length
const affectedParentCollectionIDRange =
draggedParentCollectionSize - 1 - draggedCollectionIndexPos
moveRESTFolder( moveRESTFolder(
collectionHandleRef.value.data.collectionID, collectionHandleRef.value.data.collectionID,
destinationCollectionID destinationCollectionID
) )
this.issuedHandles.forEach((handle) => {
if (handle.value.type === "invalid") {
return
}
if (!("requestID" in handle.value.data)) {
return
}
const { collectionID, requestID } = handle.value.data
const reqIndexPos = requestID.slice(-1)[0]
if (requestID.startsWith(draggedCollectionID)) {
const newCollectionID = collectionID.replace(
draggedCollectionID,
resolvedDestinationCollectionID
)
handle.value.data.collectionID = newCollectionID
handle.value.data.requestID = `${newCollectionID}/${reqIndexPos}`
}
})
Array.from({ length: affectedParentCollectionIDRange }).forEach(
(_, idx) => {
// Adding `1` to dragged collection index position to get the affected collection index position
const affectedCollectionIndexPos = draggedCollectionIndexPos + idx + 1
const affectedCollectionID = `${draggedParentCollectionID}/${affectedCollectionIndexPos}`
// The index position will be reduced by `1` for the affected collections
const newAffectedCollectionID = `${draggedParentCollectionID}/${
affectedCollectionIndexPos - 1
}`
// For each affected collection, we'll have to iterate over the `issuedHandles` to account for nested collections
this.issuedHandles.forEach((handle) => {
if (
handle.value.type === "invalid" ||
!("requestID" in handle.value.data)
) {
return
}
if (handle.value.data.requestID.startsWith(affectedCollectionID)) {
const { collectionID, requestID } = handle.value.data
handle.value.data.collectionID = collectionID.replace(
affectedCollectionID,
newAffectedCollectionID
)
handle.value.data.requestID = requestID.replace(
affectedCollectionID,
newAffectedCollectionID
)
}
})
}
)
return Promise.resolve(E.right(undefined)) return Promise.resolve(E.right(undefined))
} }