diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/DeleteCollection/StyledWrapper.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/DeleteCollection/StyledWrapper.js new file mode 100644 index 00000000..48b87421 --- /dev/null +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/DeleteCollection/StyledWrapper.js @@ -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; diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/DeleteCollection/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/DeleteCollection/index.js new file mode 100644 index 00000000..27306bf9 --- /dev/null +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/DeleteCollection/index.js @@ -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 ( + + + Are you sure you want to delete the collection {collection.name} ? + + + ); +}; + +export default DeleteCollection; diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/StyledWrapper.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/StyledWrapper.js index 1779008f..aa67c369 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/StyledWrapper.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/StyledWrapper.js @@ -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; + } + } } `; diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js index 7f617355..22fe299e 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js @@ -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 && setShowNewRequestModal(false)}/>} {showNewFolderModal && setShowNewFolderModal(false)}/>} {showRenameCollectionModal && setShowRenameCollectionModal(false)}/>} + {showDeleteCollectionModal && setShowDeleteCollectionModal(false)}/>}
@@ -85,17 +88,16 @@ const Collection = ({collection, searchText}) => { New Folder
{ - dispatch(removeCollection(collection.uid)); menuDropdownTippyRef.current.hide(); setShowRenameCollectionModal(true); }}> Rename
-
{ - dispatch(removeCollection(collection.uid)); +
{ menuDropdownTippyRef.current.hide(); + setShowDeleteCollectionModal(true); }}> - Remove + Delete
diff --git a/packages/bruno-app/src/components/Sidebar/TitleBar/index.js b/packages/bruno-app/src/components/Sidebar/TitleBar/index.js index baa63617..0e38eab8 100644 --- a/packages/bruno-app/src/components/Sidebar/TitleBar/index.js +++ b/packages/bruno-app/src/components/Sidebar/TitleBar/index.js @@ -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 ( - {showToast.show && } {modalOpen ? ( { 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 ( diff --git a/packages/bruno-app/src/pageComponents/Collections/CollectionItem/index.js b/packages/bruno-app/src/pageComponents/Collections/CollectionItem/index.js index 906a4e2f..e0b10aff 100644 --- a/packages/bruno-app/src/pageComponents/Collections/CollectionItem/index.js +++ b/packages/bruno-app/src/pageComponents/Collections/CollectionItem/index.js @@ -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 && setShowRenameCollectionModal(false)}/>} + {showDeleteCollectionModal && setShowDeleteCollectionModal(false)}/>}
  • {collection.name}
  • setShowRenameCollectionModal(true)}/> - + setShowDeleteCollectionModal(true)}/>
    diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js index 6c1f88e3..debe0c86 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js @@ -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); + }); }; \ No newline at end of file diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js index f8db4bd5..6f4985fa 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js @@ -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; diff --git a/packages/bruno-app/src/utils/idb/index.js b/packages/bruno-app/src/utils/idb/index.js index be0766ae..f90b1afc 100644 --- a/packages/bruno-app/src/utils/idb/index.js +++ b/packages/bruno-app/src/utils/idb/index.js @@ -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