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) => { canDrop: (draggedItem) => {
return draggedItem.id !== item.uid; return draggedItem.uid !== item.uid;
}, },
collect: (monitor) => ({ collect: (monitor) => ({
isOver: monitor.isOver() isOver: monitor.isOver()

View File

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

View File

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

View File

@ -8,6 +8,7 @@ import cloneDeep from 'lodash/cloneDeep';
import { import {
findItemInCollection, findItemInCollection,
moveCollectionItem, moveCollectionItem,
moveCollectionItemToRootOfCollection,
findCollectionByUid, findCollectionByUid,
recursivelyGetAllItemUids, recursivelyGetAllItemUids,
transformCollectionToSaveToIdb, transformCollectionToSaveToIdb,
@ -35,6 +36,7 @@ import {
cloneItem as _cloneItem, cloneItem as _cloneItem,
deleteItem as _deleteItem, deleteItem as _deleteItem,
moveItem as _moveItem, moveItem as _moveItem,
moveItemToRootOfCollection as _moveItemToRootOfCollection,
saveRequest as _saveRequest, saveRequest as _saveRequest,
addEnvironment as _addEnvironment, addEnvironment as _addEnvironment,
renameEnvironment as _renameEnvironment, 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) => { export const newHttpRequest = (params) => (dispatch, getState) => {
const { requestName, requestType, requestUrl, requestMethod, collectionUid, itemUid } = params; const { requestName, requestType, requestUrl, requestMethod, collectionUid, itemUid } = params;

View File

@ -199,6 +199,21 @@ export const collectionsSlice = createSlice({
addDepth(collection.items); 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) => { requestSent: (state, action) => {
const { itemUid, collectionUid, cancelTokenUid } = action.payload; const { itemUid, collectionUid, cancelTokenUid } = action.payload;
const collection = findCollectionByUid(state.collections, collectionUid); const collection = findCollectionByUid(state.collections, collectionUid);
@ -804,6 +819,7 @@ export const {
renameItem, renameItem,
cloneItem, cloneItem,
moveItem, moveItem,
moveItemToRootOfCollection,
requestSent, requestSent,
requestCancelled, requestCancelled,
responseReceived, 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 = {}) => { export const transformCollectionToSaveToIdb = (collection, options = {}) => {
const copyHeaders = (headers) => { const copyHeaders = (headers) => {
return map(headers, (header) => { return map(headers, (header) => {