feat: drag item to root of collection

This commit is contained in:
Anoop M D 2023-01-10 09:37:09 +05:30
parent ee4734c957
commit 36d0550472
6 changed files with 120 additions and 19 deletions

View File

@ -51,7 +51,7 @@ const CollectionItem = ({ item, collection, searchText }) => {
}
},
canDrop: (draggedItem) => {
return draggedItem.id !== item.uid;
return draggedItem.uid !== item.uid;
},
collect: (monitor) => ({
isOver: monitor.isOver()

View File

@ -2,11 +2,11 @@ import React, { useState, forwardRef, useRef, useEffect } from 'react';
import classnames from 'classnames';
import filter from 'lodash/filter';
import cloneDeep from 'lodash/cloneDeep';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { useDrop } from 'react-dnd';
import { IconChevronRight, IconDots } from '@tabler/icons';
import Dropdown from 'components/Dropdown';
import { collectionClicked } from 'providers/ReduxStore/slices/collections';
import { moveItemToRootOfCollection } from 'providers/ReduxStore/slices/collections/actions';
import { useDispatch } from 'react-redux';
import NewRequest from 'components/Sidebar/NewRequest';
import NewFolder from 'components/Sidebar/NewFolder';
@ -73,6 +73,21 @@ const Collection = ({ collection, searchText }) => {
const isLocal = isLocalCollection(collection);
const [{ isOver }, drop] = useDrop({
accept: 'COLLECTION_ITEM',
drop: (draggedItem) => {
console.log('drop', draggedItem);
dispatch(moveItemToRootOfCollection(collection.uid, draggedItem.uid));
},
canDrop: (draggedItem) => {
// todo need to make sure that draggedItem belongs to the collection
return true;
},
collect: (monitor) => ({
isOver: monitor.isOver()
})
});
return (
<StyledWrapper className="flex flex-col">
{showNewRequestModal && <NewRequest collection={collection} onClose={() => setShowNewRequestModal(false)} />}
@ -81,7 +96,7 @@ const Collection = ({ collection, searchText }) => {
{showRemoveCollectionFromWSModal && <RemoveCollectionFromWorkspace collection={collection} onClose={() => setShowRemoveCollectionFromWSModal(false)} />}
{showDeleteCollectionModal && <DeleteCollection collection={collection} onClose={() => setShowDeleteCollectionModal(false)} />}
{showRemoveLocalCollectionModal && <RemoveLocalCollection collection={collection} onClose={() => setShowRemoveLocalCollectionModal(false)} />}
<div className="flex py-1 collection-name items-center">
<div className="flex py-1 collection-name items-center" ref={(node) => drop(node)}>
<div className="flex flex-grow items-center" onClick={handleClick}>
<IconChevronRight size={16} strokeWidth={2} className={iconClassName} style={{ width: 16, color: 'rgb(160 160 160)' }} />
<div className="ml-1" id="sidebar-collection-name">{collection.name}</div>
@ -164,21 +179,19 @@ const Collection = ({ collection, searchText }) => {
<div>
{!collectionIsCollapsed ? (
<DndProvider backend={HTML5Backend}>
<div>
{requestItems && requestItems.length
? requestItems.map((i) => {
return <CollectionItem key={i.uid} item={i} collection={collection} searchText={searchText} />;
})
: null}
<div>
{requestItems && requestItems.length
? requestItems.map((i) => {
return <CollectionItem key={i.uid} item={i} collection={collection} searchText={searchText} />;
})
: null}
{folderItems && folderItems.length
? folderItems.map((i) => {
return <CollectionItem key={i.uid} item={i} collection={collection} searchText={searchText} />;
})
: null}
</div>
</DndProvider>
{folderItems && folderItems.length
? folderItems.map((i) => {
return <CollectionItem key={i.uid} item={i} collection={collection} searchText={searchText} />;
})
: null}
</div>
) : null}
</div>
</StyledWrapper>

View File

@ -1,5 +1,7 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import find from 'lodash/find';
import filter from 'lodash/filter';
import Collection from './Collection';
@ -26,7 +28,11 @@ const Collections = ({ searchText }) => {
<div className="mt-4 flex flex-col">
{collectionToDisplay && collectionToDisplay.length
? collectionToDisplay.map((c) => {
return <Collection searchText={searchText} collection={c} key={c.uid} />;
return (
<DndProvider backend={HTML5Backend} key={c.uid}>
<Collection searchText={searchText} collection={c} />;
</DndProvider>
);
})
: null}
</div>

View File

@ -8,6 +8,7 @@ import cloneDeep from 'lodash/cloneDeep';
import {
findItemInCollection,
moveCollectionItem,
moveCollectionItemToRootOfCollection,
findCollectionByUid,
recursivelyGetAllItemUids,
transformCollectionToSaveToIdb,
@ -35,6 +36,7 @@ import {
cloneItem as _cloneItem,
deleteItem as _deleteItem,
moveItem as _moveItem,
moveItemToRootOfCollection as _moveItemToRootOfCollection,
saveRequest as _saveRequest,
addEnvironment as _addEnvironment,
renameEnvironment as _renameEnvironment,
@ -615,6 +617,58 @@ export const moveItem = (collectionUid, draggedItemUid, targetItemUid) => (dispa
});
};
export const moveItemToRootOfCollection = (collectionUid, draggedItemUid) => (dispatch, getState) => {
const state = getState();
const collection = findCollectionByUid(state.collections.collections, collectionUid);
return new Promise((resolve, reject) => {
if (!collection) {
return reject(new Error('Collection not found'));
}
if (isLocalCollection(collection)) {
const draggedItem = findItemInCollection(collection, draggedItemUid);
if (!draggedItem) {
return reject(new Error('Dragged item not found'));
}
const { ipcRenderer } = window;
ipcRenderer
.invoke('renderer:move-item-to-root-of-collection', draggedItem.pathname)
.then(() => resolve())
.catch((error) => reject(error));
return;
}
const collectionCopy = cloneDeep(collection);
const draggedItem = findItemInCollection(collectionCopy, draggedItemUid);
if (!draggedItem) {
return reject(new Error('Dragged item not found'));
}
moveCollectionItemToRootOfCollection(collectionCopy, draggedItem);
const collectionToSave = transformCollectionToSaveToIdb(collectionCopy);
collectionSchema
.validate(collectionToSave)
.then(() => saveCollectionToIdb(window.__idb, collectionToSave))
.then(() => {
dispatch(
_moveItemToRootOfCollection({
collectionUid: collectionUid,
draggedItemUid: draggedItemUid
})
);
})
.then(() => resolve())
.catch((error) => reject(error));
});
};
export const newHttpRequest = (params) => (dispatch, getState) => {
const { requestName, requestType, requestUrl, requestMethod, collectionUid, itemUid } = params;

View File

@ -199,6 +199,21 @@ export const collectionsSlice = createSlice({
addDepth(collection.items);
}
},
moveItemToRootOfCollection: (state, action) => {
const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
const draggedItemUid = action.payload.draggedItemUid;
if (collection) {
const draggedItem = findItemInCollection(collection, draggedItemUid);
if (!draggedItem) {
return;
}
moveCollectionItemToRootOfCollection(collection, draggedItem);
addDepth(collection.items);
}
},
requestSent: (state, action) => {
const { itemUid, collectionUid, cancelTokenUid } = action.payload;
const collection = findCollectionByUid(state.collections, collectionUid);
@ -804,6 +819,7 @@ export const {
renameItem,
cloneItem,
moveItem,
moveItemToRootOfCollection,
requestSent,
requestCancelled,
responseReceived,

View File

@ -147,6 +147,18 @@ export const moveCollectionItem = (collection, draggedItem, targetItem) => {
}
};
export const moveCollectionItemToRootOfCollection = (collection, draggedItem) => {
let draggedItemParent = findParentItemInCollection(collection, draggedItem.uid);
if (draggedItemParent) {
draggedItemParent.items = filter(draggedItemParent.items, (i) => i.uid !== draggedItem.uid);
} else {
collection.items = filter(collection.items, (i) => i.uid !== draggedItem.uid);
}
collection.items.push(draggedItem);
};
export const transformCollectionToSaveToIdb = (collection, options = {}) => {
const copyHeaders = (headers) => {
return map(headers, (header) => {