diff --git a/packages/hoppscotch-common/package.json b/packages/hoppscotch-common/package.json
index 57e35b39..4263f0da 100644
--- a/packages/hoppscotch-common/package.json
+++ b/packages/hoppscotch-common/package.json
@@ -31,9 +31,9 @@
"@codemirror/state": "^6.1.0",
"@codemirror/view": "^6.0.2",
"@hoppscotch/codemirror-lang-graphql": "workspace:^0.2.0",
- "@hoppscotch/ui": "workspace:^0.0.1",
"@hoppscotch/data": "workspace:^0.4.4",
"@hoppscotch/js-sandbox": "workspace:^2.1.0",
+ "@hoppscotch/ui": "workspace:^0.0.1",
"@hoppscotch/vue-toasted": "^0.1.0",
"@lezer/highlight": "^1.0.0",
"@sentry/tracing": "^7.13.0",
@@ -125,6 +125,7 @@
"@vue/eslint-config-typescript": "^11.0.1",
"@vue/runtime-core": "^3.2.39",
"cross-env": "^7.0.3",
+ "dotenv": "^16.0.3",
"eslint": "^8.24.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.5.1",
diff --git a/packages/hoppscotch-common/src/components.d.ts b/packages/hoppscotch-common/src/components.d.ts
index 970a9ec0..40471f3c 100644
--- a/packages/hoppscotch-common/src/components.d.ts
+++ b/packages/hoppscotch-common/src/components.d.ts
@@ -89,7 +89,6 @@ declare module '@vue/runtime-core' {
HoppSmartSpinner: typeof import('@hoppscotch/ui')['HoppSmartSpinner']
HoppSmartTab: typeof import('@hoppscotch/ui')['HoppSmartTab']
HoppSmartTabs: typeof import('@hoppscotch/ui')['HoppSmartTabs']
- HoppSmartToggle: typeof import('@hoppscotch/ui')['HoppSmartToggle']
HttpAuthorization: typeof import('./components/http/Authorization.vue')['default']
HttpBody: typeof import('./components/http/Body.vue')['default']
HttpBodyParameters: typeof import('./components/http/BodyParameters.vue')['default']
diff --git a/packages/hoppscotch-common/src/components/collections/Collection.vue b/packages/hoppscotch-common/src/components/collections/Collection.vue
index 83f87c90..f368409f 100644
--- a/packages/hoppscotch-common/src/components/collections/Collection.vue
+++ b/packages/hoppscotch-common/src/components/collections/Collection.vue
@@ -4,7 +4,7 @@
class="h-1 w-full transition"
:class="[
{
- 'bg-accentDark': ordering && notSameDestination,
+ 'bg-accentDark': isReorderable,
},
]"
@drop="orderUpdateCollectionEvent"
@@ -20,35 +20,43 @@
}"
>
{
+ resetDragState()
+ dropItemID = ''
+ }
+ "
@contextmenu.prevent="options?.tippy.show()"
>
-
-
-
-
-
-
- {{ collectionName }}
+
+
+
-
+
+
+ {{ collectionName }}
+
+
+
,
+ default: null,
+ required: true,
+ },
data: {
type: Object as PropType | TeamCollection>,
default: () => ({}),
@@ -258,6 +276,12 @@ const dragging = ref(false)
const ordering = ref(false)
const dropItemID = ref("")
+const currentReorderingStatus = useReadonlyStream(currentReorderingStatus$, {
+ type: "collection",
+ id: "",
+ parentID: "",
+})
+
// Used to determine if the collection is being dragged to a different destination
// This is used to make the highlight effect work
watch(
@@ -293,11 +317,52 @@ watch(
}
)
+const isRequestDragging = computed(() => {
+ return currentReorderingStatus.value.type === "request"
+})
+
+const isSameParent = computed(() => {
+ return currentReorderingStatus.value.parentID === props.parentID
+})
+
+const isReorderable = computed(() => {
+ return (
+ ordering.value &&
+ notSameDestination.value &&
+ !isRequestDragging.value &&
+ isSameParent.value
+ )
+})
+
const dragStart = ({ dataTransfer }: DragEvent) => {
if (dataTransfer) {
emit("drag-event", dataTransfer)
dropItemID.value = dataTransfer.getData("collectionIndex")
dragging.value = !dragging.value
+ changeCurrentReorderStatus({
+ type: "collection",
+ id: props.id,
+ parentID: props.parentID,
+ })
+ }
+}
+
+// Trigger the re-ordering event when a collection is dragged over another collection's top section
+const handleDragOver = (e: DragEvent) => {
+ dragging.value = true
+ if (e.offsetY < 10 && notSameDestination.value) {
+ ordering.value = true
+ dragging.value = false
+ } else {
+ ordering.value = false
+ }
+}
+
+const handelDrop = (e: DragEvent) => {
+ if (ordering.value) {
+ orderUpdateCollectionEvent(e)
+ } else {
+ dropEvent(e)
}
}
@@ -305,8 +370,7 @@ const dropEvent = (e: DragEvent) => {
if (e.dataTransfer) {
e.stopPropagation()
emit("drop-event", e.dataTransfer)
- dragging.value = !dragging.value
- dropItemID.value = ""
+ resetDragState()
}
}
@@ -314,8 +378,7 @@ const orderUpdateCollectionEvent = (e: DragEvent) => {
if (e.dataTransfer) {
e.stopPropagation()
emit("update-collection-order", e.dataTransfer)
- ordering.value = !ordering.value
- dropItemID.value = ""
+ resetDragState()
}
}
@@ -334,6 +397,5 @@ const isCollLoading = computed(() => {
const resetDragState = () => {
dragging.value = false
ordering.value = false
- dropItemID.value = ""
}
diff --git a/packages/hoppscotch-common/src/components/collections/MyCollections.vue b/packages/hoppscotch-common/src/components/collections/MyCollections.vue
index 7c6fdcbc..759b7ad6 100644
--- a/packages/hoppscotch-common/src/components/collections/MyCollections.vue
+++ b/packages/hoppscotch-common/src/components/collections/MyCollections.vue
@@ -39,6 +39,7 @@
-
-
-
-
- {{ request.method }}
-
-
-
-
- {{ request.name }}
+
+
+
+
+ {{ request.method }}
+
-
+
+ {{ request.name }}
+ v-if="isActive"
+ v-tippy="{ theme: 'tooltip' }"
+ class="relative h-1.5 w-1.5 flex flex-shrink-0 mx-3"
+ :title="`${t('collection.request_in_use')}`"
+ >
+
+
+
+
-
+
,
+ default: null,
+ required: true,
+ },
collectionsType: {
type: String as PropType,
default: "my-collections",
@@ -222,6 +236,12 @@ const duplicate = ref(null)
const dragging = ref(false)
const ordering = ref(false)
+const currentReorderingStatus = useReadonlyStream(currentReorderingStatus$, {
+ type: "collection",
+ id: "",
+ parentID: "",
+})
+
const requestMethodLabels = {
get: "text-green-500",
post: "text-yellow-500",
@@ -255,13 +275,41 @@ const dragStart = ({ dataTransfer }: DragEvent) => {
if (dataTransfer) {
emit("drag-request", dataTransfer)
dragging.value = !dragging.value
+ changeCurrentReorderStatus({
+ type: "request",
+ id: props.requestID,
+ parentID: props.parentID,
+ })
+ }
+}
+
+const isCollectionDragging = computed(() => {
+ return currentReorderingStatus.value.type === "collection"
+})
+
+const isSameParent = computed(() => {
+ return currentReorderingStatus.value.parentID === props.parentID
+})
+
+const isReorderable = computed(() => {
+ return ordering.value && !isCollectionDragging.value && isSameParent.value
+})
+
+// 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
+ } else {
+ ordering.value = false
}
}
const dropEvent = (e: DragEvent) => {
if (e.dataTransfer) {
e.stopPropagation()
- ordering.value = !ordering.value
+ resetDragState()
emit("update-request-order", e.dataTransfer)
}
}
@@ -273,4 +321,9 @@ const isRequestLoading = computed(() => {
return false
}
})
+
+const resetDragState = () => {
+ dragging.value = false
+ ordering.value = false
+}
diff --git a/packages/hoppscotch-common/src/components/collections/TeamCollections.vue b/packages/hoppscotch-common/src/components/collections/TeamCollections.vue
index 2b694d7f..c26e2960 100644
--- a/packages/hoppscotch-common/src/components/collections/TeamCollections.vue
+++ b/packages/hoppscotch-common/src/components/collections/TeamCollections.vue
@@ -53,6 +53,7 @@
{
return filteredCollections
})
-const isSelected = computed(() => {
- return ({
- collectionIndex,
- folderPath,
- requestIndex,
- collectionID,
- folderID,
- requestID,
- }: {
- collectionIndex?: number | undefined
- folderPath?: string | undefined
- requestIndex?: number | undefined
- collectionID?: string | undefined
- folderID?: string | undefined
- requestID?: string | undefined
- }) => {
- if (collectionIndex !== undefined) {
- return (
- props.picked &&
- props.picked.pickedType === "my-collection" &&
- props.picked.collectionIndex === collectionIndex
- )
- } else if (requestIndex !== undefined && folderPath !== undefined) {
- return (
- props.picked &&
- props.picked.pickedType === "my-request" &&
- props.picked.folderPath === folderPath &&
- props.picked.requestIndex === requestIndex
- )
- } else if (folderPath !== undefined) {
- return (
- props.picked &&
- props.picked.pickedType === "my-folder" &&
- props.picked.folderPath === folderPath
- )
- } else if (collectionID !== undefined) {
- return (
- props.picked &&
- props.picked.pickedType === "teams-collection" &&
- props.picked.collectionID === collectionID
- )
- } else if (requestID !== undefined) {
- return (
- props.picked &&
- props.picked.pickedType === "teams-request" &&
- props.picked.requestID === requestID
- )
- } else if (folderID !== undefined) {
- return (
- props.picked &&
- props.picked.pickedType === "teams-folder" &&
- props.picked.folderID === folderID
- )
- }
+const isSelected = ({
+ collectionIndex,
+ folderPath,
+ requestIndex,
+ collectionID,
+ folderID,
+ requestID,
+}: {
+ collectionIndex?: number | undefined
+ folderPath?: string | undefined
+ requestIndex?: number | undefined
+ collectionID?: string | undefined
+ folderID?: string | undefined
+ requestID?: string | undefined
+}) => {
+ if (collectionIndex !== undefined) {
+ return (
+ props.picked &&
+ props.picked.pickedType === "my-collection" &&
+ props.picked.collectionIndex === collectionIndex
+ )
+ } else if (requestIndex !== undefined && folderPath !== undefined) {
+ return (
+ props.picked &&
+ props.picked.pickedType === "my-request" &&
+ props.picked.folderPath === folderPath &&
+ props.picked.requestIndex === requestIndex
+ )
+ } else if (folderPath !== undefined) {
+ return (
+ props.picked &&
+ props.picked.pickedType === "my-folder" &&
+ props.picked.folderPath === folderPath
+ )
+ } else if (collectionID !== undefined) {
+ return (
+ props.picked &&
+ props.picked.pickedType === "teams-collection" &&
+ props.picked.collectionID === collectionID
+ )
+ } else if (requestID !== undefined) {
+ return (
+ props.picked &&
+ props.picked.pickedType === "teams-request" &&
+ props.picked.requestID === requestID
+ )
+ } else if (folderID !== undefined) {
+ return (
+ props.picked &&
+ props.picked.pickedType === "teams-folder" &&
+ props.picked.folderID === folderID
+ )
}
-})
+}
const modalLoadingState = ref(false)
const exportLoading = ref(false)
@@ -1023,7 +1021,7 @@ const onRemoveCollection = () => {
if (collectionIndex === null) return
if (
- isSelected.value({
+ isSelected({
collectionIndex,
})
) {
@@ -1040,7 +1038,7 @@ const onRemoveCollection = () => {
if (!collectionID) return
if (
- isSelected.value({
+ isSelected({
collectionID,
})
) {
@@ -1067,7 +1065,7 @@ const onRemoveFolder = () => {
if (!folderPath) return
if (
- isSelected.value({
+ isSelected({
folderPath,
})
) {
@@ -1084,7 +1082,7 @@ const onRemoveFolder = () => {
if (!collectionID) return
if (
- isSelected.value({
+ isSelected({
collectionID,
})
) {
@@ -1118,7 +1116,7 @@ const onRemoveRequest = () => {
if (folderPath === null || requestIndex === null) return
if (
- isSelected.value({
+ isSelected({
folderPath,
requestIndex,
})
@@ -1136,7 +1134,7 @@ const onRemoveRequest = () => {
if (!requestID) return
if (
- isSelected.value({
+ isSelected({
requestID,
})
) {
@@ -1342,12 +1340,10 @@ const discardRequestChange = () => {
* @param path The path of the request
* @returns The index of the request
*/
-const pathToIndex = computed(() => {
- return (path: string) => {
- const pathArr = path.split("/")
- return parseInt(pathArr[pathArr.length - 1])
- }
-})
+const pathToLastIndex = (path: string) => {
+ const pathArr = path.split("/")
+ return parseInt(pathArr[pathArr.length - 1])
+}
/**
* This function is called when the user drops the request inside a collection
@@ -1363,7 +1359,7 @@ const dropRequest = (payload: {
if (collectionsType.value.type === "my-collections" && folderPath) {
moveRESTRequest(
folderPath,
- pathToIndex.value(requestIndex),
+ pathToLastIndex(requestIndex),
destinationCollectionIndex
)
toast.success(`${t("request.moved")}`)
@@ -1395,6 +1391,43 @@ const dropRequest = (payload: {
}
}
+/**
+ * @param path The path of the collection or request
+ * @returns The index of the collection or request
+ */
+const pathToIndex = (path: string) => {
+ const pathArr = path.split("/")
+ return pathArr
+}
+
+/**
+ * Used to check if the collection exist as the parent of the childrens
+ * @param collectionIndexDragged The index of the collection dragged
+ * @param destinationCollectionIndex The index of the destination collection
+ * @returns True if the collection exist as the parent of the childrens
+ */
+const checkIfCollectionIsAParentOfTheChildren = (
+ collectionIndexDragged: string,
+ destinationCollectionIndex: string
+) => {
+ const collectionDraggedPath = pathToIndex(collectionIndexDragged)
+ const destinationCollectionPath = pathToIndex(destinationCollectionIndex)
+
+ if (collectionDraggedPath.length < destinationCollectionPath.length) {
+ const slicedDestinationCollectionPath = destinationCollectionPath.slice(
+ 0,
+ collectionDraggedPath.length
+ )
+ if (isEqual(slicedDestinationCollectionPath, collectionDraggedPath)) {
+ return true
+ } else {
+ return false
+ }
+ }
+
+ return false
+}
+
/**
* This function is called when the user moves the collection
* to a different collection or folder
@@ -1408,6 +1441,15 @@ const dropCollection = (payload: {
if (!collectionIndexDragged || !destinationCollectionIndex) return
if (collectionIndexDragged === destinationCollectionIndex) return
if (collectionsType.value.type === "my-collections") {
+ if (
+ checkIfCollectionIsAParentOfTheChildren(
+ collectionIndexDragged,
+ destinationCollectionIndex
+ )
+ ) {
+ toast.error(`${t("team.parent_coll_move")}`)
+ return
+ }
moveRESTFolder(collectionIndexDragged, destinationCollectionIndex)
draggingToRoot.value = false
toast.success(`${t("collection.moved")}`)
@@ -1445,12 +1487,10 @@ const dropCollection = (payload: {
* @param id - path of the collection
* @returns boolean - true if the collection is already in the root
*/
-const isAlreadyInRoot = computed(() => {
- return (id: string) => {
- const indexPath = id.split("/").map((i) => parseInt(i))
- return indexPath.length === 1
- }
-})
+const isAlreadyInRoot = (id: string) => {
+ const indexPath = pathToIndex(id)
+ return indexPath.length === 1
+}
/**
* This function is called when the user drops the collection
@@ -1463,7 +1503,7 @@ const dropToRoot = ({ dataTransfer }: DragEvent) => {
if (!collectionIndexDragged) return
if (collectionsType.value.type === "my-collections") {
// check if the collection is already in the root
- if (isAlreadyInRoot.value(collectionIndexDragged)) {
+ if (isAlreadyInRoot(collectionIndexDragged)) {
toast.error(`${t("collection.invalid_root_move")}`)
} else {
moveRESTFolder(collectionIndexDragged, null)
@@ -1506,26 +1546,25 @@ const dropToRoot = ({ dataTransfer }: DragEvent) => {
* @param destinationReq - path index of the destination request
* @returns boolean - true if the request is being moved to the same parent
*/
-const isSameSameParent = computed(
- () => (draggedReq: string, destinationReq: string) => {
- const draggedReqIndex = draggedReq.split("/").map((i) => parseInt(i))
- const destinationReqIndex = destinationReq
- .split("/")
- .map((i) => parseInt(i))
+const isSameSameParent = (draggedItem: string, destinationItem: string) => {
+ const draggedItemIndex = pathToIndex(draggedItem)
+ const destinationItemIndex = pathToIndex(destinationItem)
- // length of 1 means the request is in the root
- if (draggedReqIndex.length === 1 && destinationReqIndex.length === 1) {
- return true
- } else if (
- draggedReqIndex[draggedReqIndex.length - 2] ===
- destinationReqIndex[destinationReqIndex.length - 2]
- ) {
+ // length of 1 means the request is in the root
+ if (draggedItemIndex.length === 1 && destinationItemIndex.length === 1) {
+ return true
+ } else if (draggedItemIndex.length === destinationItemIndex.length) {
+ const dragedItemParent = draggedItemIndex.slice(0, -1)
+ const destinationItemParent = destinationItemIndex.slice(0, -1)
+ if (isEqual(dragedItemParent, destinationItemParent)) {
return true
} else {
return false
}
+ } else {
+ return false
}
-)
+}
/**
* This function is called when the user updates the request order in a collection
@@ -1553,12 +1592,12 @@ const updateRequestOrder = (payload: {
if (dragedRequestIndex === destinationRequestIndex) return
if (collectionsType.value.type === "my-collections") {
- if (!isSameSameParent.value(dragedRequestIndex, destinationRequestIndex)) {
+ if (!isSameSameParent(dragedRequestIndex, destinationRequestIndex)) {
toast.error(`${t("collection.different_parent")}`)
} else {
updateRESTRequestOrder(
- pathToIndex.value(dragedRequestIndex),
- pathToIndex.value(destinationRequestIndex),
+ pathToLastIndex(dragedRequestIndex),
+ pathToLastIndex(destinationRequestIndex),
destinationCollectionIndex
)
toast.success(`${t("request.order_changed")}`)
@@ -1608,9 +1647,7 @@ const updateCollectionOrder = (payload: {
if (dragedCollectionIndex === destinationCollectionIndex) return
if (collectionsType.value.type === "my-collections") {
- if (
- !isSameSameParent.value(dragedCollectionIndex, destinationCollectionIndex)
- ) {
+ if (!isSameSameParent(dragedCollectionIndex, destinationCollectionIndex)) {
toast.error(`${t("collection.different_parent")}`)
} else {
updateRESTCollectionOrder(
diff --git a/packages/hoppscotch-common/src/helpers/teams/TeamCollectionAdapter.ts b/packages/hoppscotch-common/src/helpers/teams/TeamCollectionAdapter.ts
index ee9617d3..aee9af86 100644
--- a/packages/hoppscotch-common/src/helpers/teams/TeamCollectionAdapter.ts
+++ b/packages/hoppscotch-common/src/helpers/teams/TeamCollectionAdapter.ts
@@ -547,6 +547,15 @@ export default class NewTeamCollectionAdapter {
)
}
+ private 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)
+ }
+ }
+
public updateRequestOrder(
dragedRequestID: string,
destinationRequestID: string,
@@ -570,10 +579,7 @@ export default class NewTeamCollectionAdapter {
if (requestIndex === -1) return
- const request = collection.requests[requestIndex]
-
- collection.requests.splice(requestIndex, 1)
- collection.requests.splice(destinationIndex, 0, request)
+ this.reorderItems(collection.requests, requestIndex, destinationIndex)
this.collections$.next(tree)
}
@@ -600,10 +606,7 @@ export default class NewTeamCollectionAdapter {
// If the collection index is not found, don't update
if (collectionIndex === -1) return
- const collection = coll.children[collectionIndex]
-
- coll.children.splice(collectionIndex, 1)
- coll.children.splice(destinationIndex, 0, collection)
+ this.reorderItems(coll.children, collectionIndex, destinationIndex)
} else {
// If the collection has no parent collection, it is a root collection
const collectionIndex = tree.findIndex((coll) => coll.id === collectionID)
@@ -615,10 +618,7 @@ export default class NewTeamCollectionAdapter {
// If the collection index is not found, don't update
if (collectionIndex === -1) return
- const collection = tree[collectionIndex]
-
- tree.splice(collectionIndex, 1)
- tree.splice(destinationIndex, 0, collection)
+ this.reorderItems(tree, collectionIndex, destinationIndex)
}
this.collections$.next(tree)
diff --git a/packages/hoppscotch-common/src/newstore/collections.ts b/packages/hoppscotch-common/src/newstore/collections.ts
index bcfe0557..39c3e0c9 100644
--- a/packages/hoppscotch-common/src/newstore/collections.ts
+++ b/packages/hoppscotch-common/src/newstore/collections.ts
@@ -31,7 +31,7 @@ const defaultGraphqlCollectionState = {
type RESTCollectionStoreType = typeof defaultRESTCollectionState
type GraphqlCollectionStoreType = typeof defaultGraphqlCollectionState
-function navigateToFolderWithIndexPath(
+export function navigateToFolderWithIndexPath(
collections: HoppCollection[],
indexPaths: number[]
) {
@@ -45,6 +45,15 @@ function navigateToFolderWithIndexPath(
return target !== undefined ? target : null
}
+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)
+ }
+}
+
const restCollectionDispatchers = defineDispatchers({
setCollections(
_: RESTCollectionStoreType,
@@ -88,12 +97,15 @@ const restCollectionDispatchers = defineDispatchers({
{ state }: RESTCollectionStoreType,
{
collectionIndex,
- collection,
- }: { collectionIndex: number; collection: HoppCollection }
+ partialCollection,
+ }: {
+ collectionIndex: number
+ partialCollection: Partial>
+ }
) {
return {
state: state.map((col, index) =>
- index === collectionIndex ? collection : col
+ index === collectionIndex ? { ...col, ...partialCollection } : col
),
}
},
@@ -295,18 +307,14 @@ const restCollectionDispatchers = defineDispatchers({
)
if (containingFolder === null) {
- const [removed] = newState.splice(folderIndex, 1)
-
- newState.splice(destinationFolderIndex, 0, removed)
+ reorderItems(newState, folderIndex, destinationFolderIndex)
return {
state: newState,
}
}
- const [removed] = containingFolder.folders.splice(folderIndex, 1)
-
- containingFolder.folders.splice(destinationFolderIndex, 0, removed)
+ reorderItems(containingFolder.folders, folderIndex, destinationFolderIndex)
return {
state: newState,
@@ -480,9 +488,7 @@ const restCollectionDispatchers = defineDispatchers({
return {}
}
- const [removed] = targetLocation.requests.splice(requestIndex, 1)
-
- targetLocation.requests.splice(destinationRequestIndex, 0, removed)
+ reorderItems(targetLocation.requests, requestIndex, destinationRequestIndex)
return {
state: newState,
@@ -821,13 +827,13 @@ export function getRESTCollection(collectionIndex: number) {
export function editRESTCollection(
collectionIndex: number,
- collection: HoppCollection
+ partialCollection: Partial>
) {
restCollectionStore.dispatch({
dispatcher: "editCollection",
payload: {
collectionIndex,
- collection,
+ partialCollection: partialCollection,
},
})
}
diff --git a/packages/hoppscotch-common/src/newstore/reordering.ts b/packages/hoppscotch-common/src/newstore/reordering.ts
new file mode 100644
index 00000000..ecf1048d
--- /dev/null
+++ b/packages/hoppscotch-common/src/newstore/reordering.ts
@@ -0,0 +1,46 @@
+import { distinctUntilChanged, pluck } from "rxjs"
+import DispatchingStore, { defineDispatchers } from "./DispatchingStore"
+
+type ReorderingItem =
+ | { type: "collection"; id: string; parentID: string | null }
+ | { type: "request"; id: string; parentID: string | null }
+
+type CurrentReorderingState = {
+ currentReorderingItem: ReorderingItem
+}
+
+const initialState: CurrentReorderingState = {
+ currentReorderingItem: {
+ type: "collection",
+ id: "",
+ parentID: "",
+ },
+}
+
+const dispatchers = defineDispatchers({
+ changeCurrentReorderStatus(
+ _,
+ { reorderItem }: { reorderItem: ReorderingItem }
+ ) {
+ return {
+ currentReorderingItem: reorderItem,
+ }
+ },
+})
+
+export const currentReorderStore = new DispatchingStore(
+ initialState,
+ dispatchers
+)
+
+export const currentReorderingStatus$ = currentReorderStore.subject$.pipe(
+ pluck("currentReorderingItem"),
+ distinctUntilChanged()
+)
+
+export function changeCurrentReorderStatus(reorderItem: ReorderingItem) {
+ currentReorderStore.dispatch({
+ dispatcher: "changeCurrentReorderStatus",
+ payload: { reorderItem },
+ })
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index b56665a4..8a227705 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -84,6 +84,7 @@ importers:
eslint-config-prettier: ^8.5.0
eslint-plugin-prettier: ^4.2.1
express: ^4.17.1
+ express-session: ^1.17.3
fp-ts: ^2.13.1
graphql: ^15.5.0
graphql-query-complexity: ^0.12.0
@@ -130,6 +131,7 @@ importers:
cookie: 0.5.0
cookie-parser: 1.4.6
express: 4.18.2
+ express-session: 1.17.3
fp-ts: 2.13.1
graphql: 15.8.0
graphql-query-complexity: 0.12.0_graphql@15.8.0
@@ -296,6 +298,7 @@ importers:
axios: ^0.21.4
buffer: ^6.0.3
cross-env: ^7.0.3
+ dotenv: ^16.0.3
eslint: ^8.24.0
eslint-plugin-prettier: ^4.2.1
eslint-plugin-vue: ^9.5.1
@@ -471,6 +474,7 @@ importers:
'@vue/eslint-config-typescript': 11.0.1_kpxf5iryryrlim2ejhkirkiuey
'@vue/runtime-core': 3.2.39
cross-env: 7.0.3
+ dotenv: 16.0.3
eslint: 8.24.0
eslint-plugin-prettier: 4.2.1_eslint@8.24.0
eslint-plugin-vue: 9.5.1_eslint@8.24.0
@@ -4647,7 +4651,7 @@ packages:
'@types/jsonwebtoken': 8.5.9
chalk: 4.1.2
debug: 4.3.4
- dotenv: 16.0.1
+ dotenv: 16.0.3
graphql: 15.8.0
graphql-request: 4.3.0_graphql@15.8.0
http-proxy-agent: 5.0.0
@@ -4681,7 +4685,7 @@ packages:
'@types/jsonwebtoken': 9.0.1
chalk: 4.1.2
debug: 4.3.4
- dotenv: 16.0.1
+ dotenv: 16.0.3
graphql: 16.6.0
graphql-request: 5.1.0_graphql@16.6.0
http-proxy-agent: 5.0.0
@@ -10063,13 +10067,18 @@ packages:
dev: false
/cookie-signature/1.0.6:
- resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
+ resolution: {integrity: sha1-4wOogrNCzD7oylE6eZmXNNqzriw=}
/cookie/0.4.1:
resolution: {integrity: sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==}
engines: {node: '>= 0.6'}
dev: false
+ /cookie/0.4.2:
+ resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
/cookie/0.5.0:
resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
engines: {node: '>= 0.6'}
@@ -10603,8 +10612,8 @@ packages:
is-obj: 2.0.0
dev: true
- /dotenv/16.0.1:
- resolution: {integrity: sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==}
+ /dotenv/16.0.3:
+ resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==}
engines: {node: '>=12'}
dev: true
@@ -12062,6 +12071,22 @@ packages:
raw-body: 2.5.1
dev: false
+ /express-session/1.17.3:
+ resolution: {integrity: sha512-4+otWXlShYlG1Ma+2Jnn+xgKUZTMJ5QD3YvfilX3AcocOAbIkVylSWEklzALe/+Pu4qV6TYBj5GwOBFfdKqLBw==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ cookie: 0.4.2
+ cookie-signature: 1.0.6
+ debug: 2.6.9
+ depd: 2.0.0
+ on-headers: 1.0.2
+ parseurl: 1.3.3
+ safe-buffer: 5.2.1
+ uid-safe: 2.1.5
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
/express/4.18.2:
resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==}
engines: {node: '>= 0.10.0'}
@@ -16028,6 +16053,11 @@ packages:
dependencies:
ee-first: 1.1.1
+ /on-headers/1.0.2:
+ resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
/once/1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
@@ -16844,6 +16874,11 @@ packages:
resolution: {integrity: sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA==}
dev: false
+ /random-bytes/1.0.0:
+ resolution: {integrity: sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==}
+ engines: {node: '>= 0.8'}
+ dev: false
+
/randombytes/2.1.0:
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
dependencies:
@@ -18834,6 +18869,13 @@ packages:
resolution: {integrity: sha512-boAm74ubXHY7KJQZLlXrtMz52qFvpsbOxDcZOnw/Wf+LS4Mmyu7JxmzD4tDLtUQtmZECypJ0FrCz4QIe6dvKRA==}
dev: true
+ /uid-safe/2.1.5:
+ resolution: {integrity: sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ random-bytes: 1.0.0
+ dev: false
+
/uid2/0.0.4:
resolution: {integrity: sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA==}
dev: false