refactor: integrate provider API methods for collection move/reorder

This commit is contained in:
jamesgeorge007
2024-02-20 22:16:03 +05:30
parent 0a0f441da1
commit fe01322bf7
9 changed files with 609 additions and 304 deletions

View File

@@ -534,6 +534,7 @@ const saveRequest = async () => {
if (E.isLeft(requestHandleResult)) { if (E.isLeft(requestHandleResult)) {
// INVALID_COLLECTION_HANDLE | INVALID_REQUEST_ID | REQUEST_NOT_FOUND // INVALID_COLLECTION_HANDLE | INVALID_REQUEST_ID | REQUEST_NOT_FOUND
showSaveRequestModal.value = true
return return
} }

View File

@@ -22,8 +22,8 @@
></div> ></div>
<div <div
class="z-[3] group pointer-events-auto relative flex cursor-pointer items-stretch" class="z-[3] group pointer-events-auto relative flex cursor-pointer items-stretch"
:draggable="true"
@dragstart="dragStart" @dragstart="dragStart"
@drop="handleDrop($event)"
@dragover="handleDragOver($event)" @dragover="handleDragOver($event)"
@dragleave="resetDragState" @dragleave="resetDragState"
@dragend=" @dragend="
@@ -32,7 +32,8 @@
dropItemID = '' dropItemID = ''
} }
" "
@contextmenu.prevent="options?.tippy.show()" @drop="handleDrop($event)"
@contextmenu.prevent="options?.tippy?.show()"
> >
<div <div
class="flex min-w-0 flex-1 items-center justify-center" class="flex min-w-0 flex-1 items-center justify-center"
@@ -179,12 +180,12 @@
</div> </div>
</div> </div>
<div <div
v-if="isLastItem" v-if="collectionView.isLastItem"
class="w-full transition" class="w-full transition"
:class="[ :class="[
{ {
'bg-accentDark': isLastItemReorderable, 'bg-accentDark': isLastItemReorderable,
'h-1 ': isLastItem, 'h-1 ': collectionView.isLastItem,
}, },
]" ]"
@drop="updateLastItemOrder" @drop="updateLastItemOrder"
@@ -224,7 +225,6 @@ const props = defineProps<{
collectionView: RESTCollectionViewCollection collectionView: RESTCollectionViewCollection
isOpen: boolean isOpen: boolean
isSelected?: boolean | null isSelected?: boolean | null
isLastItem?: boolean
}>() }>()
const emit = defineEmits<{ const emit = defineEmits<{
@@ -349,8 +349,10 @@ const editCollection = () => {
const dragStart = ({ dataTransfer }: DragEvent) => { const dragStart = ({ dataTransfer }: DragEvent) => {
if (dataTransfer) { if (dataTransfer) {
emit("drag-event", dataTransfer) emit("drag-event", dataTransfer)
dropItemID.value = dataTransfer.getData("collectionIndex") dropItemID.value = dataTransfer.getData("collectionIndex")
dragging.value = !dragging.value dragging.value = !dragging.value
changeCurrentReorderStatus({ changeCurrentReorderStatus({
type: "collection", type: "collection",
id: props.collectionView.collectionID, id: props.collectionView.collectionID,
@@ -376,7 +378,7 @@ const handleDragOver = (e: DragEvent) => {
notSameDestination.value && notSameDestination.value &&
!isRequestDragging.value && !isRequestDragging.value &&
isSameParent.value && isSameParent.value &&
props.isLastItem props.collectionView.isLastItem
) { ) {
orderingLastItem.value = true orderingLastItem.value = true
dragging.value = false dragging.value = false

View File

@@ -1,8 +1,27 @@
<template> <template>
<div class="flex flex-col"> <div class="flex flex-col">
<div
class="h-1 w-full transition"
:class="[
{
'bg-accentDark': isReorderable,
},
]"
@drop="updateRequestOrder"
@dragover.prevent="ordering = true"
@dragleave="resetDragState"
@dragend="resetDragState"
></div>
<div <div
class="group flex items-stretch" class="group flex items-stretch"
@contextmenu.prevent="options?.tippy.show()" :draggable="true"
@dragstart="dragStart"
@dragover="handleDragOver($event)"
@dragleave="resetDragState"
@dragend="resetDragState"
@drop="handleDrop"
@contextmenu.prevent="options?.tippy?.show()"
> >
<div <div
class="pointer-events-auto flex min-w-0 flex-1 cursor-pointer items-center justify-center" class="pointer-events-auto flex min-w-0 flex-1 cursor-pointer items-center justify-center"
@@ -45,6 +64,7 @@
</span> </span>
</span> </span>
</div> </div>
<div class="flex"> <div class="flex">
<HoppButtonSecondary <HoppButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
@@ -59,7 +79,7 @@
interactive interactive
trigger="click" trigger="click"
theme="popover" theme="popover"
:on-shown="() => tippyActions!.focus()" :on-shown="() => tippyActions.focus()"
> >
<HoppButtonSecondary <HoppButtonSecondary
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
@@ -134,6 +154,20 @@
</span> </span>
</div> </div>
</div> </div>
<div
class="w-full transition"
:class="[
{
'bg-accentDark': isLastItemReorderable,
'h-1 ': props.requestView.isLastItem,
},
]"
@drop="handleDrop"
@dragover.prevent="orderingLastItem = true"
@dragleave="resetDragState"
@dragend="resetDragState"
></div>
</div> </div>
</template> </template>
@@ -142,8 +176,13 @@ import { useI18n } from "@composables/i18n"
import { HoppRESTRequest } from "@hoppscotch/data" import { HoppRESTRequest } from "@hoppscotch/data"
import { computed, ref } from "vue" import { computed, ref } from "vue"
import { TippyComponent } from "vue-tippy" import { TippyComponent } from "vue-tippy"
import { useReadonlyStream } from "~/composables/stream"
import { getMethodLabelColorClassOf } from "~/helpers/rest/labelColoring" import { getMethodLabelColorClassOf } from "~/helpers/rest/labelColoring"
import {
currentReorderingStatus$,
changeCurrentReorderStatus,
} from "~/newstore/reordering"
import { RESTCollectionViewRequest } from "~/services/new-workspace/view" import { RESTCollectionViewRequest } from "~/services/new-workspace/view"
import IconCheckCircle from "~icons/lucide/check-circle" import IconCheckCircle from "~icons/lucide/check-circle"
@@ -156,6 +195,12 @@ import IconTrash2 from "~icons/lucide/trash-2"
const t = useI18n() const t = useI18n()
const currentReorderingStatus = useReadonlyStream(currentReorderingStatus$, {
type: "collection",
id: "",
parentID: "",
})
const props = defineProps<{ const props = defineProps<{
isActive: boolean isActive: boolean
requestView: RESTCollectionViewRequest requestView: RESTCollectionViewRequest
@@ -174,6 +219,9 @@ const emit = defineEmits<{
(event: "remove-request", requestIndexPath: string): void (event: "remove-request", requestIndexPath: string): void
(event: "select-request", requestIndexPath: string): void (event: "select-request", requestIndexPath: string): void
(event: "share-request", request: HoppRESTRequest): void (event: "share-request", request: HoppRESTRequest): void
(event: "drag-request", payload: DataTransfer): void
(event: "update-request-order", payload: DataTransfer): void
(event: "update-last-request-order", payload: DataTransfer): void
}>() }>()
const tippyActions = ref<TippyComponent | null>(null) const tippyActions = ref<TippyComponent | null>(null)
@@ -183,9 +231,105 @@ const options = ref<TippyComponent | null>(null)
const duplicate = ref<HTMLButtonElement | null>(null) const duplicate = ref<HTMLButtonElement | null>(null)
const shareAction = ref<HTMLButtonElement | null>(null) const shareAction = ref<HTMLButtonElement | null>(null)
const dragging = ref(false)
const ordering = ref(false)
const orderingLastItem = ref(false)
const isCollectionDragging = computed(() => {
return currentReorderingStatus.value.type === "collection"
})
const isLastItemReorderable = computed(() => {
return (
orderingLastItem.value && isSameParent.value && !isCollectionDragging.value
)
})
const isReorderable = computed(() => {
return (
ordering.value &&
!isCollectionDragging.value &&
isSameParent.value &&
!isSameRequest.value
)
})
const isSameParent = computed(() => {
return (
currentReorderingStatus.value.parentID ===
props.requestView.parentCollectionID
)
})
const isSameRequest = computed(() => {
return currentReorderingStatus.value.id === props.requestView.requestID
})
const requestLabelColor = computed(() => const requestLabelColor = computed(() =>
getMethodLabelColorClassOf(props.requestView.request) getMethodLabelColorClassOf(props.requestView.request)
) )
const dragStart = ({ dataTransfer }: DragEvent) => {
if (dataTransfer) {
emit("drag-request", dataTransfer)
dragging.value = !dragging.value
changeCurrentReorderStatus({
type: "request",
id: props.requestView.requestID,
parentID: props.requestView.parentCollectionID,
})
}
}
const handleDrop = (e: DragEvent) => {
if (ordering.value) {
updateRequestOrder(e)
} else if (orderingLastItem.value) {
updateLastItemOrder(e)
} else {
updateRequestOrder(e)
}
}
// Trigger the re-ordering event when a request is dragged over another request's top section
const handleDragOver = (e: DragEvent) => {
dragging.value = true
if (e.offsetY < 10) {
ordering.value = true
dragging.value = false
orderingLastItem.value = false
} else if (e.offsetY > 18) {
orderingLastItem.value = true
dragging.value = false
ordering.value = false
} else {
ordering.value = false
orderingLastItem.value = false
}
}
const resetDragState = () => {
dragging.value = false
ordering.value = false
orderingLastItem.value = false
}
const selectRequest = () => emit("select-request", props.requestView.requestID) const selectRequest = () => emit("select-request", props.requestView.requestID)
const updateRequestOrder = (e: DragEvent) => {
if (e.dataTransfer) {
e.stopPropagation()
resetDragState()
emit("update-request-order", e.dataTransfer)
}
}
const updateLastItemOrder = (e: DragEvent) => {
if (e.dataTransfer) {
e.stopPropagation()
resetDragState()
emit("update-last-request-order", e.dataTransfer)
}
}
</script> </script>

View File

@@ -12,9 +12,10 @@
> >
<div <div
class="sticky z-10 flex flex-shrink-0 flex-col overflow-x-auto border-b border-dividerLight bg-primary" class="sticky z-10 flex flex-shrink-0 flex-col overflow-x-auto border-b border-dividerLight bg-primary"
:style="{ :class="{ 'rounded-t': saveRequest }"
top: 0, :style="
}" saveRequest ? 'top: calc(-1 * var(--line-height-body))' : 'top: 0'
"
> >
<WorkspaceCurrent :section="t('tab.collections')" /> <WorkspaceCurrent :section="t('tab.collections')" />
<input <input
@@ -25,6 +26,7 @@
:placeholder="t('action.search')" :placeholder="t('action.search')"
/> />
</div> </div>
<div class="flex flex-1 flex-col"> <div class="flex flex-1 flex-col">
<div <div
class="sticky z-10 flex flex-1 justify-between border-b border-dividerLight bg-primary" class="sticky z-10 flex flex-1 justify-between border-b border-dividerLight bg-primary"
@@ -66,7 +68,6 @@
<NewCollectionsRestCollection <NewCollectionsRestCollection
v-if="node.data.type === 'collection'" v-if="node.data.type === 'collection'"
:collection-view="node.data.value" :collection-view="node.data.value"
:is-last-item="node.data.value.isLastItem"
:is-open="isOpen" :is-open="isOpen"
:is-selected=" :is-selected="
isSelected( isSelected(
@@ -126,7 +127,6 @@
<NewCollectionsRestRequest <NewCollectionsRestRequest
v-else-if="node.data.type === 'request'" v-else-if="node.data.type === 'request'"
:is-active="isActiveRequest(node.data.value)" :is-active="isActiveRequest(node.data.value)"
:is-last-item="node.data.value.isLastItem"
:is-selected=" :is-selected="
isSelected(getRequestIndexPathArgs(node.data.value.requestID)) isSelected(getRequestIndexPathArgs(node.data.value.requestID))
" "
@@ -168,12 +168,14 @@
</HoppSmartTree> </HoppSmartTree>
</div> </div>
<!-- <div <div
class="py-15 hidden flex-1 flex-col items-center justify-center bg-primaryDark px-4 text-secondaryLight" class="py-15 hidden flex-1 flex-col items-center justify-center bg-primaryDark px-4 text-secondaryLight"
:class="{ :class="{
'!flex': draggingToRoot && currentReorderingStatus.type !== 'request', '!flex': draggingToRoot && currentReorderingStatus.type !== 'request',
}" }"
> --> >
<icon-lucide-list-end class="svg-icons !h-8 !w-8" />
</div>
<CollectionsAdd <CollectionsAdd
:show="showModalAdd" :show="showModalAdd"
@@ -258,20 +260,22 @@ import { WorkspaceRESTCollectionTreeAdapter } from "~/helpers/adapters/Workspace
import { TeamCollection } from "~/helpers/backend/graphql" import { TeamCollection } from "~/helpers/backend/graphql"
import { import {
getFoldersByPath, getFoldersByPath,
resolveSaveContextOnCollectionReorder,
updateInheritedPropertiesForAffectedRequests, updateInheritedPropertiesForAffectedRequests,
updateSaveContextForAffectedRequests,
} from "~/helpers/collection/collection" } from "~/helpers/collection/collection"
import {
getRequestsByPath,
resolveSaveContextOnRequestReorder,
} from "~/helpers/collection/request"
import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties" import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties"
import { Picked } from "~/helpers/types/HoppPicked" import { Picked } from "~/helpers/types/HoppPicked"
import { import {
cascadeParentCollectionForHeaderAuth,
moveRESTFolder,
moveRESTRequest,
navigateToFolderWithIndexPath, navigateToFolderWithIndexPath,
restCollections$, restCollections$,
saveRESTRequestAs, saveRESTRequestAs,
updateRESTCollectionOrder,
updateRESTRequestOrder,
} from "~/newstore/collections" } from "~/newstore/collections"
import { currentReorderingStatus$ } from "~/newstore/reordering"
import { platform } from "~/platform" import { platform } from "~/platform"
import { NewWorkspaceService } from "~/services/new-workspace" import { NewWorkspaceService } from "~/services/new-workspace"
import { HandleRef } from "~/services/new-workspace/handle" import { HandleRef } from "~/services/new-workspace/handle"
@@ -281,7 +285,6 @@ import { RESTTabService } from "~/services/tab/rest"
import IconImport from "~icons/lucide/folder-down" import IconImport from "~icons/lucide/folder-down"
import IconHelpCircle from "~icons/lucide/help-circle" import IconHelpCircle from "~icons/lucide/help-circle"
import IconPlus from "~icons/lucide/plus" import IconPlus from "~icons/lucide/plus"
import { currentReorderingStatus$ } from "~/newstore/reordering"
const t = useI18n() const t = useI18n()
const toast = useToast() const toast = useToast()
@@ -296,40 +299,7 @@ const props = defineProps<{
const emit = defineEmits<{ const emit = defineEmits<{
(e: "display-modal-add"): void (e: "display-modal-add"): void
(e: "display-modal-import-export"): void (e: "display-modal-import-export"): void
(
event: "drop-collection",
payload: {
collectionIndexDragged: string
destinationCollectionIndex: string
}
): void
(
event: "drop-request",
payload: {
parentCollectionIndexPath: string
requestIndex: string
destinationCollectionIndex: string
}
): void
(event: "select", payload: Picked | null): void (event: "select", payload: Picked | null): void
(
event: "update-collection-order",
payload: {
dragedCollectionIndex: string
destinationCollection: {
destinationCollectionIndex: string | null
destinationCollectionParentIndex: string | null
}
}
): void
(
event: "update-request-order",
payload: {
dragedRequestIndex: string
destinationRequestIndex: string | null
destinationCollectionIndex: string
}
): void
}>() }>()
const workspaceService = useService(NewWorkspaceService) const workspaceService = useService(NewWorkspaceService)
@@ -1301,7 +1271,7 @@ const dragRequest = (
dataTransfer.setData("requestIndex", requestIndex) dataTransfer.setData("requestIndex", requestIndex)
} }
const dropEvent = ( const dropEvent = async (
dataTransfer: DataTransfer, dataTransfer: DataTransfer,
destinationCollectionIndex: string destinationCollectionIndex: string
) => { ) => {
@@ -1309,22 +1279,17 @@ const dropEvent = (
"parentCollectionIndexPath" "parentCollectionIndexPath"
) )
const requestIndex = dataTransfer.getData("requestIndex") const requestIndex = dataTransfer.getData("requestIndex")
const collectionIndexDragged = dataTransfer.getData("collectionIndex") const draggedCollectionIndex = dataTransfer.getData("collectionIndex")
if (parentCollectionIndexPath && requestIndex) { if (parentCollectionIndexPath && requestIndex) {
// emit("drop-request", { await dropRequest({
// parentCollectionIndexPath,
// requestIndex,
// destinationCollectionIndex,
// })
dropRequest({
parentCollectionIndexPath, parentCollectionIndexPath,
requestIndex, requestIndex,
destinationCollectionIndex, destinationCollectionIndex,
}) })
} else { } else {
dropCollection({ await dropCollection({
collectionIndexDragged, draggedCollectionIndex,
destinationCollectionIndex, destinationCollectionIndex,
}) })
} }
@@ -1335,23 +1300,115 @@ const dropEvent = (
* to the root * to the root
* @param payload - object containing the collection index dragged * @param payload - object containing the collection index dragged
*/ */
const dropToRoot = ({ dataTransfer }: DragEvent) => { const dropToRoot = async ({ dataTransfer }: DragEvent) => {
if (dataTransfer) { if (!dataTransfer) {
const collectionIndexDragged = dataTransfer.getData("collectionIndex") return
if (!collectionIndexDragged) return
// check if the collection is already in the root
if (isAlreadyInRoot(collectionIndexDragged)) {
toast.error(`${t("collection.invalid_root_move")}`)
} else {
moveRESTFolder(collectionIndexDragged, null)
toast.success(`${t("collection.moved")}`)
}
draggingToRoot.value = false
} }
const draggedCollectionIndex = dataTransfer.getData("collectionIndex")
if (!draggedCollectionIndex) {
return
}
// check if the collection is already in the root
if (isAlreadyInRoot(draggedCollectionIndex)) {
toast.error(`${t("collection.invalid_root_move")}`)
draggingToRoot.value = false
return
}
const draggedCollectionHandleResult =
await workspaceService.getCollectionHandle(
props.workspaceHandle,
draggedCollectionIndex
)
if (E.isLeft(draggedCollectionHandleResult)) {
// INVALID_WORKSPACE_HANDLE | INVALID_COLLECTION_ID | INVALID_PATH
return
}
const draggedCollectionHandle = draggedCollectionHandleResult.right
if (draggedCollectionHandle.value.type === "invalid") {
// WORKSPACE_INVALIDATED
return
}
const result = await workspaceService.moveRESTCollection(
draggedCollectionHandle,
null
)
if (E.isLeft(result)) {
// INVALID_COLLECTION_HANDLE
return
}
const destinationRootCollectionIndex = (
restCollectionState.value.length - 1
).toString()
updateSaveContextForAffectedRequests(
draggedCollectionIndex,
destinationRootCollectionIndex
)
const destinationRootCollectionHandleResult =
await workspaceService.getCollectionHandle(
props.workspaceHandle,
destinationRootCollectionIndex
)
if (E.isLeft(destinationRootCollectionHandleResult)) {
// INVALID_WORKSPACE_HANDLE | INVALID_COLLECTION_ID | INVALID_PATH
return
}
const destinationRootCollectionHandle =
destinationRootCollectionHandleResult.right
if (destinationRootCollectionHandle.value.type === "invalid") {
// WORKSPACE_INVALIDATED
return
}
const cascadingAuthHeadersHandleResult =
await workspaceService.getRESTCollectionLevelAuthHeadersView(
destinationRootCollectionHandle
)
if (E.isLeft(cascadingAuthHeadersHandleResult)) {
// INVALID_COLLECTION_HANDLE
return
}
const cascadingAuthHeadersHandle = cascadingAuthHeadersHandleResult.right
if (cascadingAuthHeadersHandle.value.type === "invalid") {
// COLLECTION_INVALIDATED
return
}
const { auth, headers } = cascadingAuthHeadersHandle.value.data
const inheritedProperty = {
auth,
headers,
}
updateInheritedPropertiesForAffectedRequests(
destinationRootCollectionIndex,
inheritedProperty,
"rest"
)
toast.success(`${t("collection.moved")}`)
draggingToRoot.value = false
} }
const dropRequest = (payload: { const dropRequest = async (payload: {
parentCollectionIndexPath?: string | undefined parentCollectionIndexPath?: string | undefined
requestIndex: string requestIndex: string
destinationCollectionIndex: string destinationCollectionIndex: string
@@ -1366,65 +1423,137 @@ const dropRequest = (payload: {
!requestIndex || !requestIndex ||
!destinationCollectionIndex || !destinationCollectionIndex ||
!parentCollectionIndexPath !parentCollectionIndexPath
) ) {
return return
}
// const { auth, headers } = cascadeParentCollectionForHeaderAuth( const requestHandleResult = await workspaceService.getRequestHandle(
// destinationCollectionIndex, props.workspaceHandle,
// "rest" requestIndex
// ) )
// const possibleTab = tabs.getTabRefWithSaveContext({ if (E.isLeft(requestHandleResult)) {
// originLocation: "user-collection", // INVALID_COLLECTION_HANDLE | INVALID_REQUEST_ID | REQUEST_NOT_FOUND
// folderPath, return
// requestIndex: pathToLastIndex(requestIndex), }
// })
// If there is a tab attached to this request, change save its save context const requestHandle = requestHandleResult.right
// if (possibleTab) {
// possibleTab.value.document.saveContext = {
// originLocation: "user-collection",
// folderPath: destinationCollectionIndex,
// requestIndex: getRequestsByPath(
// restCollectionState.value,
// destinationCollectionIndex
// ).length,
// }
// possibleTab.value.document.inheritedProperties = { if (requestHandle.value.type === "invalid") {
// auth, // COLLECTION_INVALIDATED
// headers, return
// } }
// }
// When it's drop it's basically getting deleted from last folder. reordering last folder accordingly const result = await workspaceService.moveRESTRequest(
// resolveSaveContextOnRequestReorder({ requestHandle,
// lastIndex: pathToLastIndex(requestIndex),
// newIndex: -1, // being deleted from last folder
// folderPath,
// length: getRequestsByPath(myCollections.value, folderPath).length,
// })
moveRESTRequest(
parentCollectionIndexPath,
pathToLastIndex(requestIndex),
destinationCollectionIndex destinationCollectionIndex
) )
if (E.isLeft(result)) {
// INVALID_REQUEST_HANDLE
return
}
const collectionHandleResult = await workspaceService.getCollectionHandle(
props.workspaceHandle,
destinationCollectionIndex
)
if (E.isLeft(collectionHandleResult)) {
// INVALID_WORKSPACE_HANDLE | INVALID_COLLECTION_ID | INVALID_PATH
return
}
const collectionHandle = collectionHandleResult.right
if (collectionHandle.value.type === "invalid") {
// WORKSPACE_INVALIDATED
return
}
const cascadingAuthHeadersHandleResult =
await workspaceService.getRESTCollectionLevelAuthHeadersView(
collectionHandle
)
if (E.isLeft(cascadingAuthHeadersHandleResult)) {
// INVALID_COLLECTION_HANDLE
return
}
const cascadingAuthHeadersHandle = cascadingAuthHeadersHandleResult.right
if (cascadingAuthHeadersHandle.value.type === "invalid") {
// COLLECTION_INVALIDATED
return
}
const { auth, headers } = cascadingAuthHeadersHandle.value.data
const { collectionID, providerID, requestID, workspaceID } =
requestHandle.value.data
const possibleTab = tabs.getTabRefWithSaveContext({
originLocation: "workspace-user-collection",
workspaceID,
providerID,
collectionID,
requestID,
})
// If there is a tab attached to this request, update its save context
if (possibleTab) {
const newCollectionID = destinationCollectionIndex
const newRequestID = `${destinationCollectionIndex}/${(
getRequestsByPath(restCollectionState.value, destinationCollectionIndex)
.length - 1
).toString()}`
possibleTab.value.document.saveContext = {
originLocation: "workspace-user-collection",
workspaceID,
providerID,
collectionID: newCollectionID,
requestID: newRequestID,
}
possibleTab.value.document.inheritedProperties = {
auth,
headers,
}
}
// When it's drop it's basically getting deleted from last folder. reordering last folder accordingly
resolveSaveContextOnRequestReorder({
lastIndex: pathToLastIndex(requestIndex),
newIndex: -1, // being deleted from last folder
folderPath: parentCollectionIndexPath,
length:
getRequestsByPath(restCollectionState.value, parentCollectionIndexPath)
.length - 1,
})
toast.success(`${t("request.moved")}`) toast.success(`${t("request.moved")}`)
// draggingToRoot.value = false draggingToRoot.value = false
} }
const dropCollection = (payload: { const dropCollection = async (payload: {
collectionIndexDragged: string draggedCollectionIndex: string
destinationCollectionIndex: string destinationCollectionIndex: string
}) => { }) => {
const { collectionIndexDragged, destinationCollectionIndex } = payload const { draggedCollectionIndex, destinationCollectionIndex } = payload
if (!collectionIndexDragged || !destinationCollectionIndex) return
if (collectionIndexDragged === destinationCollectionIndex) return if (
!draggedCollectionIndex ||
!destinationCollectionIndex ||
draggedCollectionIndex === destinationCollectionIndex
) {
return
}
if ( if (
checkIfCollectionIsAParentOfTheChildren( checkIfCollectionIsAParentOfTheChildren(
collectionIndexDragged, draggedCollectionIndex,
destinationCollectionIndex destinationCollectionIndex
) )
) { ) {
@@ -1434,38 +1563,96 @@ const dropCollection = (payload: {
//check if the collection is being moved to its own parent //check if the collection is being moved to its own parent
if ( if (
isMoveToSameLocation(collectionIndexDragged, destinationCollectionIndex) isMoveToSameLocation(draggedCollectionIndex, destinationCollectionIndex)
) { ) {
return return
} }
const parentFolder = collectionIndexDragged.split("/").slice(0, -1).join("/") // remove last folder to get parent folder const parentFolder = draggedCollectionIndex.split("/").slice(0, -1).join("/") // remove last folder to get parent folder
const totalFoldersOfDestinationCollection = const totalFoldersOfDestinationCollection =
getFoldersByPath(restCollectionState.value, destinationCollectionIndex) getFoldersByPath(restCollectionState.value, destinationCollectionIndex)
.length - (parentFolder === destinationCollectionIndex ? 1 : 0) .length - (parentFolder === destinationCollectionIndex ? 1 : 0)
moveRESTFolder(collectionIndexDragged, destinationCollectionIndex) const draggedCollectionHandleResult =
await workspaceService.getCollectionHandle(
props.workspaceHandle,
draggedCollectionIndex
)
// resolveSaveContextOnCollectionReorder( if (E.isLeft(draggedCollectionHandleResult)) {
// { // INVALID_WORKSPACE_HANDLE | INVALID_COLLECTION_ID | INVALID_PATH
// lastIndex: pathToLastIndex(collectionIndexDragged), return
// newIndex: -1, }
// folderPath: parentFolder,
// length: getFoldersByPath(restCollectionState.value, parentFolder).length,
// },
// "drop"
// )
// updateSaveContextForAffectedRequests( const draggedCollectionHandle = draggedCollectionHandleResult.right
// collectionIndexDragged,
// `${destinationCollectionIndex}/${totalFoldersOfDestinationCollection}`
// )
const { auth, headers } = cascadeParentCollectionForHeaderAuth( if (draggedCollectionHandle.value.type === "invalid") {
`${destinationCollectionIndex}/${totalFoldersOfDestinationCollection}`, // WORKSPACE_INVALIDATED
"rest" return
}
const result = await workspaceService.moveRESTCollection(
draggedCollectionHandle,
destinationCollectionIndex
) )
if (E.isLeft(result)) {
// INVALID_COLLECTION_HANDLE
return
}
resolveSaveContextOnCollectionReorder(
{
lastIndex: pathToLastIndex(draggedCollectionIndex),
newIndex: -1,
folderPath: parentFolder,
length: getFoldersByPath(restCollectionState.value, parentFolder).length,
},
"drop"
)
updateSaveContextForAffectedRequests(
draggedCollectionIndex,
`${destinationCollectionIndex}/${totalFoldersOfDestinationCollection}`
)
const destinationCollectionHandleResult =
await workspaceService.getCollectionHandle(
props.workspaceHandle,
destinationCollectionIndex
)
if (E.isLeft(destinationCollectionHandleResult)) {
// INVALID_WORKSPACE_HANDLE | INVALID_COLLECTION_ID | INVALID_PATH
return
}
const destinationCollectionHandle = destinationCollectionHandleResult.right
if (destinationCollectionHandle.value.type === "invalid") {
// WORKSPACE_INVALIDATED
return
}
const cascadingAuthHeadersHandleResult =
await workspaceService.getRESTCollectionLevelAuthHeadersView(
destinationCollectionHandle
)
if (E.isLeft(cascadingAuthHeadersHandleResult)) {
// INVALID_COLLECTION_HANDLE
return
}
const cascadingAuthHeadersHandle = cascadingAuthHeadersHandleResult.right
if (cascadingAuthHeadersHandle.value.type === "invalid") {
// COLLECTION_INVALIDATED
return
}
const { auth, headers } = cascadingAuthHeadersHandle.value.data
const inheritedProperty = { const inheritedProperty = {
auth, auth,
headers, headers,
@@ -1477,50 +1664,75 @@ const dropCollection = (payload: {
"rest" "rest"
) )
// draggingToRoot.value = false draggingToRoot.value = false
toast.success(`${t("collection.moved")}`) toast.success(`${t("collection.moved")}`)
} }
const updateRequestOrder = ( const updateRequestOrder = async (
dataTransfer: DataTransfer, dataTransfer: DataTransfer,
{ {
parentCollectionIndexPath, parentCollectionIndexPath,
requestIndex, requestIndex,
}: { parentCollectionIndexPath: string | null; requestIndex: string | null } }: { parentCollectionIndexPath: string | null; requestIndex: string | null }
) => { ) => {
if (!parentCollectionIndexPath) return if (!parentCollectionIndexPath) {
const dragedRequestIndex = dataTransfer.getData("requestIndex") return
}
const draggedRequestIndex = dataTransfer.getData("requestIndex")
const destinationRequestIndex = requestIndex const destinationRequestIndex = requestIndex
const destinationCollectionIndex = parentCollectionIndexPath const destinationCollectionIndex = parentCollectionIndexPath
if ( if (
!dragedRequestIndex || !draggedRequestIndex ||
!destinationCollectionIndex || !destinationCollectionIndex ||
dragedRequestIndex === destinationRequestIndex draggedRequestIndex === destinationRequestIndex
) { ) {
return return
} }
if ( if (
!isSameSameParent( !isSameSameParent(
dragedRequestIndex, draggedRequestIndex,
destinationRequestIndex, destinationRequestIndex,
destinationCollectionIndex destinationCollectionIndex
) )
) { ) {
toast.error(`${t("collection.different_parent")}`) return toast.error(`${t("collection.different_parent")}`)
} else {
updateRESTRequestOrder(
pathToLastIndex(dragedRequestIndex),
destinationRequestIndex ? pathToLastIndex(destinationRequestIndex) : null,
destinationCollectionIndex
)
toast.success(`${t("request.order_changed")}`)
} }
const requestHandleResult = await workspaceService.getRequestHandle(
props.workspaceHandle,
draggedRequestIndex
)
if (E.isLeft(requestHandleResult)) {
// INVALID_COLLECTION_HANDLE | INVALID_REQUEST_ID | REQUEST_NOT_FOUND
return
}
const requestHandle = requestHandleResult.right
if (requestHandle.value.type === "invalid") {
// COLLECTION_INVALIDATED
return
}
const result = await workspaceService.reorderRESTRequest(
requestHandle,
destinationCollectionIndex,
destinationRequestIndex
)
if (E.isLeft(result)) {
// INVALID_REQUEST_HANDLE
return
}
toast.success(`${t("request.order_changed")}`)
} }
const updateCollectionOrder = ( const updateCollectionOrder = async (
dataTransfer: DataTransfer, dataTransfer: DataTransfer,
destinationCollection: { destinationCollection: {
destinationCollectionIndex: string | null destinationCollectionIndex: string | null
@@ -1546,21 +1758,43 @@ const updateCollectionOrder = (
destinationCollectionParentIndex destinationCollectionParentIndex
) )
) { ) {
toast.error(`${t("collection.different_parent")}`) return toast.error(`${t("collection.different_parent")}`)
} else {
updateRESTCollectionOrder(
draggedCollectionIndex,
destinationCollectionIndex
)
// resolveSaveContextOnCollectionReorder({
// lastIndex: pathToLastIndex(draggedCollectionIndex),
// newIndex: pathToLastIndex(
// destinationCollectionIndex ? destinationCollectionIndex : ""
// ),
// folderPath: draggedCollectionIndex.split("/").slice(0, -1).join("/"),
// })
toast.success(`${t("collection.order_changed")}`)
} }
const collectionHandleResult = await workspaceService.getCollectionHandle(
props.workspaceHandle,
draggedCollectionIndex
)
if (E.isLeft(collectionHandleResult)) {
// INVALID_WORKSPACE_HANDLE | INVALID_COLLECTION_ID | INVALID_PATH
return
}
const collectionHandle = collectionHandleResult.right
if (collectionHandle.value.type === "invalid") {
// WORKSPACE_INVALIDATED
return
}
const result = await workspaceService.reorderRESTCollection(
collectionHandle,
destinationCollectionIndex
)
if (E.isLeft(result)) {
// INVALID_COLLECTION_HANDLE
return
}
resolveSaveContextOnCollectionReorder({
lastIndex: pathToLastIndex(draggedCollectionIndex),
newIndex: pathToLastIndex(destinationCollectionIndex ?? ""),
folderPath: draggedCollectionIndex.split("/").slice(0, -1).join("/"),
})
toast.success(`${t("collection.order_changed")}`)
} }
const shareRequest = (request: HoppRESTRequest) => { const shareRequest = (request: HoppRESTRequest) => {
@@ -1579,15 +1813,15 @@ const shareRequest = (request: HoppRESTRequest) => {
/** /**
* Used to check if the collection exist as the parent of the childrens * Used to check if the collection exist as the parent of the childrens
* @param collectionIndexDragged The index of the collection dragged * @param draggedCollectionIndex The index of the collection dragged
* @param destinationCollectionIndex The index of the destination collection * @param destinationCollectionIndex The index of the destination collection
* @returns True if the collection exist as the parent of the childrens * @returns True if the collection exist as the parent of the childrens
*/ */
const checkIfCollectionIsAParentOfTheChildren = ( const checkIfCollectionIsAParentOfTheChildren = (
collectionIndexDragged: string, draggedCollectionIndex: string,
destinationCollectionIndex: string destinationCollectionIndex: string
) => { ) => {
const collectionDraggedPath = pathToIndex(collectionIndexDragged) const collectionDraggedPath = pathToIndex(draggedCollectionIndex)
const destinationCollectionPath = pathToIndex(destinationCollectionIndex) const destinationCollectionPath = pathToIndex(destinationCollectionIndex)
if (collectionDraggedPath.length < destinationCollectionPath.length) { if (collectionDraggedPath.length < destinationCollectionPath.length) {
@@ -1701,9 +1935,9 @@ const isSameSameParent = (
draggedItemIndex.length !== 1 && draggedItemIndex.length !== 1 &&
destinationCollectionIndex !== null destinationCollectionIndex !== null
) { ) {
const dragedItemParent = draggedItemIndex.slice(0, -1) const draggedItemParent = draggedItemIndex.slice(0, -1)
return dragedItemParent.join("/") === destinationCollectionIndex return draggedItemParent.join("/") === destinationCollectionIndex
} }
if (destinationItemPath === null) return false if (destinationItemPath === null) return false
const destinationItemIndex = pathToIndex(destinationItemPath) const destinationItemIndex = pathToIndex(destinationItemPath)
@@ -1712,9 +1946,9 @@ const isSameSameParent = (
if (draggedItemIndex.length === 1 && destinationItemIndex.length === 1) { if (draggedItemIndex.length === 1 && destinationItemIndex.length === 1) {
return true return true
} else if (draggedItemIndex.length === destinationItemIndex.length) { } else if (draggedItemIndex.length === destinationItemIndex.length) {
const dragedItemParent = draggedItemIndex.slice(0, -1) const draggedItemParent = draggedItemIndex.slice(0, -1)
const destinationItemParent = destinationItemIndex.slice(0, -1) const destinationItemParent = destinationItemIndex.slice(0, -1)
if (isEqual(dragedItemParent, destinationItemParent)) { if (isEqual(draggedItemParent, destinationItemParent)) {
return true return true
} }
return false return false

View File

@@ -87,10 +87,15 @@ export function resolveSaveContextOnCollectionReorder(
tab.value.document.saveContext?.originLocation === tab.value.document.saveContext?.originLocation ===
"workspace-user-collection" "workspace-user-collection"
) { ) {
const newPath = affectedPaths.get( const newCollectionID = affectedPaths.get(
tab.value.document.saveContext?.collectionID tab.value.document.saveContext?.collectionID
)! )!
tab.value.document.saveContext.collectionID = newPath const newRequestID = `${newCollectionID}/${
tab.value.document.saveContext.requestID.split("/").slice(-1)[0]
}`
tab.value.document.saveContext.collectionID = newCollectionID
tab.value.document.saveContext.requestID = newRequestID
} }
} }
} }
@@ -134,12 +139,19 @@ export function updateSaveContextForAffectedRequests(
tab.value.document.saveContext?.originLocation === tab.value.document.saveContext?.originLocation ===
"workspace-user-collection" "workspace-user-collection"
) { ) {
tab.value.document.saveContext = { const newCollectionID =
...tab.value.document.saveContext, tab.value.document.saveContext.collectionID.replace(
collectionID: tab.value.document.saveContext.collectionID.replace(
oldFolderPath, oldFolderPath,
newFolderPath newFolderPath
), )
const newRequestID = `${newCollectionID}/${
tab.value.document.saveContext.requestID.split("/").slice(-1)[0]
}`
tab.value.document.saveContext = {
...tab.value.document.saveContext,
collectionID: newCollectionID,
requestID: newRequestID,
} }
} }
} }

View File

@@ -63,6 +63,19 @@ export function resolveSaveContextOnRequestReorder(payload: {
)! )!
tab.value.document.saveContext.requestIndex = newIndex tab.value.document.saveContext.requestIndex = newIndex
} }
if (
tab.value.document.saveContext?.originLocation ===
"workspace-user-collection"
) {
const requestID = tab.value.document.saveContext.requestID
const requestIDArray = requestID.split("/")
const requestIndex = affectedIndexes.get(
parseInt(requestIDArray[requestIDArray.length - 1])
)!
requestIDArray[requestIDArray.length - 1] = requestIndex.toString()
tab.value.document.saveContext.requestID = requestIDArray.join("/")
}
} }
} }

View File

@@ -478,7 +478,7 @@ export class NewWorkspaceService extends Service {
public async reorderRESTCollection( public async reorderRESTCollection(
collectionHandle: HandleRef<WorkspaceCollection>, collectionHandle: HandleRef<WorkspaceCollection>,
destinationCollectionIndex: string destinationCollectionIndex: string | null
): Promise< ): Promise<
E.Either<WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">, void> E.Either<WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">, void>
> { > {
@@ -508,7 +508,7 @@ export class NewWorkspaceService extends Service {
public async moveRESTCollection( public async moveRESTCollection(
collectionHandle: HandleRef<WorkspaceCollection>, collectionHandle: HandleRef<WorkspaceCollection>,
destinationCollectionIndex: string destinationCollectionIndex: string | null
): Promise< ): Promise<
E.Either<WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">, void> E.Either<WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">, void>
> { > {
@@ -538,8 +538,8 @@ export class NewWorkspaceService extends Service {
public async reorderRESTRequest( public async reorderRESTRequest(
requestHandle: HandleRef<WorkspaceRequest>, requestHandle: HandleRef<WorkspaceRequest>,
destinationRequestIndex: string, destinationCollectionIndex: string,
destinationCollectionIndex: string destinationRequestIndex: string | null
): Promise< ): Promise<
E.Either<WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">, void> E.Either<WorkspaceError<"INVALID_HANDLE" | "INVALID_PROVIDER">, void>
> { > {
@@ -557,8 +557,8 @@ export class NewWorkspaceService extends Service {
const result = await provider.reorderRESTRequest( const result = await provider.reorderRESTRequest(
requestHandle, requestHandle,
destinationRequestIndex, destinationCollectionIndex,
destinationCollectionIndex destinationRequestIndex
) )
if (E.isLeft(result)) { if (E.isLeft(result)) {

View File

@@ -83,7 +83,7 @@ export interface WorkspaceProvider {
reorderRESTCollection( reorderRESTCollection(
collectionHandle: HandleRef<WorkspaceCollection>, collectionHandle: HandleRef<WorkspaceCollection>,
destinationCollectionIndex: string destinationCollectionIndex: string | null
): Promise<E.Either<unknown, void>> ): Promise<E.Either<unknown, void>>
moveRESTCollection( moveRESTCollection(
collectionHandle: HandleRef<WorkspaceCollection>, collectionHandle: HandleRef<WorkspaceCollection>,
@@ -91,8 +91,8 @@ export interface WorkspaceProvider {
): Promise<E.Either<unknown, void>> ): Promise<E.Either<unknown, void>>
reorderRESTRequest( reorderRESTRequest(
requestHandle: HandleRef<WorkspaceRequest>, requestHandle: HandleRef<WorkspaceRequest>,
destinationRequestIndex: string, destinationCollectionIndex: string,
destinationCollectionIndex: string destinationRequestIndex: string | null
): Promise<E.Either<unknown, void>> ): Promise<E.Either<unknown, void>>
moveRESTRequest( moveRESTRequest(
requestHandle: HandleRef<WorkspaceRequest>, requestHandle: HandleRef<WorkspaceRequest>,

View File

@@ -16,7 +16,6 @@ import {
addRESTCollection, addRESTCollection,
addRESTFolder, addRESTFolder,
appendRESTCollections, appendRESTCollections,
cascadeParentCollectionForHeaderAuth,
editRESTCollection, editRESTCollection,
editRESTFolder, editRESTFolder,
editRESTRequest, editRESTRequest,
@@ -52,20 +51,10 @@ import { HoppRESTRequest } from "@hoppscotch/data"
import { merge } from "lodash-es" import { merge } from "lodash-es"
import path from "path" import path from "path"
import { HoppGQLHeader } from "~/helpers/graphql" import { HoppGQLHeader } from "~/helpers/graphql"
import { initializeDownloadFile } from "~/helpers/import-export/export"
import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties" import { HoppInheritedProperty } from "~/helpers/types/HoppInheritedProperties"
import IconUser from "~icons/lucide/user" import IconUser from "~icons/lucide/user"
import { NewWorkspaceService } from ".." import { NewWorkspaceService } from ".."
import { initializeDownloadFile } from "~/helpers/import-export/export"
import {
getFoldersByPath,
resolveSaveContextOnCollectionReorder,
updateInheritedPropertiesForAffectedRequests,
updateSaveContextForAffectedRequests,
} from "~/helpers/collection/collection"
import {
getRequestsByPath,
resolveSaveContextOnRequestReorder,
} from "~/helpers/collection/request"
export class PersonalWorkspaceProviderService export class PersonalWorkspaceProviderService
extends Service extends Service
@@ -492,7 +481,7 @@ export class PersonalWorkspaceProviderService
public reorderRESTCollection( public reorderRESTCollection(
collectionHandle: HandleRef<WorkspaceCollection>, collectionHandle: HandleRef<WorkspaceCollection>,
destinationCollectionIndex: string destinationCollectionIndex: string | null
): Promise<E.Either<unknown, void>> { ): Promise<E.Either<unknown, void>> {
if ( if (
collectionHandle.value.type !== "ok" || collectionHandle.value.type !== "ok" ||
@@ -508,11 +497,6 @@ export class PersonalWorkspaceProviderService
draggedCollectionIndex, draggedCollectionIndex,
destinationCollectionIndex destinationCollectionIndex
) )
resolveSaveContextOnCollectionReorder({
lastIndex: this.pathToLastIndex(draggedCollectionIndex),
newIndex: this.pathToLastIndex(destinationCollectionIndex ?? ""),
folderPath: draggedCollectionIndex.split("/").slice(0, -1).join("/"),
})
return Promise.resolve(E.right(undefined)) return Promise.resolve(E.right(undefined))
} }
@@ -529,64 +513,18 @@ export class PersonalWorkspaceProviderService
return Promise.resolve(E.left("INVALID_COLLECTION_HANDLE" as const)) return Promise.resolve(E.left("INVALID_COLLECTION_HANDLE" as const))
} }
const draggedCollectionIndex = collectionHandle.value.data.collectionID moveRESTFolder(
collectionHandle.value.data.collectionID,
moveRESTFolder(draggedCollectionIndex, destinationCollectionIndex) destinationCollectionIndex
if (destinationCollectionIndex === null) {
return Promise.resolve(E.right(undefined))
}
const parentFolder = draggedCollectionIndex
.split("/")
.slice(0, -1)
.join("/") // remove last folder to get parent folder
const totalFoldersOfDestinationCollection =
getFoldersByPath(
restCollectionStore.value.state,
destinationCollectionIndex
).length - (parentFolder === destinationCollectionIndex ? 1 : 0)
resolveSaveContextOnCollectionReorder(
{
lastIndex: this.pathToLastIndex(draggedCollectionIndex),
newIndex: -1,
folderPath: parentFolder,
length: getFoldersByPath(restCollectionStore.value.state, parentFolder)
.length,
},
"drop"
) )
updateSaveContextForAffectedRequests(
draggedCollectionIndex,
`${destinationCollectionIndex}/${totalFoldersOfDestinationCollection}`
)
// const { auth, headers } = cascadeParentCollectionForHeaderAuth(
// `${destinationCollectionIndex}/${totalFoldersOfDestinationCollection}`,
// "rest"
// )
// const inheritedProperty = {
// auth,
// headers,
// }
// updateInheritedPropertiesForAffectedRequests(
// `${destinationCollectionIndex}/${totalFoldersOfDestinationCollection}`,
// inheritedProperty,
// "rest"
// )
return Promise.resolve(E.right(undefined)) return Promise.resolve(E.right(undefined))
} }
public reorderRESTRequest( public reorderRESTRequest(
requestHandle: HandleRef<WorkspaceRequest>, requestHandle: HandleRef<WorkspaceRequest>,
destinationCollectionIndex: string, destinationCollectionIndex: string,
destinationRequestIndex: string destinationRequestIndex: string | null
): Promise<E.Either<unknown, void>> { ): Promise<E.Either<unknown, void>> {
if ( if (
requestHandle.value.type !== "ok" || requestHandle.value.type !== "ok" ||
@@ -627,45 +565,6 @@ export class PersonalWorkspaceProviderService
.slice(0, -1) .slice(0, -1)
.join("/") .join("/")
// const { auth, headers } = cascadeParentCollectionForHeaderAuth(
// destinationCollectionIndex,
// "rest"
// )
// const possibleTab = tabs.getTabRefWithSaveContext({
// originLocation: "user-collection",
// folderPath: parentCollectionIndexPath,
// requestIndex: this.pathToLastIndex(requestIndex),
// })
// // If there is a tab attached to this request, change save its save context
// if (possibleTab) {
// possibleTab.value.document.saveContext = {
// originLocation: "user-collection",
// folderPath: destinationCollectionIndex,
// requestIndex: getRequestsByPath(
// restCollectionStore.value.state,
// destinationCollectionIndex
// ).length,
// }
// possibleTab.value.document.inheritedProperties = {
// auth,
// headers,
// }
// }
// // When it's drop it's basically getting deleted from last folder. reordering last folder accordingly
// resolveSaveContextOnRequestReorder({
// lastIndex: this.pathToLastIndex(requestIndex),
// newIndex: -1, // being deleted from last folder
// folderPath: parentCollectionIndexPath,
// length: getRequestsByPath(
// restCollectionStore.value.state,
// parentCollectionIndexPath
// ).length,
// })
moveRESTRequest( moveRESTRequest(
parentCollectionIndexPath, parentCollectionIndexPath,
this.pathToLastIndex(requestIndex), this.pathToLastIndex(requestIndex),
@@ -924,7 +823,7 @@ export class PersonalWorkspaceProviderService
isLastItem: isLastItem:
id === this.restCollectionState.value.state.length - 1, id === this.restCollectionState.value.state.length - 1,
name: coll.name, name: coll.name,
parentIndex: null, parentCollectionID: null,
} }
}) })
}), }),