forked from extern/bruno
feat: delete collections
This commit is contained in:
parent
adc6be031d
commit
02ff85cc57
@ -0,0 +1,15 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
button.submit {
|
||||
color: white;
|
||||
background-color: var(--color-background-danger) !important;
|
||||
border: inherit !important;
|
||||
|
||||
&:hover {
|
||||
border: inherit !important;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default Wrapper;
|
@ -0,0 +1,33 @@
|
||||
import React from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
import Modal from 'components/Modal';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { deleteCollection } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const DeleteCollection = ({onClose, collection}) => {
|
||||
const dispatch = useDispatch();
|
||||
const onConfirm = () =>{
|
||||
dispatch(deleteCollection(collection.uid))
|
||||
.then(() => {
|
||||
toast.success("Collection deleted");
|
||||
})
|
||||
.catch(() => toast.error("An error occured while deleting the collection"));
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<Modal
|
||||
size="sm"
|
||||
title="Delete Collection"
|
||||
confirmText="Delete"
|
||||
handleConfirm={onConfirm}
|
||||
handleCancel={onClose}
|
||||
>
|
||||
Are you sure you want to delete the collection <span className="font-semibold">{collection.name}</span> ?
|
||||
</Modal>
|
||||
</StyledWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeleteCollection;
|
@ -44,6 +44,14 @@ const Wrapper = styled.div`
|
||||
top: -0.625rem;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
div.dropdown-item.delete-collection {
|
||||
color: var(--color-text-danger);
|
||||
&:hover {
|
||||
background-color: var(--color-background-danger);
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -3,7 +3,7 @@ import classnames from 'classnames';
|
||||
import filter from 'lodash/filter';
|
||||
import { IconChevronRight, IconDots } from '@tabler/icons';
|
||||
import Dropdown from 'components/Dropdown';
|
||||
import { collectionClicked, removeCollection } from 'providers/ReduxStore/slices/collections';
|
||||
import { collectionClicked } from 'providers/ReduxStore/slices/collections';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import NewRequest from 'components/Sidebar/NewRequest';
|
||||
import NewFolder from 'components/Sidebar/NewFolder';
|
||||
@ -12,23 +12,17 @@ import { doesCollectionHaveItemsMatchingSearchText } from 'utils/collections/sea
|
||||
import { isItemAFolder, isItemARequest } from 'utils/collections';
|
||||
|
||||
import RenameCollection from './RenameCollection';
|
||||
import DeleteCollection from './DeleteCollection';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const Collection = ({collection, searchText}) => {
|
||||
const [showNewFolderModal, setShowNewFolderModal] = useState(false);
|
||||
const [showNewRequestModal, setShowNewRequestModal] = useState(false);
|
||||
const [showRenameCollectionModal, setShowRenameCollectionModal] = useState(false);
|
||||
const [showDeleteCollectionModal, setShowDeleteCollectionModal] = useState(false);
|
||||
const [collectionIsCollapsed, setCollectionIsCollapsed] = useState(collection.collapsed);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
if (searchText && searchText.length) {
|
||||
setCollectionIsCollapsed(false);
|
||||
} else {
|
||||
setCollectionIsCollapsed(collection.collapsed);
|
||||
}
|
||||
}, [searchText, collection]);
|
||||
|
||||
const menuDropdownTippyRef = useRef();
|
||||
const onMenuDropdownCreate = (ref) => menuDropdownTippyRef.current = ref;
|
||||
const MenuIcon = forwardRef((props, ref) => {
|
||||
@ -39,6 +33,14 @@ const Collection = ({collection, searchText}) => {
|
||||
);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (searchText && searchText.length) {
|
||||
setCollectionIsCollapsed(false);
|
||||
} else {
|
||||
setCollectionIsCollapsed(collection.collapsed);
|
||||
}
|
||||
}, [searchText, collection]);
|
||||
|
||||
const iconClassName = classnames({
|
||||
'rotate-90': !collectionIsCollapsed
|
||||
});
|
||||
@ -61,6 +63,7 @@ const Collection = ({collection, searchText}) => {
|
||||
{showNewRequestModal && <NewRequest collection={collection} onClose={() => setShowNewRequestModal(false)}/>}
|
||||
{showNewFolderModal && <NewFolder collection={collection} onClose={() => setShowNewFolderModal(false)}/>}
|
||||
{showRenameCollectionModal && <RenameCollection collection={collection} onClose={() => setShowRenameCollectionModal(false)}/>}
|
||||
{showDeleteCollectionModal && <DeleteCollection collection={collection} onClose={() => setShowDeleteCollectionModal(false)}/>}
|
||||
<div className="flex py-1 collection-name items-center">
|
||||
<div className="flex flex-grow items-center" onClick={handleClick}>
|
||||
<IconChevronRight size={16} strokeWidth={2} className={iconClassName} style={{width:16, color: 'rgb(160 160 160)'}}/>
|
||||
@ -85,17 +88,16 @@ const Collection = ({collection, searchText}) => {
|
||||
New Folder
|
||||
</div>
|
||||
<div className="dropdown-item" onClick={(e) => {
|
||||
dispatch(removeCollection(collection.uid));
|
||||
menuDropdownTippyRef.current.hide();
|
||||
setShowRenameCollectionModal(true);
|
||||
}}>
|
||||
Rename
|
||||
</div>
|
||||
<div className="dropdown-item" onClick={(e) => {
|
||||
dispatch(removeCollection(collection.uid));
|
||||
<div className="dropdown-item delete-collection" onClick={(e) => {
|
||||
menuDropdownTippyRef.current.hide();
|
||||
setShowDeleteCollectionModal(true);
|
||||
}}>
|
||||
Remove
|
||||
Delete
|
||||
</div>
|
||||
</Dropdown>
|
||||
</div>
|
||||
|
@ -1,9 +1,9 @@
|
||||
import React, { useState, forwardRef, useRef } from 'react';
|
||||
import Toast from 'components/Toast';
|
||||
import toast from 'react-hot-toast';
|
||||
import Dropdown from 'components/Dropdown';
|
||||
import Bruno from 'components/Bruno';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { createCollection } from 'providers/ReduxStore/slices/collections';
|
||||
import { createCollection } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import { showHomePage } from 'providers/ReduxStore/slices/app';
|
||||
import { IconDots } from '@tabler/icons';
|
||||
import CreateCollection from '../CreateCollection';
|
||||
@ -11,7 +11,6 @@ import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const TitleBar = () => {
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
const [showToast, setShowToast] = useState({show: false});
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const menuDropdownTippyRef = useRef();
|
||||
@ -25,17 +24,19 @@ const TitleBar = () => {
|
||||
});
|
||||
|
||||
const handleCancel = () => setModalOpen(false);
|
||||
const handleCloseToast = () => setShowToast({show: false});
|
||||
const handleTitleClick = () => dispatch(showHomePage());
|
||||
|
||||
const handleConfirm = (values) => {
|
||||
setModalOpen(false);
|
||||
dispatch(createCollection(values.collectionName, values.collectionLocation));
|
||||
dispatch(createCollection(values.collectionName))
|
||||
.then(() => {
|
||||
toast.success("Collection created");
|
||||
})
|
||||
.catch(() => toast.error("An error occured while creating the collection"));
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledWrapper className="px-2 py-2">
|
||||
{showToast.show && <Toast text={showToast.text} type={showToast.type} duration={showToast.duration} handleClose={handleCloseToast}/>}
|
||||
{modalOpen ? (
|
||||
<CreateCollection
|
||||
handleCancel={handleCancel}
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
IconDeviceDesktop
|
||||
} from '@tabler/icons';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { createCollection } from 'providers/ReduxStore/slices/collections';
|
||||
import { createCollection } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import Bruno from 'components/Bruno';
|
||||
import CreateCollection from 'components/Sidebar/CreateCollection';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
@ -22,7 +22,11 @@ const Welcome = () => {
|
||||
const handleCancel = () => setModalOpen(false);
|
||||
const handleConfirm = (values) => {
|
||||
setModalOpen(false);
|
||||
dispatch(createCollection(values.collectionName, values.collectionLocation));
|
||||
dispatch(createCollection(values.collectionName))
|
||||
.then(() => {
|
||||
toast.success("Collection created");
|
||||
})
|
||||
.catch(() => toast.error("An error occured while creating the collection"));
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -1,18 +1,21 @@
|
||||
import React, { useState } from 'react';
|
||||
import { IconEdit, IconTrash } from "@tabler/icons";
|
||||
import RenameCollection from 'components/Sidebar/Collections/Collection/RenameCollection';
|
||||
import DeleteCollection from 'components/Sidebar/Collections/Collection/DeleteCollection';
|
||||
|
||||
export default function CollectionItem({collection}) {
|
||||
const [showRenameCollectionModal, setShowRenameCollectionModal] = useState(false);
|
||||
const [showDeleteCollectionModal, setShowDeleteCollectionModal] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
{showRenameCollectionModal && <RenameCollection collection={collection} onClose={() => setShowRenameCollectionModal(false)}/>}
|
||||
{showDeleteCollectionModal && <DeleteCollection collection={collection} onClose={() => setShowDeleteCollectionModal(false)}/>}
|
||||
<div className="flex justify-between items-baseline mb-2 collection-list-item">
|
||||
<li style={{listStyle: 'none'}} className="collection-name">{collection.name}</li>
|
||||
<div className="flex gap-x-4" >
|
||||
<IconEdit className="cursor-pointer" size={20} strokeWidth={1.5} onClick={() => setShowRenameCollectionModal(true)}/>
|
||||
<IconTrash className="cursor-pointer" size={20} strokeWidth={1.5}/>
|
||||
<IconTrash className="cursor-pointer" size={20} strokeWidth={1.5} onClick={() => setShowDeleteCollectionModal(true)}/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
@ -1,15 +1,36 @@
|
||||
import { uuid } from 'utils/common';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import {
|
||||
findCollectionByUid,
|
||||
findItemInCollection,
|
||||
recursivelyGetAllItemUids,
|
||||
transformCollectionToSaveToIdb
|
||||
} from 'utils/collections';
|
||||
import { saveCollectionToIdb } from 'utils/idb';
|
||||
import { saveCollectionToIdb, deleteCollectionInIdb } from 'utils/idb';
|
||||
|
||||
import {
|
||||
_renameCollection
|
||||
createCollection as _createCollection,
|
||||
renameCollection as _renameCollection,
|
||||
deleteCollection as _deleteCollection,
|
||||
} from './index';
|
||||
|
||||
import { closeTabs } from 'providers/ReduxStore/slices/tabs';
|
||||
|
||||
export const createCollection = (collectionName) => (dispatch) => {
|
||||
const newCollection = {
|
||||
uid: uuid(),
|
||||
name: collectionName,
|
||||
items: [],
|
||||
environments: [],
|
||||
};
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
saveCollectionToIdb(window.__idb, newCollection)
|
||||
.then(() => dispatch(_createCollection(newCollection)))
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
export const renameCollection = (newName, collectionUid) => (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const collection = findCollectionByUid(state.collections.collections, collectionUid);
|
||||
@ -30,4 +51,27 @@ export const renameCollection = (newName, collectionUid) => (dispatch, getState)
|
||||
})
|
||||
.catch((err) => console.log(err));
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteCollection = (collectionUid) => (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const collection = findCollectionByUid(state.collections.collections, collectionUid);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
if(!collection) {
|
||||
return reject('collection not found');
|
||||
}
|
||||
|
||||
deleteCollectionInIdb(window.__idb, collection.uid)
|
||||
.then(() => {
|
||||
dispatch(closeTabs({
|
||||
tabUids: recursivelyGetAllItemUids(collection.items)
|
||||
}));
|
||||
dispatch(_deleteCollection({
|
||||
collectionUid: collectionUid
|
||||
}));
|
||||
})
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
@ -1,4 +1,3 @@
|
||||
import path from 'path';
|
||||
import { uuid } from 'utils/common';
|
||||
import find from 'lodash/find';
|
||||
import concat from 'lodash/concat';
|
||||
@ -37,16 +36,19 @@ export const collectionsSlice = createSlice({
|
||||
each(action.payload.collections, (c) => addDepth(c.items));
|
||||
state.collections = action.payload.collections;
|
||||
},
|
||||
_createCollection: (state, action) => {
|
||||
createCollection: (state, action) => {
|
||||
state.collections.push(action.payload);
|
||||
},
|
||||
_renameCollection: (state, action) => {
|
||||
renameCollection: (state, action) => {
|
||||
const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
|
||||
|
||||
if(collection) {
|
||||
collection.name = action.payload.newName;
|
||||
}
|
||||
},
|
||||
deleteCollection: (state, action) => {
|
||||
state.collections = filter(state.collections, c => c.uid !== action.payload.collectionUid);
|
||||
},
|
||||
_newItem: (state, action) => {
|
||||
const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
|
||||
|
||||
@ -525,8 +527,9 @@ export const collectionsSlice = createSlice({
|
||||
});
|
||||
|
||||
export const {
|
||||
_createCollection,
|
||||
_renameCollection,
|
||||
createCollection,
|
||||
renameCollection,
|
||||
deleteCollection,
|
||||
_loadCollections,
|
||||
_newItem,
|
||||
_deleteItem,
|
||||
@ -564,19 +567,6 @@ export const loadCollectionsFromIdb = () => (dispatch) => {
|
||||
.catch((err) => console.log(err));
|
||||
};
|
||||
|
||||
export const createCollection = (collectionName) => (dispatch) => {
|
||||
const newCollection = {
|
||||
uid: uuid(),
|
||||
name: collectionName,
|
||||
items: [],
|
||||
environments: [],
|
||||
};
|
||||
|
||||
saveCollectionToIdb(window.__idb, newCollection)
|
||||
.then(() => dispatch(_createCollection(newCollection)))
|
||||
.catch((err) => console.log(err));
|
||||
};
|
||||
|
||||
export const sendRequest = (item, collectionUid) => (dispatch) => {
|
||||
dispatch(_requestSent({
|
||||
itemUid: item.uid,
|
||||
@ -803,8 +793,4 @@ export const cloneItem = (newName, itemUid, collectionUid) => (dispatch, getStat
|
||||
}
|
||||
};
|
||||
|
||||
export const removeCollection = (collectionPath) => () => {
|
||||
console.log('removeCollection');
|
||||
};
|
||||
|
||||
export default collectionsSlice.reducer;
|
||||
|
@ -21,6 +21,20 @@ export const saveCollectionToIdb = (connection, collection) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteCollectionInIdb = (connection, collectionUid) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
connection
|
||||
.then((db) => {
|
||||
let tx = db.transaction(`collection`, 'readwrite');
|
||||
tx.objectStore('collection').delete(collectionUid);
|
||||
|
||||
tx.oncomplete = () => resolve();
|
||||
tx.onerror = () => reject(tx.error);
|
||||
})
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export const getCollectionsFromIdb = (connection) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
connection
|
||||
|
Loading…
Reference in New Issue
Block a user