forked from extern/bruno
feat: drag item to root of collection
This commit is contained in:
parent
ee4734c957
commit
36d0550472
@ -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()
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user