feat: delete collections

This commit is contained in:
Anoop M D 2022-10-11 03:20:50 +05:30
parent adc6be031d
commit 02ff85cc57
10 changed files with 157 additions and 47 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;
}
}
}
`;

View File

@ -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>

View File

@ -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}

View File

@ -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 (

View File

@ -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>
</>

View File

@ -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);
});
};

View File

@ -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;

View File

@ -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