diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSelector/StyledWrapper.js b/packages/bruno-app/src/components/Environments/EnvironmentSelector/StyledWrapper.js index 4db3ada0..a4dc148c 100644 --- a/packages/bruno-app/src/components/Environments/EnvironmentSelector/StyledWrapper.js +++ b/packages/bruno-app/src/components/Environments/EnvironmentSelector/StyledWrapper.js @@ -2,7 +2,7 @@ import styled from 'styled-components'; const Wrapper = styled.div` .current-enviroment { - background-color: ${(props) => props.theme.sidebar.workspace.bg}; + background-color: ${(props) => props.theme.sidebar.badge.bg}; border-radius: 15px; .caret { diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSelector/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSelector/index.js index 311648cc..7bd3bc69 100644 --- a/packages/bruno-app/src/components/Environments/EnvironmentSelector/index.js +++ b/packages/bruno-app/src/components/Environments/EnvironmentSelector/index.js @@ -69,7 +69,7 @@ const EnvironmentSelector = ({ collection }) => {
- Settings + Configure diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js index a2dc0262..fee5a84c 100644 --- a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js +++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js @@ -7,7 +7,6 @@ import DeleteEnvironment from '../../DeleteEnvironment'; const EnvironmentDetails = ({ environment, collection }) => { const [openEditModal, setOpenEditModal] = useState(false); const [openDeleteModal, setOpenDeleteModal] = useState(false); - console.log(environment); return (
diff --git a/packages/bruno-app/src/components/ResponsePane/NetworkError/index.js b/packages/bruno-app/src/components/ResponsePane/NetworkError/index.js index 906d0667..2969e8dc 100644 --- a/packages/bruno-app/src/components/ResponsePane/NetworkError/index.js +++ b/packages/bruno-app/src/components/ResponsePane/NetworkError/index.js @@ -7,9 +7,6 @@ const NetworkError = ({ onClose }) => {

Network Error

-

- Please note that if you are using Bruno on the web, then the api you are connecting to must allow CORS. If not, please use the chrome extension or the desktop app -

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 deleted file mode 100644 index 48b87421..00000000 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/DeleteCollection/StyledWrapper.js +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index dbab75a9..00000000 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/DeleteCollection/index.js +++ /dev/null @@ -1,27 +0,0 @@ -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/RemoveLocalCollection/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/index.js similarity index 71% rename from packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveLocalCollection/index.js rename to packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/index.js index 5de2eac2..ec4cfae4 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveLocalCollection/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/index.js @@ -2,13 +2,13 @@ import React from 'react'; import toast from 'react-hot-toast'; import Modal from 'components/Modal'; import { useDispatch } from 'react-redux'; -import { removeLocalCollection } from 'providers/ReduxStore/slices/collections/actions'; +import { removeCollection } from 'providers/ReduxStore/slices/collections/actions'; -const RemoveLocalCollection = ({ onClose, collection }) => { +const RemoveCollection = ({ onClose, collection }) => { const dispatch = useDispatch(); const onConfirm = () => { - dispatch(removeLocalCollection(collection.uid)) + dispatch(removeCollection(collection.uid)) .then(() => { toast.success('Collection removed'); onClose(); @@ -23,4 +23,4 @@ const RemoveLocalCollection = ({ onClose, collection }) => { ); }; -export default RemoveLocalCollection; +export default RemoveCollection; diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollectionFromWorkspace/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollectionFromWorkspace/index.js deleted file mode 100644 index ed3b314b..00000000 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollectionFromWorkspace/index.js +++ /dev/null @@ -1,34 +0,0 @@ -import React from 'react'; -import toast from 'react-hot-toast'; -import Modal from 'components/Modal'; -import { useSelector, useDispatch } from 'react-redux'; -import { recursivelyGetAllItemUids } from 'utils/collections'; -import { removeCollectionFromWorkspace } from 'providers/ReduxStore/slices/workspaces/actions'; -import { removeLocalCollection } from 'providers/ReduxStore/slices/collections/actions'; -import { closeTabs } from 'providers/ReduxStore/slices/tabs'; - -const RemoveCollectionFromWorkspace = ({ onClose, collection }) => { - const dispatch = useDispatch(); - const { activeWorkspaceUid } = useSelector((state) => state.workspaces); - - const onConfirm = () => { - dispatch(removeCollectionFromWorkspace(activeWorkspaceUid, collection.uid)) - .then(() => { - dispatch( - closeTabs({ - tabUids: recursivelyGetAllItemUids(collection.items) - }) - ); - }) - .then(() => toast.success('Collection removed from workspace')) - .catch((err) => console.log(err) && toast.error('An error occured while removing the collection')); - }; - - return ( - - Are you sure you want to remove the collection {collection.name} from this workspace? - - ); -}; - -export default RemoveCollectionFromWorkspace; 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 7520565a..1dd20256 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js @@ -11,23 +11,19 @@ import { useDispatch } from 'react-redux'; import NewRequest from 'components/Sidebar/NewRequest'; import NewFolder from 'components/Sidebar/NewFolder'; import CollectionItem from './CollectionItem'; -import RemoveCollectionFromWorkspace from './RemoveCollectionFromWorkspace'; -import RemoveLocalCollection from './RemoveLocalCollection'; +import RemoveCollection from './RemoveCollection'; import { doesCollectionHaveItemsMatchingSearchText } from 'utils/collections/search'; -import { isItemAFolder, isItemARequest, transformCollectionToSaveToIdb, isLocalCollection } from 'utils/collections'; +import { isItemAFolder, isItemARequest, transformCollectionToSaveToIdb } from 'utils/collections'; import exportCollection from 'utils/collections/export'; 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 [showRemoveCollectionFromWSModal, setShowRemoveCollectionFromWSModal] = useState(false); - const [showRemoveLocalCollectionModal, setShowRemoveLocalCollectionModal] = useState(false); - const [showDeleteCollectionModal, setShowDeleteCollectionModal] = useState(false); + const [showRemoveCollectionModal, setShowRemoveCollectionModal] = useState(false); const [collectionIsCollapsed, setCollectionIsCollapsed] = useState(collection.collapsed); const dispatch = useDispatch(); @@ -71,8 +67,6 @@ const Collection = ({ collection, searchText }) => { exportCollection(transformCollectionToSaveToIdb(collectionCopy)); }; - const isLocal = isLocalCollection(collection); - // const [{ isOver }, drop] = useDrop({ // accept: 'COLLECTION_ITEM', // drop: (draggedItem) => { @@ -93,9 +87,7 @@ const Collection = ({ collection, searchText }) => { {showNewRequestModal && setShowNewRequestModal(false)} />} {showNewFolderModal && setShowNewFolderModal(false)} />} {showRenameCollectionModal && setShowRenameCollectionModal(false)} />} - {showRemoveCollectionFromWSModal && setShowRemoveCollectionFromWSModal(false)} />} - {showDeleteCollectionModal && setShowDeleteCollectionModal(false)} />} - {showRemoveLocalCollectionModal && setShowRemoveLocalCollectionModal(false)} />} + {showRemoveCollectionModal && setShowRemoveCollectionModal(false)} />}
@@ -121,17 +113,16 @@ const Collection = ({ collection, searchText }) => { > New Folder
- {!isLocal ? ( -
{ - menuDropdownTippyRef.current.hide(); - setShowRenameCollectionModal(true); - }} - > - Rename -
- ) : null} + {/* Todo: implement rename collection */} + {/*
{ + menuDropdownTippyRef.current.hide(); + setShowRenameCollectionModal(true); + }} + > + Rename +
*/}
{ @@ -141,38 +132,15 @@ const Collection = ({ collection, searchText }) => { > Export
- {!isLocal ? ( -
{ - menuDropdownTippyRef.current.hide(); - setShowRemoveCollectionFromWSModal(true); - }} - > - Remove from Workspace -
- ) : ( -
{ - menuDropdownTippyRef.current.hide(); - setShowRemoveLocalCollectionModal(true); - }} - > - Remove -
- )} - {!isLocal ? ( -
{ - menuDropdownTippyRef.current.hide(); - setShowDeleteCollectionModal(true); - }} - > - Delete -
- ) : null} +
{ + menuDropdownTippyRef.current.hide(); + setShowRemoveCollectionModal(true); + }} + > + Remove +
diff --git a/packages/bruno-app/src/components/Sidebar/Collections/CreateOrAddCollection/index.js b/packages/bruno-app/src/components/Sidebar/Collections/CreateOrAddCollection/index.js deleted file mode 100644 index 6e0c071f..00000000 --- a/packages/bruno-app/src/components/Sidebar/Collections/CreateOrAddCollection/index.js +++ /dev/null @@ -1,71 +0,0 @@ -import { useState } from 'react'; -import { useTheme } from '../../../../providers/Theme'; -import { useSelector, useDispatch } from 'react-redux'; -import { createCollection } from 'providers/ReduxStore/slices/collections/actions'; -import { addCollectionToWorkspace } from 'providers/ReduxStore/slices/workspaces/actions'; - -import toast from 'react-hot-toast'; -import styled from 'styled-components'; -import CreateCollection from 'components/Sidebar/CreateCollection'; -import SelectCollection from 'components/Sidebar/Collections/SelectCollection'; -import StyledWrapper from './StyledWrapper'; - -const LinkStyle = styled.span` - color: ${(props) => props.theme['text-link']}; -`; - -const CreateOrAddCollection = () => { - const { theme } = useTheme(); - const dispatch = useDispatch(); - const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false); - const [addCollectionToWSModalOpen, setAddCollectionToWSModalOpen] = useState(false); - const { activeWorkspaceUid } = useSelector((state) => state.workspaces); - - const handleCreateCollection = (values) => { - setCreateCollectionModalOpen(false); - dispatch(createCollection(values.collectionName)) - .then(() => { - toast.success('Collection created'); - }) - .catch(() => toast.error('An error occured while creating the collection')); - }; - - const handleAddCollectionToWorkspace = (collectionUid) => { - setAddCollectionToWSModalOpen(false); - dispatch(addCollectionToWorkspace(activeWorkspaceUid, collectionUid)) - .then(() => { - toast.success('Collection added to workspace'); - }) - .catch(() => toast.error('An error occured while adding collection to workspace')); - }; - - const CreateLink = () => ( - setCreateCollectionModalOpen(true)}> - Create - - ); - const AddLink = () => ( - setAddCollectionToWSModalOpen(true)}> - Add - - ); - - return ( - - {createCollectionModalOpen ? setCreateCollectionModalOpen(false)} handleConfirm={handleCreateCollection} /> : null} - - {addCollectionToWSModalOpen ? ( - setAddCollectionToWSModalOpen(false)} onSelect={handleAddCollectionToWorkspace} /> - ) : null} - -
-
No collections found.
-
- or Collection to Workspace. -
-
-
- ); -}; - -export default CreateOrAddCollection; diff --git a/packages/bruno-app/src/components/Sidebar/Collections/CreateOrAddCollection/StyledWrapper.js b/packages/bruno-app/src/components/Sidebar/Collections/CreateOrOpenCollection/StyledWrapper.js similarity index 100% rename from packages/bruno-app/src/components/Sidebar/Collections/CreateOrAddCollection/StyledWrapper.js rename to packages/bruno-app/src/components/Sidebar/Collections/CreateOrOpenCollection/StyledWrapper.js diff --git a/packages/bruno-app/src/components/Sidebar/Collections/CreateOrOpenCollection/index.js b/packages/bruno-app/src/components/Sidebar/Collections/CreateOrOpenCollection/index.js new file mode 100644 index 00000000..4874b5ce --- /dev/null +++ b/packages/bruno-app/src/components/Sidebar/Collections/CreateOrOpenCollection/index.js @@ -0,0 +1,48 @@ +import { useState } from 'react'; +import { useTheme } from '../../../../providers/Theme'; +import { useDispatch } from 'react-redux'; +import { openCollection } from 'providers/ReduxStore/slices/collections/actions'; + +import toast from 'react-hot-toast'; +import styled from 'styled-components'; +import CreateCollection from 'components/Sidebar/CreateCollection'; +import StyledWrapper from './StyledWrapper'; + +const LinkStyle = styled.span` + color: ${(props) => props.theme['text-link']}; +`; + +const CreateOrOpenCollection = () => { + const { theme } = useTheme(); + const dispatch = useDispatch(); + const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false); + + const handleOpenCollection = () => { + dispatch(openCollection()).catch((err) => console.log(err) && toast.error('An error occured while opening the collection')); + }; + const CreateLink = () => ( + setCreateCollectionModalOpen(true)}> + Create + + ); + const OpenLink = () => ( + handleOpenCollection(true)}> + Open + + ); + + return ( + + {createCollectionModalOpen ? setCreateCollectionModalOpen(false)} /> : null} + +
+
No collections found.
+
+ or Collection. +
+
+
+ ); +}; + +export default CreateOrOpenCollection; diff --git a/packages/bruno-app/src/components/Sidebar/Collections/SelectCollection/index.js b/packages/bruno-app/src/components/Sidebar/Collections/SelectCollection/index.js index a7cccf73..525109b3 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/SelectCollection/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/SelectCollection/index.js @@ -1,21 +1,18 @@ import React from 'react'; -import filter from 'lodash/filter'; import Modal from 'components/Modal/index'; import { IconFiles } from '@tabler/icons'; import { useSelector } from 'react-redux'; -import { isLocalCollection } from 'utils/collections'; import StyledWrapper from './StyledWrapper'; const SelectCollection = ({ onClose, onSelect, title }) => { const { collections } = useSelector((state) => state.collections); - const collectionsToDisplay = filter(collections, (c) => !isLocalCollection(c)); return (
    - {collectionsToDisplay && collectionsToDisplay.length ? ( - collectionsToDisplay.map((c) => ( + {collections && collections.length ? ( + collections.map((c) => (
    onSelect(c.uid)}> {c.name}
    diff --git a/packages/bruno-app/src/components/Workspaces/WorkspaceSelector/StyledWrapper.js b/packages/bruno-app/src/components/Sidebar/Collections/StyledWrapper.js similarity index 63% rename from packages/bruno-app/src/components/Workspaces/WorkspaceSelector/StyledWrapper.js rename to packages/bruno-app/src/components/Sidebar/Collections/StyledWrapper.js index b81097d8..c38bfc4e 100644 --- a/packages/bruno-app/src/components/Workspaces/WorkspaceSelector/StyledWrapper.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/StyledWrapper.js @@ -1,9 +1,9 @@ import styled from 'styled-components'; const Wrapper = styled.div` - .current-workspace { + .collections-badge { margin-inline: 0.5rem; - background-color: ${(props) => props.theme.sidebar.workspace.bg}; + background-color: ${(props) => props.theme.sidebar.badge.bg}; border-radius: 5px; .caret { @@ -12,10 +12,6 @@ const Wrapper = styled.div` fill: rgb(140, 140, 140); } } - - div[data-tippy-root] { - width: calc(100% - 1rem); - } `; export default Wrapper; diff --git a/packages/bruno-app/src/components/Sidebar/Collections/index.js b/packages/bruno-app/src/components/Sidebar/Collections/index.js index e06eae57..e401174d 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/index.js @@ -1,42 +1,80 @@ -import React from 'react'; +import React, { useState } from 'react'; import { useSelector } from 'react-redux'; +import { IconSearch, IconFolders } from '@tabler/icons'; +import Collection from '../Collections/Collection'; +import CreateCollection from '../CreateCollection'; +import StyledWrapper from './StyledWrapper'; +import CreateOrOpenCollection from './CreateOrOpenCollection'; import { DndProvider } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; -import find from 'lodash/find'; -import filter from 'lodash/filter'; -import Collection from './Collection'; -import CreateOrAddCollection from './CreateOrAddCollection'; -import { findCollectionInWorkspace } from 'utils/workspaces'; -import { isLocalCollection } from 'utils/collections'; - -const Collections = ({ searchText }) => { - const { collections } = useSelector((state) => state.collections); - const { workspaces, activeWorkspaceUid } = useSelector((state) => state.workspaces); - const activeWorkspace = find(workspaces, (w) => w.uid === activeWorkspaceUid); - - if (!activeWorkspace) { - return null; - } - - const collectionToDisplay = filter(collections, (c) => findCollectionInWorkspace(activeWorkspace, c.uid) && !isLocalCollection(c)); - - if (!collectionToDisplay || !collectionToDisplay.length) { - return ; - } +const CollectionsBadge = () => { return ( -
    - {collectionToDisplay && collectionToDisplay.length - ? collectionToDisplay.map((c) => { - return ( - - - - ); - }) - : null} +
    +
    + + + + Collections +
    ); }; +const Collections = () => { + const [searchText, setSearchText] = useState(''); + const { collections } = useSelector((state) => state.collections); + const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false); + + if (!collections || !collections.length) { + return ( + + + + + ); + } + + return ( + + {createCollectionModalOpen ? setCreateCollectionModalOpen(false)} /> : null} + + + +
    +
    + + + +
    + setSearchText(e.target.value.toLowerCase())} + /> +
    + +
    + {collections && collections.length + ? collections.map((c) => { + return ( + + + + ); + }) + : null} +
    +
    + ); +}; + export default Collections; + diff --git a/packages/bruno-app/src/components/Sidebar/CreateCollection/index.js b/packages/bruno-app/src/components/Sidebar/CreateCollection/index.js index a168337e..b5104cfa 100644 --- a/packages/bruno-app/src/components/Sidebar/CreateCollection/index.js +++ b/packages/bruno-app/src/components/Sidebar/CreateCollection/index.js @@ -2,16 +2,14 @@ import React, { useRef, useEffect } from 'react'; import { useDispatch } from 'react-redux'; import { useFormik } from 'formik'; import * as Yup from 'yup'; -import { browserLocalDirectory } from 'providers/ReduxStore/slices/collections/actions'; -import { isElectron } from 'utils/common/platform'; -import { createCollection, createLocalCollection } from 'providers/ReduxStore/slices/collections/actions'; +import { browseDirectory } from 'providers/ReduxStore/slices/collections/actions'; +import { createCollection } from 'providers/ReduxStore/slices/collections/actions'; import toast from 'react-hot-toast'; import Modal from 'components/Modal'; -const CreateCollection = ({ onClose, isLocal }) => { +const CreateCollection = ({ onClose }) => { const inputRef = useRef(); const dispatch = useDispatch(); - const isPlatformElectron = isElectron(); const formik = useFormik({ enableReinitialize: true, @@ -23,8 +21,7 @@ const CreateCollection = ({ onClose, isLocal }) => { collectionName: Yup.string().min(1, 'must be atleast 1 characters').max(50, 'must be 50 characters or less').required('name is required') }), onSubmit: (values) => { - const action = isLocal && isPlatformElectron ? createLocalCollection : createCollection; - dispatch(action(values.collectionName, values.collectionLocation)) + dispatch(createCollection(values.collectionName, values.collectionLocation)) .then(() => { toast.success('Collection created'); onClose(); @@ -34,7 +31,7 @@ const CreateCollection = ({ onClose, isLocal }) => { }); const browse = () => { - dispatch(browserLocalDirectory()) + dispatch(browseDirectory()) .then((dirPath) => { formik.setFieldValue('collectionLocation', dirPath); }) @@ -74,37 +71,33 @@ const CreateCollection = ({ onClose, isLocal }) => { /> {formik.touched.collectionName && formik.errors.collectionName ?
    {formik.errors.collectionName}
    : null} - {isLocal && isPlatformElectron ? ( - <> - - - - ) : null} - {isLocal && isPlatformElectron && formik.touched.collectionLocation && formik.errors.collectionLocation ? ( + <> + + + + {formik.touched.collectionLocation && formik.errors.collectionLocation ? (
    {formik.errors.collectionLocation}
    ) : null} - {isLocal && isPlatformElectron ? ( -
    - - Browse - -
    - ) : null} +
    + + Browse + +
    diff --git a/packages/bruno-app/src/components/Sidebar/ImportCollection/index.js b/packages/bruno-app/src/components/Sidebar/ImportCollection/index.js index e922d796..8fc8cb32 100644 --- a/packages/bruno-app/src/components/Sidebar/ImportCollection/index.js +++ b/packages/bruno-app/src/components/Sidebar/ImportCollection/index.js @@ -1,24 +1,14 @@ import React from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import { collectionImported } from 'providers/ReduxStore/slices/collections'; import importBrunoCollection from 'utils/importers/bruno-collection'; import importPostmanCollection from 'utils/importers/postman-collection'; -import { addCollectionToWorkspace } from 'providers/ReduxStore/slices/workspaces/actions'; import { toastError } from 'utils/common/error'; -import toast from 'react-hot-toast'; import Modal from 'components/Modal'; -const ImportCollection = ({ onClose }) => { - const dispatch = useDispatch(); - const { activeWorkspaceUid } = useSelector((state) => state.workspaces); - +const ImportCollection = ({ onClose, handleSubmit }) => { const handleImportBrunoCollection = () => { importBrunoCollection() .then((collection) => { - dispatch(collectionImported({ collection: collection })); - dispatch(addCollectionToWorkspace(activeWorkspaceUid, collection.uid)); - toast.success('Collection imported successfully'); - onClose(); + handleSubmit(collection); }) .catch((err) => toastError(err, 'Import collection failed')); }; @@ -26,10 +16,7 @@ const ImportCollection = ({ onClose }) => { const handleImportPostmanCollection = () => { importPostmanCollection() .then((collection) => { - dispatch(collectionImported({ collection: collection })); - dispatch(addCollectionToWorkspace(activeWorkspaceUid, collection.uid)); - toast.success('Postman Collection imported successfully'); - onClose(); + handleSubmit(collection); }) .catch((err) => toastError(err, 'Postman Import collection failed')); }; diff --git a/packages/bruno-app/src/components/Sidebar/ImportCollectionLocation/index.js b/packages/bruno-app/src/components/Sidebar/ImportCollectionLocation/index.js new file mode 100644 index 00000000..8f642e5a --- /dev/null +++ b/packages/bruno-app/src/components/Sidebar/ImportCollectionLocation/index.js @@ -0,0 +1,87 @@ +import React, { useRef, useEffect } from 'react'; +import { useDispatch } from 'react-redux'; +import { useFormik } from 'formik'; +import * as Yup from 'yup'; +import { browseDirectory } from 'providers/ReduxStore/slices/collections/actions'; +import Modal from 'components/Modal'; + +const ImportCollectionLocation = ({ onClose, handleSubmit, collectionName }) => { + const inputRef = useRef(); + const dispatch = useDispatch(); + + const formik = useFormik({ + enableReinitialize: true, + initialValues: { + collectionLocation: '' + }, + validationSchema: Yup.object({ + collectionLocation: Yup.string().min(1, 'must be atleast 1 characters').max(500, 'must be 500 characters or less').required('name is required') + }), + onSubmit: (values) => { + console.log('here'); + handleSubmit(values.collectionLocation); + } + }); + + const browse = () => { + dispatch(browseDirectory()) + .then((dirPath) => { + formik.setFieldValue('collectionLocation', dirPath); + }) + .catch((error) => { + formik.setFieldValue('collectionLocation', ''); + console.error(error); + }); + }; + + useEffect(() => { + if (inputRef && inputRef.current) { + inputRef.current.focus(); + } + }, [inputRef]); + + const onSubmit = () => formik.handleSubmit(); + + return ( + +
    +
    + +
    {collectionName}
    + + <> + + + + {formik.touched.collectionLocation && formik.errors.collectionLocation ? ( +
    {formik.errors.collectionLocation}
    + ) : null} + +
    + + Browse + +
    +
    +
    +
    + ); +}; + +export default ImportCollectionLocation; diff --git a/packages/bruno-app/src/components/Sidebar/LocalCollections/StyledWrapper.js b/packages/bruno-app/src/components/Sidebar/LocalCollections/StyledWrapper.js deleted file mode 100644 index b8ba958d..00000000 --- a/packages/bruno-app/src/components/Sidebar/LocalCollections/StyledWrapper.js +++ /dev/null @@ -1,26 +0,0 @@ -import styled from 'styled-components'; - -const Wrapper = styled.div` - .current-workspace { - margin-inline: 0.5rem; - background-color: ${(props) => props.theme.sidebar.workspace.bg}; - border-radius: 5px; - - .caret { - margin-left: 0.25rem; - color: rgb(140, 140, 140); - fill: rgb(140, 140, 140); - } - } - - .muted-message { - color: ${(props) => props.theme.sidebar.muted}; - border-top: solid 1px ${(props) => props.theme.dropdown.seperator}; - } - - div[data-tippy-root] { - width: calc(100% - 1rem); - } -`; - -export default Wrapper; diff --git a/packages/bruno-app/src/components/Sidebar/LocalCollections/index.js b/packages/bruno-app/src/components/Sidebar/LocalCollections/index.js deleted file mode 100644 index 741bc018..00000000 --- a/packages/bruno-app/src/components/Sidebar/LocalCollections/index.js +++ /dev/null @@ -1,79 +0,0 @@ -import React, { useState, useRef, forwardRef } from 'react'; -import filter from 'lodash/filter'; -import { useSelector, useDispatch } from 'react-redux'; -import Dropdown from 'components/Dropdown'; -import { openLocalCollection } from 'providers/ReduxStore/slices/collections/actions'; -import { IconArrowForwardUp, IconCaretDown, IconFolders, IconPlus } from '@tabler/icons'; -import Collection from '../Collections/Collection'; -import CreateCollection from '../CreateCollection'; -import { isLocalCollection } from 'utils/collections'; -import StyledWrapper from './StyledWrapper'; - -const LocalCollections = ({ searchText }) => { - const dropdownTippyRef = useRef(); - const dispatch = useDispatch(); - const { collections } = useSelector((state) => state.collections); - const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false); - - const collectionToDisplay = filter(collections, (c) => isLocalCollection(c)); - - if (!collectionToDisplay || !collectionToDisplay.length) { - return null; - } - - const Icon = forwardRef((props, ref) => { - return ( -
    -
    - - - - Local Collections -
    - -
    - ); - }); - - const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref); - - const handleOpenLocalCollection = () => { - dispatch(openLocalCollection()).catch((err) => console.log(err) && toast.error('An error occured while opening the local collection')); - }; - - return ( - - {createCollectionModalOpen ? setCreateCollectionModalOpen(false)} /> : null} - -
    - } placement="bottom-end"> -
    setCreateCollectionModalOpen(true)}> -
    - -
    - Create Collection -
    -
    -
    - -
    - Open Collection -
    - -
    - Note: Local collections are not tied to a workspace -
    -
    -
    -
    - {collectionToDisplay && collectionToDisplay.length - ? collectionToDisplay.map((c) => { - return ; - }) - : null} -
    -
    - ); -}; - -export default LocalCollections; diff --git a/packages/bruno-app/src/components/Sidebar/TitleBar/StyledWrapper.js b/packages/bruno-app/src/components/Sidebar/TitleBar/StyledWrapper.js index 2cacea5d..f312e534 100644 --- a/packages/bruno-app/src/components/Sidebar/TitleBar/StyledWrapper.js +++ b/packages/bruno-app/src/components/Sidebar/TitleBar/StyledWrapper.js @@ -1,12 +1,6 @@ import styled from 'styled-components'; const StyledWrapper = styled.div` - .local-collections-unavailable { - padding: 0.35rem 0.6rem; - color: ${(props) => props.theme.sidebar.muted}; - border-top: solid 1px ${(props) => props.theme.dropdown.seperator}; - font-size: 11px; - } .collection-dropdown { color: ${(props) => props.theme.sidebar.dropdownIcon.color}; diff --git a/packages/bruno-app/src/components/Sidebar/TitleBar/index.js b/packages/bruno-app/src/components/Sidebar/TitleBar/index.js index 189d9fc3..54224e12 100644 --- a/packages/bruno-app/src/components/Sidebar/TitleBar/index.js +++ b/packages/bruno-app/src/components/Sidebar/TitleBar/index.js @@ -2,27 +2,36 @@ import toast from 'react-hot-toast'; import Bruno from 'components/Bruno'; import Dropdown from 'components/Dropdown'; import CreateCollection from '../CreateCollection'; -import SelectCollection from 'components/Sidebar/Collections/SelectCollection'; import ImportCollection from 'components/Sidebar/ImportCollection'; +import ImportCollectionLocation from 'components/Sidebar/ImportCollectionLocation'; import { IconDots } from '@tabler/icons'; -import { IconFolders } from '@tabler/icons'; -import { isElectron } from 'utils/common/platform'; import { useState, forwardRef, useRef } from 'react'; -import { useSelector, useDispatch } from 'react-redux'; +import { useDispatch } from 'react-redux'; import { showHomePage } from 'providers/ReduxStore/slices/app'; -import { openLocalCollection } from 'providers/ReduxStore/slices/collections/actions'; -import { addCollectionToWorkspace } from 'providers/ReduxStore/slices/workspaces/actions'; +import { openCollection, importCollection } from 'providers/ReduxStore/slices/collections/actions'; import StyledWrapper from './StyledWrapper'; const TitleBar = () => { + const [importedCollection, setImportedCollection] = useState(null); const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false); const [importCollectionModalOpen, setImportCollectionModalOpen] = useState(false); - const [addCollectionToWSModalOpen, setAddCollectionToWSModalOpen] = useState(false); - const { activeWorkspaceUid } = useSelector((state) => state.workspaces); - const isPlatformElectron = isElectron(); + const [importCollectionLocationModalOpen, setImportCollectionLocationModalOpen] = useState(false); const dispatch = useDispatch(); + const handleImportCollection = (collection) => { + setImportedCollection(collection); + setImportCollectionModalOpen(false); + setImportCollectionLocationModalOpen(true); + }; + + const handleImportCollectionLocation = (collectionLocation) => { + dispatch(importCollection(importedCollection, collectionLocation)); + setImportCollectionLocationModalOpen(false); + setImportedCollection(null); + toast.success('Collection imported successfully'); + }; + const menuDropdownTippyRef = useRef(); const onMenuDropdownCreate = (ref) => (menuDropdownTippyRef.current = ref); const MenuIcon = forwardRef((props, ref) => { @@ -35,27 +44,21 @@ const TitleBar = () => { const handleTitleClick = () => dispatch(showHomePage()); - const handleOpenLocalCollection = () => { - dispatch(openLocalCollection()).catch((err) => console.log(err) && toast.error('An error occured while opening the local collection')); - }; - - const handleAddCollectionToWorkspace = (collectionUid) => { - setAddCollectionToWSModalOpen(false); - dispatch(addCollectionToWorkspace(activeWorkspaceUid, collectionUid)) - .then(() => { - toast.success('Collection added to workspace'); - }) - .catch(() => toast.error('An error occured while adding collection to workspace')); + const handleOpenCollection = () => { + dispatch(openCollection()).catch((err) => console.log(err) && toast.error('An error occured while opening the collection')); }; return ( - {createCollectionModalOpen ? setCreateCollectionModalOpen(false)} /> : null} - {importCollectionModalOpen ? setImportCollectionModalOpen(false)} /> : null} - - {addCollectionToWSModalOpen ? ( - setAddCollectionToWSModalOpen(false)} onSelect={handleAddCollectionToWorkspace} /> - ) : null} + {createCollectionModalOpen ? setCreateCollectionModalOpen(false)} /> : null} + {importCollectionModalOpen ? setImportCollectionModalOpen(false)} handleSubmit={handleImportCollection} /> : null} + {importCollectionLocationModalOpen ? ( + setImportCollectionLocationModalOpen(false)} + handleSubmit={handleImportCollectionLocation} + /> + ): null}
    @@ -73,12 +76,21 @@ const TitleBar = () => {
    { - menuDropdownTippyRef.current.hide(); setCreateCollectionModalOpen(true); + menuDropdownTippyRef.current.hide(); }} > Create Collection
    +
    { + handleOpenCollection(); + menuDropdownTippyRef.current.hide(); + }} + > + Open Collection +
    { @@ -88,49 +100,6 @@ const TitleBar = () => { > Import Collection
    -
    { - menuDropdownTippyRef.current.hide(); - setAddCollectionToWSModalOpen(true); - }} - > - Add Collection to Workspace -
    - {isPlatformElectron ? ( - <> -
    -
    - - - - Local Collections -
    -
    -
    { - setCreateCollectionModalOpen('local'); - menuDropdownTippyRef.current.hide(); - }} - > - Create Local Collection -
    -
    { - handleOpenLocalCollection(); - menuDropdownTippyRef.current.hide(); - }} - > - Open Local Collection -
    - - ) : ( -
    - Note: Local collections are only available on the desktop app. -
    - )}
    diff --git a/packages/bruno-app/src/components/Sidebar/index.js b/packages/bruno-app/src/components/Sidebar/index.js index 99ba3e69..442b001c 100644 --- a/packages/bruno-app/src/components/Sidebar/index.js +++ b/packages/bruno-app/src/components/Sidebar/index.js @@ -1,13 +1,11 @@ import MenuBar from './MenuBar'; import TitleBar from './TitleBar'; import Collections from './Collections'; -import LocalCollections from './LocalCollections'; import StyledWrapper, { BottomWrapper, VersionNumber } from './StyledWrapper'; -import WorkspaceSelector from 'components/Workspaces/WorkspaceSelector'; import { useState, useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux'; -import { IconSearch, IconChevronsRight } from '@tabler/icons'; +import { IconChevronsRight } from '@tabler/icons'; import { updateLeftSidebarWidth, updateIsDragging, toggleLeftMenuBar } from 'providers/ReduxStore/slices/app'; const MIN_LEFT_SIDEBAR_WIDTH = 222; @@ -21,7 +19,6 @@ const Sidebar = () => { const dispatch = useDispatch(); const [dragging, setDragging] = useState(false); - const [searchText, setSearchText] = useState(''); const handleMouseMove = (e) => { if (dragging) { @@ -82,30 +79,7 @@ const Sidebar = () => {
    - - -
    -
    - - - -
    - setSearchText(e.target.value.toLowerCase())} - /> -
    - - - +
    @@ -124,7 +98,7 @@ const Sidebar = () => { title="GitHub" >
    -
    v0.3.0
    +
    v0.6.0
    diff --git a/packages/bruno-app/src/components/Welcome/index.js b/packages/bruno-app/src/components/Welcome/index.js index 894e63f2..3e7d104b 100644 --- a/packages/bruno-app/src/components/Welcome/index.js +++ b/packages/bruno-app/src/components/Welcome/index.js @@ -1,61 +1,50 @@ import { useState } from 'react'; import toast from 'react-hot-toast'; -import { isElectron } from 'utils/common/platform'; -import { useSelector, useDispatch } from 'react-redux'; -import { collectionImported } from 'providers/ReduxStore/slices/collections'; -import { openLocalCollection } from 'providers/ReduxStore/slices/collections/actions'; -import { addCollectionToWorkspace } from 'providers/ReduxStore/slices/workspaces/actions'; -import { IconBrandGithub, IconPlus, IconUpload, IconFiles, IconFolders, IconPlayerPlay, IconBrandChrome, IconSpeakerphone, IconDeviceDesktop } from '@tabler/icons'; +import { useDispatch } from 'react-redux'; +import { openCollection, importCollection } from 'providers/ReduxStore/slices/collections/actions'; +import { IconBrandGithub, IconPlus, IconUpload, IconFolders, IconSpeakerphone } from '@tabler/icons'; import Bruno from 'components/Bruno'; import CreateCollection from 'components/Sidebar/CreateCollection'; -import SelectCollection from 'components/Sidebar/Collections/SelectCollection'; -import { importSampleCollection } from 'utils/importers/bruno-collection'; import ImportCollection from 'components/Sidebar/ImportCollection'; +import ImportCollectionLocation from 'components/Sidebar/ImportCollectionLocation'; import StyledWrapper from './StyledWrapper'; const Welcome = () => { const dispatch = useDispatch(); + const [importedCollection, setImportedCollection] = useState(null); const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false); - const [addCollectionToWSModalOpen, setAddCollectionToWSModalOpen] = useState(false); const [importCollectionModalOpen, setImportCollectionModalOpen] = useState(false); - const { activeWorkspaceUid } = useSelector((state) => state.workspaces); - const isPlatformElectron = isElectron(); + const [importCollectionLocationModalOpen, setImportCollectionLocationModalOpen] = useState(false); - const handleAddCollectionToWorkspace = (collectionUid) => { - setAddCollectionToWSModalOpen(false); - dispatch(addCollectionToWorkspace(activeWorkspaceUid, collectionUid)) - .then(() => { - toast.success('Collection added to workspace'); - }) - .catch(() => toast.error('An error occured while adding collection to workspace')); + const handleOpenCollection = () => { + dispatch(openCollection()).catch((err) => console.log(err) && toast.error('An error occured while opening the collection')); }; - const handleImportSampleCollection = () => { - importSampleCollection() - .then((collection) => { - dispatch(collectionImported({ collection: collection })); - dispatch(addCollectionToWorkspace(activeWorkspaceUid, collection.uid)); - }) - .then(() => toast.success('Sample Collection loaded successfully')) - .catch((err) => { - toast.error('Load sample collection failed'); - console.log(err); - }); + const handleImportCollection = (collection) => { + setImportedCollection(collection); + setImportCollectionModalOpen(false); + setImportCollectionLocationModalOpen(true); }; - const handleOpenLocalCollection = () => { - dispatch(openLocalCollection()).catch((err) => console.log(err) && toast.error('An error occured while opening the local collection')); + const handleImportCollectionLocation = (collectionLocation) => { + dispatch(importCollection(importedCollection, collectionLocation)); + setImportCollectionLocationModalOpen(false); + setImportedCollection(null); + toast.success('Collection imported successfully'); }; return ( - {createCollectionModalOpen ? setCreateCollectionModalOpen(false)} /> : null} - {importCollectionModalOpen ? setImportCollectionModalOpen(false)} /> : null} - - {addCollectionToWSModalOpen ? ( - setAddCollectionToWSModalOpen(false)} onSelect={handleAddCollectionToWorkspace} /> - ) : null} + {createCollectionModalOpen ? setCreateCollectionModalOpen(false)} /> : null} + {importCollectionModalOpen ? setImportCollectionModalOpen(false)} handleSubmit={handleImportCollection} /> : null} + {importCollectionLocationModalOpen ? ( + setImportCollectionLocationModalOpen(false)} + handleSubmit={handleImportCollectionLocation} + /> + ): null}
    @@ -71,58 +60,22 @@ const Welcome = () => { Create Collection
    -
    setAddCollectionToWSModalOpen(true)}> - - - Add Collection to Workspace - -
    +
    + + + Open Collection + +
    setImportCollectionModalOpen(true)}> Import Collection
    -
    - - Load Sample Collection -
    -
    Local Collections
    - {isPlatformElectron ? ( -
    -
    - - setCreateCollectionModalOpen('local')}> - Create Collection - -
    -
    - - - Open Collection - -
    -
    - ) : ( -
    Local collections are only available on the desktop app.
    - )} -
    Links
    - -
    - + Report Issues diff --git a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/AddWorkspace/index.js b/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/AddWorkspace/index.js deleted file mode 100644 index 02934b1f..00000000 --- a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/AddWorkspace/index.js +++ /dev/null @@ -1,70 +0,0 @@ -import React, { useEffect, useRef } from 'react'; -import Portal from 'components/Portal/index'; -import Modal from 'components/Modal/index'; -import { useFormik } from 'formik'; -import { addWorkspace } from 'providers/ReduxStore/slices/workspaces/actions'; -import * as Yup from 'yup'; -import { useDispatch } from 'react-redux'; -import toast from 'react-hot-toast'; - -const AddWorkspace = ({ onClose }) => { - const dispatch = useDispatch(); - const inputRef = useRef(); - const formik = useFormik({ - enableReinitialize: true, - initialValues: { - name: '' - }, - validationSchema: Yup.object({ - name: Yup.string().min(1, 'must be atleast 1 characters').max(30, 'must be 30 characters or less').required('name is required') - }), - onSubmit: (values) => { - dispatch(addWorkspace(values.name)) - .then(() => { - toast.success('Workspace created!'); - onClose(); - }) - .catch(() => toast.error('An error occured while creating the workspace')); - } - }); - - useEffect(() => { - if (inputRef && inputRef.current) { - inputRef.current.focus(); - } - }, [inputRef]); - - const onSubmit = () => { - formik.handleSubmit(); - }; - - return ( - - -
    -
    - - - {formik.touched.name && formik.errors.name ?
    {formik.errors.name}
    : null} -
    -
    -
    -
    - ); -}; - -export default AddWorkspace; diff --git a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/DeleteWorkspace/StyledWrapper.js b/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/DeleteWorkspace/StyledWrapper.js deleted file mode 100644 index 48b87421..00000000 --- a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/DeleteWorkspace/StyledWrapper.js +++ /dev/null @@ -1,15 +0,0 @@ -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/Workspaces/WorkspaceConfigurer/DeleteWorkspace/index.js b/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/DeleteWorkspace/index.js deleted file mode 100644 index 3e696dbc..00000000 --- a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/DeleteWorkspace/index.js +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; -import Portal from 'components/Portal/index'; -import Modal from 'components/Modal/index'; -import { deleteWorkspace } from 'providers/ReduxStore/slices/workspaces/actions'; -import { useDispatch } from 'react-redux'; -import toast from 'react-hot-toast'; -import { toastError } from 'utils/common/error'; -import StyledWrapper from './StyledWrapper'; - -const DeleteWorkspace = ({ onClose, workspace }) => { - const dispatch = useDispatch(); - const onConfirm = () => { - dispatch(deleteWorkspace(workspace.uid)) - .then(() => { - toast.success('Workspace deleted!'); - onClose(); - }) - .catch(toastError); - }; - - return ( - - - - Are you sure you want to delete {workspace.name} ? - - - - ); -}; - -export default DeleteWorkspace; diff --git a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/EditWorkspace/index.js b/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/EditWorkspace/index.js deleted file mode 100644 index 9e0a07a1..00000000 --- a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/EditWorkspace/index.js +++ /dev/null @@ -1,70 +0,0 @@ -import React, { useEffect, useRef } from 'react'; -import Portal from 'components/Portal/index'; -import Modal from 'components/Modal/index'; -import { useFormik } from 'formik'; -import { renameWorkspace } from 'providers/ReduxStore/slices/workspaces/actions'; -import * as Yup from 'yup'; -import { useDispatch } from 'react-redux'; -import toast from 'react-hot-toast'; - -const EditWorkspace = ({ onClose, workspace }) => { - const dispatch = useDispatch(); - const inputRef = useRef(); - const formik = useFormik({ - enableReinitialize: true, - initialValues: { - name: workspace.name - }, - validationSchema: Yup.object({ - name: Yup.string().min(1, 'must be atleast 1 characters').max(30, 'must be 30 characters or less').required('name is required') - }), - onSubmit: (values) => { - dispatch(renameWorkspace(values.name, workspace.uid)) - .then(() => { - toast.success('Workspace renamed!'); - onClose(); - }) - .catch(() => toast.error('An error occured while renaming the workspace')); - } - }); - - useEffect(() => { - if (inputRef && inputRef.current) { - inputRef.current.focus(); - } - }, [inputRef]); - - const onSubmit = () => { - formik.handleSubmit(); - }; - - return ( - - -
    -
    - - - {formik.touched.name && formik.errors.name ?
    {formik.errors.name}
    : null} -
    -
    -
    -
    - ); -}; - -export default EditWorkspace; diff --git a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/WorkspaceItem/StyledWrapper.js b/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/WorkspaceItem/StyledWrapper.js deleted file mode 100644 index 2c99eeb5..00000000 --- a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/WorkspaceItem/StyledWrapper.js +++ /dev/null @@ -1,17 +0,0 @@ -import styled from 'styled-components'; - -const Wrapper = styled.div` - div { - padding: 4px 6px; - padding-left: 8px; - display: flex; - align-items: center; - border-radius: 3px; - } - - div:hover { - background-color: ${(props) => props.theme.plainGrid.hoverBg}; - } -`; - -export default Wrapper; diff --git a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/WorkspaceItem/index.js b/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/WorkspaceItem/index.js deleted file mode 100644 index 25728bd7..00000000 --- a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/WorkspaceItem/index.js +++ /dev/null @@ -1,26 +0,0 @@ -import React, { useState } from 'react'; -import EditWorkspace from '../EditWorkspace'; -import DeleteWorkspace from '../DeleteWorkspace'; -import { IconEdit, IconTrash } from '@tabler/icons'; -import StyledWrapper from './StyledWrapper'; - -const WorkspaceItem = ({ workspace }) => { - const [openEditModal, setOpenEditModal] = useState(false); - const [openDeleteModal, setOpenDeleteModal] = useState(false); - - return ( - -
    -
  • {workspace.name}
  • -
    - setOpenEditModal(true)} /> - setOpenDeleteModal(true)} /> -
    - {openEditModal && setOpenEditModal(false)} workspace={workspace} />} - {openDeleteModal && setOpenDeleteModal(false)} workspace={workspace} />} -
    -
    - ); -}; - -export default WorkspaceItem; diff --git a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/index.js b/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/index.js deleted file mode 100644 index 17452d08..00000000 --- a/packages/bruno-app/src/components/Workspaces/WorkspaceConfigurer/index.js +++ /dev/null @@ -1,19 +0,0 @@ -import Modal from 'components/Modal/index'; -import React, { useState } from 'react'; -import { useSelector } from 'react-redux'; -import WorkspaceItem from './WorkspaceItem/index'; -import AddWorkspace from './AddWorkspace'; - -const WorkspaceConfigurer = ({ onClose }) => { - const { workspaces } = useSelector((state) => state.workspaces); - const [openAddModal, setOpenAddModal] = useState(false); - - return ( - setOpenAddModal(true)} handleCancel={onClose} hideCancel={true}> -
      {workspaces && workspaces.length && workspaces.map((workspace) => )}
    - {openAddModal && setOpenAddModal(false)} />} -
    - ); -}; - -export default WorkspaceConfigurer; diff --git a/packages/bruno-app/src/components/Workspaces/WorkspaceSelectModal/StyledWrapper.js b/packages/bruno-app/src/components/Workspaces/WorkspaceSelectModal/StyledWrapper.js deleted file mode 100644 index b776b1ee..00000000 --- a/packages/bruno-app/src/components/Workspaces/WorkspaceSelectModal/StyledWrapper.js +++ /dev/null @@ -1,18 +0,0 @@ -import styled from 'styled-components'; - -const StyledWrapper = styled.div` - div.workspace { - padding: 4px 6px; - padding-left: 8px; - display: flex; - align-items: center; - border-radius: 3px; - cursor: pointer; - - &:hover { - background-color: #f4f4f4; - } - } -`; - -export default StyledWrapper; diff --git a/packages/bruno-app/src/components/Workspaces/WorkspaceSelectModal/index.js b/packages/bruno-app/src/components/Workspaces/WorkspaceSelectModal/index.js deleted file mode 100644 index 42e427c3..00000000 --- a/packages/bruno-app/src/components/Workspaces/WorkspaceSelectModal/index.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; -import Modal from 'components/Modal/index'; -import { IconBox } from '@tabler/icons'; -import { useSelector } from 'react-redux'; -import StyledWrapper from './StyledWrapper'; - -const WorkspaceSelectModal = ({ onClose, onSelect, title }) => { - const { workspaces } = useSelector((state) => state.workspaces); - - return ( - - -
      - {workspaces && workspaces.length ? ( - workspaces.map((w) => ( -
      onSelect(w.uid)}> - {w.name} -
      - )) - ) : ( -
      No workspaces found
      - )} -
    -
    -
    - ); -}; - -export default WorkspaceSelectModal; diff --git a/packages/bruno-app/src/components/Workspaces/WorkspaceSelector/index.js b/packages/bruno-app/src/components/Workspaces/WorkspaceSelector/index.js deleted file mode 100644 index a5262466..00000000 --- a/packages/bruno-app/src/components/Workspaces/WorkspaceSelector/index.js +++ /dev/null @@ -1,70 +0,0 @@ -import React, { useRef, forwardRef, useState, useEffect } from 'react'; -import Dropdown from 'components/Dropdown'; -import { IconCaretDown, IconBox, IconSwitch3, IconSettings } from '@tabler/icons'; -import WorkspaceConfigurer from '../WorkspaceConfigurer'; -import WorkspaceSelectModal from '../WorkspaceSelectModal'; -import { useDispatch, useSelector } from 'react-redux'; -import { selectWorkspace } from 'providers/ReduxStore/slices/workspaces'; -import StyledWrapper from './StyledWrapper'; - -const WorkspaceSelector = () => { - const dropdownTippyRef = useRef(); - const [openWorkspacesModal, setOpenWorkspacesModal] = useState(false); - const [openSwitchWorkspaceModal, setOpenSwitchWorkspaceModal] = useState(false); - const [activeWorkspace, setActiveWorkspace] = useState({}); - const dispatch = useDispatch(); - - const { workspaces, activeWorkspaceUid } = useSelector((state) => state.workspaces); - - useEffect(() => { - setActiveWorkspace(workspaces.find((workspace) => workspace.uid === activeWorkspaceUid)); - }, [activeWorkspaceUid, workspaces]); - - const Icon = forwardRef((props, ref) => { - return ( -
    -
    - - - - {activeWorkspace ? activeWorkspace.name : ''} -
    - -
    - ); - }); - - const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref); - - const handleSelectWorkspace = (workspaceUid) => { - dispatch(selectWorkspace({ workspaceUid: workspaceUid })); - setOpenSwitchWorkspaceModal(false); - }; - - return ( - - {openWorkspacesModal && setOpenWorkspacesModal(false)} />} - {openSwitchWorkspaceModal && setOpenSwitchWorkspaceModal(false)} />} - -
    - } placement="bottom-end"> -
    setOpenSwitchWorkspaceModal(true)}> -
    - -
    - Switch Workspace -
    - -
    setOpenWorkspacesModal(true)}> -
    - -
    - Configure Workspaces -
    -
    -
    -
    - ); -}; - -export default WorkspaceSelector; diff --git a/packages/bruno-app/src/pageComponents/Collections/CollectionItem/index.js b/packages/bruno-app/src/pageComponents/Collections/CollectionItem/index.js deleted file mode 100644 index f6b54b20..00000000 --- a/packages/bruno-app/src/pageComponents/Collections/CollectionItem/index.js +++ /dev/null @@ -1,25 +0,0 @@ -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/pageComponents/Collections/StyledWrapper.js b/packages/bruno-app/src/pageComponents/Collections/StyledWrapper.js deleted file mode 100644 index 0238fb7c..00000000 --- a/packages/bruno-app/src/pageComponents/Collections/StyledWrapper.js +++ /dev/null @@ -1,30 +0,0 @@ -import styled from 'styled-components'; - -const Wrapper = styled.div` - .heading { - display: inline-flex; - font-weight: 600; - margin-top: 1.5rem; - padding: 6px 0px; - border-bottom: 2px solid !important; - } - - .collection-list { - min-width: 500px; - - .collection-list-item { - padding: 4px 0px; - border-radius: 3px; - - &:hover { - background-color: ${(props) => props.theme.plainGrid.hoverBg}; - margin-left: -8px; - margin-right: -8px; - padding-left: 8px; - padding-right: 8px; - } - } - } -`; - -export default Wrapper; diff --git a/packages/bruno-app/src/pageComponents/Collections/index.js b/packages/bruno-app/src/pageComponents/Collections/index.js deleted file mode 100644 index 68463c5e..00000000 --- a/packages/bruno-app/src/pageComponents/Collections/index.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import filter from 'lodash/filter'; -import { useSelector } from 'react-redux'; -import CollectionItem from './CollectionItem'; -import StyledWrapper from './StyledWrapper'; -import { isLocalCollection } from 'utils/collections'; - -export default function Collections() { - const collections = useSelector((state) => state.collections.collections); - const collectionsToDisplay = filter(collections, (c) => !isLocalCollection(c)); - - return ( - -

    Collections

    - -
    - {collectionsToDisplay && collectionsToDisplay.length ? ( - collectionsToDisplay.map((collection) => { - return ; - }) - ) : ( -
    No collections found
    - )} -
    -
    - ); -} diff --git a/packages/bruno-app/src/pageComponents/Login/StyledWrapper.js b/packages/bruno-app/src/pageComponents/Login/StyledWrapper.js deleted file mode 100644 index 140e8237..00000000 --- a/packages/bruno-app/src/pageComponents/Login/StyledWrapper.js +++ /dev/null @@ -1,41 +0,0 @@ -import styled from 'styled-components'; - -const Wrapper = styled.div` - display: flex; - flex-direction: column; - width: 100%; - height: 100%; - min-height: 100vh; - - .form-container { - max-width: 350px; - border-radius: 4px; - border: 1px #ddd solid; - - button.continue-btn { - font-size: 16px; - padding-top: 8x; - padding-bottom: 8px; - min-height: 38px; - align-items: center; - color: #212529; - background: #e2e6ea; - border: solid 1px #dae0e5; - } - - .field-error { - font-size: 0.875rem; - } - - a { - color: ${(props) => props.theme.textLink}; - } - - .error-msg { - font-size: 15px; - color: rgb(192 69 8); - } - } -`; - -export default Wrapper; diff --git a/packages/bruno-app/src/pageComponents/Login/index.js b/packages/bruno-app/src/pageComponents/Login/index.js deleted file mode 100644 index 2b56a7bd..00000000 --- a/packages/bruno-app/src/pageComponents/Login/index.js +++ /dev/null @@ -1,243 +0,0 @@ -import React, { useState } from 'react'; -import * as Yup from 'yup'; -import Link from 'next/link'; -import { useRouter } from 'next/router'; -import { useAuth } from 'providers/Auth'; -import AuthApi from 'api/auth'; -import { useFormik } from 'formik'; -import StyledWrapper from './StyledWrapper'; - -const Login = () => { - const router = useRouter(); - const [authState, authDispatch] = useAuth(); - - const { currentUser } = authState; - - const [loggingIn, setLoggingIn] = useState(false); - const [loginError, setLoginError] = useState(false); - - const formik = useFormik({ - initialValues: { - email: '', - password: '' - }, - validationSchema: Yup.object({ - email: Yup.string().required('Email is required'), - password: Yup.string().required('Password is required') - }), - onSubmit: (values, { resetForm }) => { - setLoggingIn(true); - AuthApi.login({ - email: values.email, - password: values.password - }) - .then((response) => { - authDispatch({ - type: 'LOGIN_SUCCESS', - user: response.data - }); - }) - .catch((error) => { - setLoggingIn(false); - setLoginError(true); - }); - } - }); - - if (authState.isLoading) { - return null; - } - - if (currentUser) { - router.push('/'); - return null; - } - - return ( - -
    -
    - - - - - - - - - - - - - - - - - - - - - - -
    -
    - bruno -
    -
    Opensource IDE for exploring and testing api's.
    -
    -
    -
    -
    Login
    - -
    - - setLoginError(false)} - onBlur={formik.handleBlur} - value={formik.values.email} - /> - {formik.touched.email && formik.errors.email ?
    {formik.errors.email}
    : null} -
    - -
    - - setLoginError(false)} - onBlur={formik.handleBlur} - value={formik.values.password} - /> - {formik.touched.password && formik.errors.password ?
    {formik.errors.password}
    : null} -
    - -
    - {loggingIn ? ( - - ) : ( -
    - -
    - )} - {loginError ?
    Invalid Credentials
    : null} -
    - -
    -
    - No account? Create one! -
    -
    -
    -
    - ); -}; - -export default Login; diff --git a/packages/bruno-app/src/pageComponents/SignUp/StyledWrapper.js b/packages/bruno-app/src/pageComponents/SignUp/StyledWrapper.js deleted file mode 100644 index 36d1cb2b..00000000 --- a/packages/bruno-app/src/pageComponents/SignUp/StyledWrapper.js +++ /dev/null @@ -1,49 +0,0 @@ -import styled from 'styled-components'; - -const Wrapper = styled.div` - display: flex; - flex-direction: column; - width: 100%; - height: 100%; - min-height: 100vh; - - .form-container { - max-width: 350px; - border-radius: 4px; - border: 1px #ddd solid; - - button.continue-btn { - font-size: 16px; - padding-top: 8px; - padding-bottom: 8px; - min-height: 38px; - align-items: center; - color: #212529; - background: #e2e6ea; - border: solid 1px #dae0e5; - } - - .field-error { - font-size: 0.875rem; - } - - a { - color: ${(props) => props.theme.textLink}; - } - - .or { - display: inline-block; - position: relative; - top: -14px; - background: white; - padding-inline: 10px; - } - - .error-msg { - font-size: 15px; - color: rgb(192 69 8); - } - } -`; - -export default Wrapper; diff --git a/packages/bruno-app/src/pageComponents/SignUp/index.js b/packages/bruno-app/src/pageComponents/SignUp/index.js deleted file mode 100644 index a054725c..00000000 --- a/packages/bruno-app/src/pageComponents/SignUp/index.js +++ /dev/null @@ -1,273 +0,0 @@ -import React, { useState } from 'react'; -import Link from 'next/link'; -import StyledWrapper from './StyledWrapper'; -import AuthApi from 'api/auth'; -import { useFormik } from 'formik'; -import * as Yup from 'yup'; -import { useRouter } from 'next/router'; -import { useAuth } from 'providers/Auth'; - -const SignUp = () => { - const router = useRouter(); - const [authState, authDispatch] = useAuth(); - const [errorSigningUp, setErrorSigningUp] = useState(false); - const [errorMsg, setErrorMsg] = useState(''); - const [signingUp, setSigningUp] = useState(false); - - const { currentUser } = authState; - - const formik = useFormik({ - initialValues: { - name: '', - email: '', - password: '' - }, - validationSchema: Yup.object({ - name: Yup.string().min(3, 'Must be atleast 3 characters').max(50, 'Must be 50 characters or less').required('Required'), - email: Yup.string().email('Invalid email address').required('Required'), - password: Yup.string().min(8, 'Must be atleast 8 characters').max(50, 'Must be 50 characters or less').required('Required') - }), - onSubmit: (values, { resetForm }) => { - setSigningUp(true); - AuthApi.signup({ - name: values.name, - email: values.email, - password: values.password - }) - .then((response) => { - authDispatch({ - type: 'LOGIN_SUCCESS', - user: response.data - }); - }) - .catch((error) => { - setSigningUp(false); - setErrorSigningUp(true); - setErrorMsg(error.message || 'An error occured during signup'); - }); - setSigningUp(false); - } - }); - - if (authState.isLoading) { - return null; - } - - if (currentUser) { - router.push('/'); - return null; - } - - return ( - -
    -
    - - - - - - - - - - - - - - - - - - - - - - -
    -
    - bruno -
    -
    Opensource IDE for exploring and testing api's.
    -
    - -
    -
    -
    Create Account
    - -
    - - setErrorSigningUp(false)} - /> - {formik.touched.name && formik.errors.name ?
    {formik.errors.name}
    : null} -
    - -
    - - setErrorSigningUp(false)} - /> - {formik.touched.email && formik.errors.email ?
    {formik.errors.email}
    : null} -
    - -
    - - setErrorSigningUp(false)} - /> - {formik.touched.password && formik.errors.password ?
    {formik.errors.password}
    : null} -
    - -
    By signing in you are agreeing to our Terms of Use and our Privacy Policy.
    - -
    - {signingUp ? ( -
    - -
    - ) : ( -
    - {errorSigningUp ?
    {errorMsg}
    : null} -
    - -
    -
    - )} -
    -
    -
    - Already have an account? Log in -
    -
    -
    -
    - ); -}; - -export default SignUp; diff --git a/packages/bruno-app/src/providers/App/index.js b/packages/bruno-app/src/providers/App/index.js index e7cf91a5..99e4badb 100644 --- a/packages/bruno-app/src/providers/App/index.js +++ b/packages/bruno-app/src/providers/App/index.js @@ -1,7 +1,6 @@ import React, { useEffect } from 'react'; -import useIdb from './useIdb'; import useTelemetry from './useTelemetry'; -import useLocalCollectionTreeSync from './useLocalCollectionTreeSync'; +import useCollectionTreeSync from './useCollectionTreeSync'; import { useDispatch } from 'react-redux'; import { refreshScreenWidth } from 'providers/ReduxStore/slices/app'; import StyledWrapper from './StyledWrapper'; @@ -9,9 +8,8 @@ import StyledWrapper from './StyledWrapper'; export const AppContext = React.createContext(); export const AppProvider = (props) => { - useIdb(); useTelemetry(); - useLocalCollectionTreeSync(); + useCollectionTreeSync(); const dispatch = useDispatch(); diff --git a/packages/bruno-app/src/providers/App/useLocalCollectionTreeSync.js b/packages/bruno-app/src/providers/App/useCollectionTreeSync.js similarity index 67% rename from packages/bruno-app/src/providers/App/useLocalCollectionTreeSync.js rename to packages/bruno-app/src/providers/App/useCollectionTreeSync.js index 86407b3b..93b29aaa 100644 --- a/packages/bruno-app/src/providers/App/useLocalCollectionTreeSync.js +++ b/packages/bruno-app/src/providers/App/useCollectionTreeSync.js @@ -1,17 +1,18 @@ import { useEffect } from 'react'; import { useDispatch } from 'react-redux'; import { - localCollectionAddDirectoryEvent, - localCollectionAddFileEvent, - localCollectionChangeFileEvent, - localCollectionUnlinkFileEvent, - localCollectionUnlinkDirectoryEvent + collectionAddDirectoryEvent, + collectionAddFileEvent, + collectionChangeFileEvent, + collectionUnlinkFileEvent, + collectionUnlinkDirectoryEvent, + collectionUnlinkEnvFileEvent } from 'providers/ReduxStore/slices/collections'; import toast from 'react-hot-toast'; -import { openLocalCollectionEvent, localCollectionLoadEnvironmentsEvent } from 'providers/ReduxStore/slices/collections/actions'; +import { openCollectionEvent, collectionAddEnvFileEvent } from 'providers/ReduxStore/slices/collections/actions'; import { isElectron } from 'utils/common/platform'; -const useLocalCollectionTreeSync = () => { +const useCollectionTreeSync = () => { const dispatch = useDispatch(); useEffect(() => { @@ -23,27 +24,27 @@ const useLocalCollectionTreeSync = () => { const _openCollection = (pathname, uid, name) => { console.log(`collection uid: ${uid}, pathname: ${pathname}, name: ${name}`); - dispatch(openLocalCollectionEvent(uid, pathname, name)); + dispatch(openCollectionEvent(uid, pathname, name)); }; const _collectionTreeUpdated = (type, val) => { if (type === 'addDir') { dispatch( - localCollectionAddDirectoryEvent({ + collectionAddDirectoryEvent({ dir: val }) ); } if (type === 'addFile') { dispatch( - localCollectionAddFileEvent({ + collectionAddFileEvent({ file: val }) ); } if (type === 'change') { dispatch( - localCollectionChangeFileEvent({ + collectionChangeFileEvent({ file: val }) ); @@ -51,7 +52,7 @@ const useLocalCollectionTreeSync = () => { if (type === 'unlink') { setTimeout(() => { dispatch( - localCollectionUnlinkFileEvent({ + collectionUnlinkFileEvent({ file: val }) ); @@ -59,21 +60,21 @@ const useLocalCollectionTreeSync = () => { } if (type === 'unlinkDir') { dispatch( - localCollectionUnlinkDirectoryEvent({ + collectionUnlinkDirectoryEvent({ directory: val }) ); } if (type === 'addEnvironmentFile') { - dispatch(localCollectionLoadEnvironmentsEvent(val)); + dispatch(collectionAddEnvFileEvent(val)); } - if (type === 'changeEnvironmentFile') { - dispatch(localCollectionLoadEnvironmentsEvent(val)); + if (type === 'unlinkEnvironmentFile') { + dispatch(collectionUnlinkEnvFileEvent(val)); } }; const _collectionAlreadyOpened = (pathname) => { - toast.success('Collection is already opened under local collections'); + toast.success('Collection is already opened'); }; const _displayError = (message) => { @@ -96,4 +97,4 @@ const useLocalCollectionTreeSync = () => { }, [isElectron]); }; -export default useLocalCollectionTreeSync; +export default useCollectionTreeSync; diff --git a/packages/bruno-app/src/providers/App/useIdb.js b/packages/bruno-app/src/providers/App/useIdb.js deleted file mode 100644 index 42ead12e..00000000 --- a/packages/bruno-app/src/providers/App/useIdb.js +++ /dev/null @@ -1,34 +0,0 @@ -import { useEffect } from 'react'; -import { openDB } from 'idb'; -import { idbConnectionReady } from 'providers/ReduxStore/slices/app'; -import { loadCollectionsFromIdb } from 'providers/ReduxStore/slices/collections/actions'; -import { loadWorkspacesFromIdb } from 'providers/ReduxStore/slices/workspaces/actions'; -import { useDispatch } from 'react-redux'; - -const useIdb = () => { - const dispatch = useDispatch(); - - useEffect(() => { - let dbName = `bruno`; - let connection = openDB(dbName, 1, { - upgrade(db, oldVersion, newVersion, transaction) { - switch (oldVersion) { - case 0: - const collectionStore = db.createObjectStore('collection', { keyPath: 'uid' }); - const workspaceStore = db.createObjectStore('workspace', { keyPath: 'uid' }); - } - } - }); - - connection - .then(() => { - window.__idb = connection; - dispatch(idbConnectionReady()); - dispatch(loadCollectionsFromIdb()); - dispatch(loadWorkspacesFromIdb()); - }) - .catch((err) => console.log(err)); - }, []); -}; - -export default useIdb; diff --git a/packages/bruno-app/src/providers/ReduxStore/index.js b/packages/bruno-app/src/providers/ReduxStore/index.js index f0bdebf7..d86b18fc 100644 --- a/packages/bruno-app/src/providers/ReduxStore/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/index.js @@ -2,14 +2,12 @@ import { configureStore } from '@reduxjs/toolkit'; import appReducer from './slices/app'; import collectionsReducer from './slices/collections'; import tabsReducer from './slices/tabs'; -import workspacesReducer from './slices/workspaces'; export const store = configureStore({ reducer: { app: appReducer, collections: collectionsReducer, - tabs: tabsReducer, - workspaces: workspacesReducer + tabs: tabsReducer } }); 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 46996f6a..8a055179 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js @@ -1,8 +1,6 @@ import path from 'path'; import filter from 'lodash/filter'; -import each from 'lodash/each'; import trim from 'lodash/trim'; -import toast from 'react-hot-toast'; import { uuid } from 'utils/common'; import cloneDeep from 'lodash/cloneDeep'; import { @@ -13,21 +11,18 @@ import { recursivelyGetAllItemUids, transformCollectionToSaveToIdb, transformRequestToSaveToFilesystem, - deleteItemInCollection, findParentItemInCollection, findEnvironmentInCollection, isItemAFolder, refreshUidsInItem, - interpolateEnvironmentVars, - getDefaultRequestPaneTab + interpolateEnvironmentVars } from 'utils/collections'; -import { collectionSchema, itemSchema, environmentsSchema } from '@usebruno/schema'; +import { collectionSchema, itemSchema, environmentSchema, environmentsSchema } from '@usebruno/schema'; import { waitForNextTick } from 'utils/common'; -import { getCollectionsFromIdb, saveCollectionToIdb, deleteCollectionInIdb } from 'utils/idb'; +import { saveCollectionToIdb } from 'utils/idb'; import { sendNetworkRequest, cancelNetworkRequest } from 'utils/network'; import { - loadCollections, requestSent, requestCancelled, responseReceived, @@ -38,91 +33,18 @@ import { moveItem as _moveItem, moveItemToRootOfCollection as _moveItemToRootOfCollection, saveRequest as _saveRequest, - addEnvironment as _addEnvironment, - renameEnvironment as _renameEnvironment, - deleteEnvironment as _deleteEnvironment, - saveEnvironment as _saveEnvironment, selectEnvironment as _selectEnvironment, createCollection as _createCollection, renameCollection as _renameCollection, - deleteCollection as _deleteCollection, - localCollectionLoadEnvironmentsEvent as _localCollectionLoadEnvironmentsEvent + removeCollection as _removeCollection, + collectionAddEnvFileEvent as _collectionAddEnvFileEvent } from './index'; -import { closeTabs, addTab } from 'providers/ReduxStore/slices/tabs'; -import { addCollectionToWorkspace } from 'providers/ReduxStore/slices/workspaces/actions'; +import { closeTabs } from 'providers/ReduxStore/slices/tabs'; import { isLocalCollection, resolveRequestFilename } from 'utils/common/platform'; const PATH_SEPARATOR = path.sep; -export const loadCollectionsFromIdb = () => (dispatch) => { - getCollectionsFromIdb(window.__idb) - .then((collections) => - dispatch( - loadCollections({ - collections: collections - }) - ) - ) - .catch(() => toast.error('Error occured while loading collections from IndexedDB')); -}; - -export const createCollection = (collectionName) => (dispatch, getState) => { - const newCollection = { - version: '1', - uid: uuid(), - name: collectionName, - items: [], - environments: [] - }; - - const requestItem = { - uid: uuid(), - type: 'http-request', - name: 'Untitled', - request: { - method: 'GET', - url: '', - headers: [], - params: [], - body: { - mode: 'none', - json: null, - text: null, - xml: null, - multipartForm: null, - formUrlEncoded: null - } - } - }; - - newCollection.items.push(requestItem); - - const state = getState(); - const { activeWorkspaceUid } = state.workspaces; - - return new Promise((resolve, reject) => { - collectionSchema - .validate(newCollection) - .then(() => saveCollectionToIdb(window.__idb, newCollection)) - .then(() => dispatch(_createCollection(newCollection))) - .then(waitForNextTick) - .then(() => dispatch(addCollectionToWorkspace(activeWorkspaceUid, newCollection.uid))) - .then(waitForNextTick) - .then(() => - dispatch( - addTab({ - uid: requestItem.uid, - collectionUid: newCollection.uid, - requestPaneTab: getDefaultRequestPaneTab(requestItem) - }) - ) - ) - .then(resolve) - .catch(reject); - }); -}; - export const renameCollection = (newName, collectionUid) => (dispatch, getState) => { const state = getState(); const collection = findCollectionByUid(state.collections.collections, collectionUid); @@ -149,33 +71,6 @@ export const renameCollection = (newName, collectionUid) => (dispatch, getState) } }; -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); - }); -}; - export const saveRequest = (itemUid, collectionUid) => (dispatch, getState) => { const state = getState(); const collection = findCollectionByUid(state.collections.collections, collectionUid); @@ -186,39 +81,19 @@ export const saveRequest = (itemUid, collectionUid) => (dispatch, getState) => { } const collectionCopy = cloneDeep(collection); - - if (isLocalCollection(collection)) { - const item = findItemInCollection(collectionCopy, itemUid); - if (item) { - const itemToSave = transformRequestToSaveToFilesystem(item); - const { ipcRenderer } = window; - - itemSchema - .validate(itemToSave) - .then(() => ipcRenderer.invoke('renderer:save-request', item.pathname, itemToSave)) - .then(resolve) - .catch(reject); - } else { - reject(new Error('Not able to locate item')); - } - return; + const item = findItemInCollection(collectionCopy, itemUid); + if (!item) { + return reject(new Error('Not able to locate item')); } - const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); + const itemToSave = transformRequestToSaveToFilesystem(item); + const { ipcRenderer } = window; - collectionSchema - .validate(collectionToSave) - .then(() => saveCollectionToIdb(window.__idb, collectionToSave)) - .then(() => { - dispatch( - _saveRequest({ - itemUid: itemUid, - collectionUid: collectionUid - }) - ); - }) - .then(() => resolve()) - .catch((error) => reject(error)); + itemSchema + .validate(itemToSave) + .then(() => ipcRenderer.invoke('renderer:save-request', item.pathname, itemToSave)) + .then(resolve) + .catch(reject); }); }; @@ -298,11 +173,25 @@ export const newFolder = (folderName, collectionUid, itemUid) => (dispatch, getS return reject(new Error('Collection not found')); } - if (isLocalCollection(collection)) { - if (!itemUid) { - const folderWithSameNameExists = find(collection.items, (i) => i.type === 'folder' && trim(i.name) === trim(folderName)); + if (!itemUid) { + const folderWithSameNameExists = find(collection.items, (i) => i.type === 'folder' && trim(i.name) === trim(folderName)); + if (!folderWithSameNameExists) { + const fullName = `${collection.pathname}${PATH_SEPARATOR}${folderName}`; + const { ipcRenderer } = window; + + ipcRenderer + .invoke('renderer:new-folder', fullName) + .then(() => resolve()) + .catch((error) => reject(error)); + } else { + return reject(new Error('folder with same name already exists')); + } + } else { + const currentItem = findItemInCollection(collection, itemUid); + if (currentItem) { + const folderWithSameNameExists = find(currentItem.items, (i) => i.type === 'folder' && trim(i.name) === trim(folderName)); if (!folderWithSameNameExists) { - const fullName = `${collection.pathname}${PATH_SEPARATOR}${folderName}`; + const fullName = `${currentItem.pathname}${PATH_SEPARATOR}${folderName}`; const { ipcRenderer } = window; ipcRenderer @@ -313,59 +202,9 @@ export const newFolder = (folderName, collectionUid, itemUid) => (dispatch, getS return reject(new Error('folder with same name already exists')); } } else { - const currentItem = findItemInCollection(collection, itemUid); - if (currentItem) { - const folderWithSameNameExists = find(currentItem.items, (i) => i.type === 'folder' && trim(i.name) === trim(folderName)); - if (!folderWithSameNameExists) { - const fullName = `${currentItem.pathname}${PATH_SEPARATOR}${folderName}`; - const { ipcRenderer } = window; - - ipcRenderer - .invoke('renderer:new-folder', fullName) - .then(() => resolve()) - .catch((error) => reject(error)); - } else { - return reject(new Error('folder with same name already exists')); - } - } else { - return reject(new Error('unable to find parent folder')); - } - } - return; - } - - const collectionCopy = cloneDeep(collection); - const item = { - uid: uuid(), - name: folderName, - type: 'folder', - items: [] - }; - if (!itemUid) { - collectionCopy.items.push(item); - } else { - const currentItem = findItemInCollection(collectionCopy, itemUid); - if (currentItem && currentItem.type === 'folder') { - currentItem.items = currentItem.items || []; - currentItem.items.push(item); + return reject(new Error('unable to find parent folder')); } } - const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); - - collectionSchema - .validate(collectionToSave) - .then(() => saveCollectionToIdb(window.__idb, collectionToSave)) - .then(() => { - dispatch( - _newItem({ - item: item, - currentItemUid: itemUid, - collectionUid: collectionUid - }) - ); - }) - .then(() => resolve()) - .catch((error) => reject(error)); }); }; @@ -384,42 +223,21 @@ export const renameItem = (newName, itemUid, collectionUid) => (dispatch, getSta return reject(new Error('Unable to locate item')); } - if (isLocalCollection(collection)) { - const dirname = path.dirname(item.pathname); + const dirname = path.dirname(item.pathname); - let newPathname = ''; - if (item.type === 'folder') { - newPathname = `${dirname}${PATH_SEPARATOR}${trim(newName)}`; - } else { - const filename = resolveRequestFilename(newName); - newPathname = `${dirname}${PATH_SEPARATOR}${filename}`; - } - const { ipcRenderer } = window; - - ipcRenderer.invoke('renderer:rename-item', item.pathname, newPathname, newName).then(resolve).catch(reject); - - return; + let newPathname = ''; + if (item.type === 'folder') { + newPathname = `${dirname}${PATH_SEPARATOR}${trim(newName)}`; + } else { + const filename = resolveRequestFilename(newName); + newPathname = `${dirname}${PATH_SEPARATOR}${filename}`; } + const { ipcRenderer } = window; - item.name = newName; - const collectionToSave = transformCollectionToSaveToIdb(collectionCopy, { - ignoreDraft: true - }); - - collectionSchema - .validate(collectionToSave) - .then(() => saveCollectionToIdb(window.__idb, collectionToSave)) - .then(() => { - dispatch( - _renameItem({ - newName: newName, - itemUid: itemUid, - collectionUid: collectionUid - }) - ); - }) - .then(() => resolve()) - .catch((error) => reject(error)); + ipcRenderer + .invoke('renderer:rename-item', item.pathname, newPathname, newName) + .then(resolve) + .catch(reject); }); }; @@ -441,74 +259,40 @@ export const cloneItem = (newName, itemUid, collectionUid) => (dispatch, getStat throw new Error('Cloning folders is not supported yet'); } - if (isLocalCollection(collection)) { - const parentItem = findParentItemInCollection(collectionCopy, itemUid); - const filename = resolveRequestFilename(newName); - const itemToSave = refreshUidsInItem(transformRequestToSaveToFilesystem(item)); - itemToSave.name = trim(newName); - if (!parentItem) { - const reqWithSameNameExists = find(collection.items, (i) => i.type !== 'folder' && trim(i.filename) === trim(filename)); - if (!reqWithSameNameExists) { - const fullName = `${collection.pathname}${PATH_SEPARATOR}${filename}`; - const { ipcRenderer } = window; - - itemSchema - .validate(itemToSave) - .then(() => ipcRenderer.invoke('renderer:new-request', fullName, itemToSave)) - .then(resolve) - .catch(reject); - } else { - return reject(new Error(`${requestName} already exists in collection`)); - } - } else { - const reqWithSameNameExists = find(parentItem.items, (i) => i.type !== 'folder' && trim(i.filename) === trim(filename)); - if (!reqWithSameNameExists) { - const dirname = path.dirname(item.pathname); - const fullName = `${dirname}${PATH_SEPARATOR}${filename}`; - const { ipcRenderer } = window; - - itemSchema - .validate(itemToSave) - .then(() => ipcRenderer.invoke('renderer:new-request', fullName, itemToSave)) - .then(resolve) - .catch(reject); - } else { - return reject(new Error(`${requestName} already exists in the folder`)); - } - } - return; - } - - // todo: clone query params - const clonedItem = cloneDeep(item); - clonedItem.name = newName; - clonedItem.uid = uuid(); - each(clonedItem.headers, (h) => (h.uid = uuid())); - const parentItem = findParentItemInCollection(collectionCopy, itemUid); - + const filename = resolveRequestFilename(newName); + const itemToSave = refreshUidsInItem(transformRequestToSaveToFilesystem(item)); + itemToSave.name = trim(newName); if (!parentItem) { - collectionCopy.items.push(clonedItem); + const reqWithSameNameExists = find(collection.items, (i) => i.type !== 'folder' && trim(i.filename) === trim(filename)); + if (!reqWithSameNameExists) { + const fullName = `${collection.pathname}${PATH_SEPARATOR}${filename}`; + const { ipcRenderer } = window; + + itemSchema + .validate(itemToSave) + .then(() => ipcRenderer.invoke('renderer:new-request', fullName, itemToSave)) + .then(resolve) + .catch(reject); + } else { + return reject(new Error(`${requestName} already exists in collection`)); + } } else { - parentItem.items.push(clonedItem); + const reqWithSameNameExists = find(parentItem.items, (i) => i.type !== 'folder' && trim(i.filename) === trim(filename)); + if (!reqWithSameNameExists) { + const dirname = path.dirname(item.pathname); + const fullName = `${dirname}${PATH_SEPARATOR}${filename}`; + const { ipcRenderer } = window; + + itemSchema + .validate(itemToSave) + .then(() => ipcRenderer.invoke('renderer:new-request', fullName, itemToSave)) + .then(resolve) + .catch(reject); + } else { + return reject(new Error(`${requestName} already exists in the folder`)); + } } - - const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); - - collectionSchema - .validate(collectionToSave) - .then(() => saveCollectionToIdb(window.__idb, collectionToSave)) - .then(() => { - dispatch( - _cloneItem({ - parentItemUid: parentItem ? parentItem.uid : null, - clonedItem: clonedItem, - collectionUid: collectionUid - }) - ); - }) - .then(() => resolve()) - .catch((error) => reject(error)); }); }; @@ -521,36 +305,16 @@ export const deleteItem = (itemUid, collectionUid) => (dispatch, getState) => { return reject(new Error('Collection not found')); } - if (isLocalCollection(collection)) { - const item = findItemInCollection(collection, itemUid); - if (item) { - const { ipcRenderer } = window; + const item = findItemInCollection(collection, itemUid); + if (item) { + const { ipcRenderer } = window; - ipcRenderer - .invoke('renderer:delete-item', item.pathname, item.type) - .then(() => resolve()) - .catch((error) => reject(error)); - } - return; + ipcRenderer + .invoke('renderer:delete-item', item.pathname, item.type) + .then(() => resolve()) + .catch((error) => reject(error)); } - - const collectionCopy = cloneDeep(collection); - deleteItemInCollection(itemUid, collectionCopy); - const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); - - collectionSchema - .validate(collectionToSave) - .then(() => saveCollectionToIdb(window.__idb, collectionToSave)) - .then(() => { - dispatch( - _deleteItem({ - itemUid: itemUid, - collectionUid: collectionUid - }) - ); - }) - .then(() => resolve()) - .catch((error) => reject(error)); + return; }); }; @@ -699,70 +463,31 @@ export const newHttpRequest = (params) => (dispatch, getState) => { } }; - if (isLocalCollection(collection)) { - const filename = resolveRequestFilename(requestName); - if (!itemUid) { - const reqWithSameNameExists = find(collection.items, (i) => i.type !== 'folder' && trim(i.filename) === trim(filename)); + const filename = resolveRequestFilename(requestName); + if (!itemUid) { + const reqWithSameNameExists = find(collection.items, (i) => i.type !== 'folder' && trim(i.filename) === trim(filename)); + if (!reqWithSameNameExists) { + const fullName = `${collection.pathname}${PATH_SEPARATOR}${filename}`; + const { ipcRenderer } = window; + + ipcRenderer.invoke('renderer:new-request', fullName, item).then(resolve).catch(reject); + } else { + return reject(new Error(`${requestName} already exists in collection`)); + } + } else { + const currentItem = findItemInCollection(collection, itemUid); + if (currentItem) { + const reqWithSameNameExists = find(currentItem.items, (i) => i.type !== 'folder' && trim(i.filename) === trim(filename)); if (!reqWithSameNameExists) { - const fullName = `${collection.pathname}${PATH_SEPARATOR}${filename}`; + const fullName = `${currentItem.pathname}${PATH_SEPARATOR}${filename}`; const { ipcRenderer } = window; ipcRenderer.invoke('renderer:new-request', fullName, item).then(resolve).catch(reject); } else { - return reject(new Error(`${requestName} already exists in collection`)); - } - } else { - const currentItem = findItemInCollection(collection, itemUid); - if (currentItem) { - const reqWithSameNameExists = find(currentItem.items, (i) => i.type !== 'folder' && trim(i.filename) === trim(filename)); - if (!reqWithSameNameExists) { - const fullName = `${currentItem.pathname}${PATH_SEPARATOR}${filename}`; - const { ipcRenderer } = window; - - ipcRenderer.invoke('renderer:new-request', fullName, item).then(resolve).catch(reject); - } else { - return reject(new Error(`${requestName} already exists in the folder`)); - } + return reject(new Error(`${requestName} already exists in the folder`)); } } - return; } - - if (!itemUid) { - collectionCopy.items.push(item); - } else { - const currentItem = findItemInCollection(collectionCopy, itemUid); - if (currentItem && currentItem.type === 'folder') { - currentItem.items = currentItem.items || []; - currentItem.items.push(item); - } - } - const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); - - collectionSchema - .validate(collectionToSave) - .then(() => saveCollectionToIdb(window.__idb, collectionToSave)) - .then(() => { - dispatch( - _newItem({ - item: item, - currentItemUid: itemUid, - collectionUid: collectionUid - }) - ); - }) - .then(waitForNextTick) - .then(() => { - dispatch( - addTab({ - uid: item.uid, - collectionUid: collection.uid, - requestPaneTab: getDefaultRequestPaneTab(item) - }) - ); - }) - .then(() => resolve()) - .catch(reject); }); }; @@ -774,30 +499,8 @@ export const addEnvironment = (name, collectionUid) => (dispatch, getState) => { return reject(new Error('Collection not found')); } - const environment = { - uid: uuid(), - name: name, - variables: [] - }; - - const collectionCopy = cloneDeep(collection); - const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); - collectionToSave.environments = collectionToSave.environments || []; - collectionToSave.environments.push(environment); - - if (isLocalCollection(collection)) { - environmentsSchema - .validate(collectionToSave.environments) - .then(() => ipcRenderer.invoke('renderer:save-environment', collection.pathname, collectionToSave.environments)) - .then(resolve) - .catch(reject); - return; - } - - collectionSchema - .validate(collectionToSave) - .then(() => saveCollectionToIdb(window.__idb, collectionToSave)) - .then(() => dispatch(_addEnvironment({ environment, collectionUid }))) + ipcRenderer + .invoke('renderer:create-environment', collection.pathname, name) .then(resolve) .catch(reject); }); @@ -817,23 +520,12 @@ export const renameEnvironment = (newName, environmentUid, collectionUid) => (di return reject(new Error('Environment not found')); } + const oldName = environment.name; environment.name = newName; - const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); - if (isLocalCollection(collection)) { - const environments = collectionToSave.environments; - environmentsSchema - .validate(environments) - .then(() => ipcRenderer.invoke('renderer:save-environment', collection.pathname, environments)) - .then(resolve) - .catch(reject); - return; - } - - collectionSchema - .validate(collectionToSave) - .then(() => saveCollectionToIdb(window.__idb, collectionToSave)) - .then(() => dispatch(_renameEnvironment({ newName, environmentUid, collectionUid }))) + environmentSchema + .validate(environment) + .then(() => ipcRenderer.invoke('renderer:rename-environment', collection.pathname, oldName, newName)) .then(resolve) .catch(reject); }); @@ -854,23 +546,8 @@ export const deleteEnvironment = (environmentUid, collectionUid) => (dispatch, g return reject(new Error('Environment not found')); } - collectionCopy.environments = filter(collectionCopy.environments, (e) => e.uid !== environmentUid); - const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); - - if (isLocalCollection(collection)) { - const environments = collectionToSave.environments; - environmentsSchema - .validate(environments) - .then(() => ipcRenderer.invoke('renderer:save-environment', collection.pathname, environments)) - .then(resolve) - .catch(reject); - return; - } - - collectionSchema - .validate(collectionToSave) - .then(() => saveCollectionToIdb(window.__idb, collectionToSave)) - .then(() => dispatch(_deleteEnvironment({ environmentUid, collectionUid }))) + ipcRenderer + .invoke('renderer:delete-environment', collection.pathname, environment.name) .then(resolve) .catch(reject); }); @@ -892,21 +569,9 @@ export const saveEnvironment = (variables, environmentUid, collectionUid) => (di environment.variables = variables; - const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); - if (isLocalCollection(collection)) { - const environments = collectionToSave.environments; - environmentsSchema - .validate(environments) - .then(() => ipcRenderer.invoke('renderer:save-environment', collection.pathname, environments)) - .then(resolve) - .catch(reject); - return; - } - - collectionSchema - .validate(collectionToSave) - .then(() => saveCollectionToIdb(window.__idb, collectionToSave)) - .then(() => dispatch(_saveEnvironment({ variables, environmentUid, collectionUid }))) + environmentSchema + .validate(environment) + .then(() => ipcRenderer.invoke('renderer:save-environment', collection.pathname, environment)) .then(resolve) .catch(reject); }); @@ -928,19 +593,12 @@ export const selectEnvironment = (environmentUid, collectionUid) => (dispatch, g } } - collectionCopy.activeEnvironmentUid = environmentUid; - const collectionToSave = transformCollectionToSaveToIdb(collectionCopy); - - collectionSchema - .validate(collectionToSave) - .then(() => saveCollectionToIdb(window.__idb, collectionToSave)) - .then(() => dispatch(_selectEnvironment({ environmentUid, collectionUid }))) - .then(resolve) - .catch(reject); + dispatch(_selectEnvironment({ environmentUid, collectionUid })); + resolve(); }); }; -export const removeLocalCollection = (collectionUid) => (dispatch, getState) => { +export const removeCollection = (collectionUid) => (dispatch, getState) => { return new Promise((resolve, reject) => { const state = getState(); const collection = findCollectionByUid(state.collections.collections, collectionUid); @@ -960,7 +618,7 @@ export const removeLocalCollection = (collectionUid) => (dispatch, getState) => .then(waitForNextTick) .then(() => { dispatch( - _deleteCollection({ + _removeCollection({ collectionUid: collectionUid }) ); @@ -970,7 +628,7 @@ export const removeLocalCollection = (collectionUid) => (dispatch, getState) => }); }; -export const browserLocalDirectory = () => (dispatch, getState) => { +export const browseDirectory = () => (dispatch, getState) => { const { ipcRenderer } = window; return new Promise((resolve, reject) => { @@ -978,8 +636,8 @@ export const browserLocalDirectory = () => (dispatch, getState) => { }); }; -export const openLocalCollectionEvent = (uid, pathname, name) => (dispatch, getState) => { - const localCollection = { +export const openCollectionEvent = (uid, pathname, name) => (dispatch, getState) => { + const collection = { version: '1', uid: uid, name: name, @@ -989,14 +647,14 @@ export const openLocalCollectionEvent = (uid, pathname, name) => (dispatch, getS return new Promise((resolve, reject) => { collectionSchema - .validate(localCollection) - .then(() => dispatch(_createCollection(localCollection))) + .validate(collection) + .then(() => dispatch(_createCollection(collection))) .then(resolve) .catch(reject); }); }; -export const createLocalCollection = (collectionName, collectionLocation) => () => { +export const createCollection = (collectionName, collectionLocation) => () => { const { ipcRenderer } = window; return new Promise((resolve, reject) => { @@ -1004,7 +662,7 @@ export const createLocalCollection = (collectionName, collectionLocation) => () }); }; -export const openLocalCollection = () => () => { +export const openCollection = () => () => { return new Promise((resolve, reject) => { const { ipcRenderer } = window; @@ -1012,8 +670,8 @@ export const openLocalCollection = () => () => { }); }; -export const localCollectionLoadEnvironmentsEvent = (payload) => (dispatch, getState) => { - const { data: environments, meta } = payload; +export const collectionAddEnvFileEvent = (payload) => (dispatch, getState) => { + const { data: environment, meta } = payload; return new Promise((resolve, reject) => { const state = getState(); @@ -1022,12 +680,12 @@ export const localCollectionLoadEnvironmentsEvent = (payload) => (dispatch, getS return reject(new Error('Collection not found')); } - environmentsSchema - .validate(environments) + environmentSchema + .validate(environment) .then(() => dispatch( - _localCollectionLoadEnvironmentsEvent({ - environments, + _collectionAddEnvFileEvent({ + environment, collectionUid: meta.collectionUid }) ) @@ -1036,3 +694,14 @@ export const localCollectionLoadEnvironmentsEvent = (payload) => (dispatch, getS .catch(reject); }); }; + +export const importCollection = (collection, collectionLocation) => (dispatch, getState) => { + return new Promise((resolve, reject) => { + const { ipcRenderer } = window; + + ipcRenderer + .invoke('renderer:import-collection', collection, collectionLocation) + .then(resolve) + .catch(reject); + }); +}; 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 1a9b3ec1..ab8f22f8 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js @@ -32,26 +32,6 @@ export const collectionsSlice = createSlice({ name: 'collections', initialState, reducers: { - loadCollections: (state, action) => { - const collectionUids = map(state.collections, (c) => c.uid); - each(action.payload.collections, (c) => collapseCollection(c)); - each(action.payload.collections, (c) => addDepth(c.items)); - each(action.payload.collections, (c) => { - if (!collectionUids.includes(c.uid)) { - state.collections.push(c); - collectionUids.push(c.uid); - } - }); - }, - collectionImported: (state, action) => { - const collectionUids = map(state.collections, (c) => c.uid); - const { collection } = action.payload; - collapseCollection(collection); - addDepth(collection.items); - if (!collectionUids.includes(collection.uid)) { - state.collections.push(collection); - } - }, createCollection: (state, action) => { const collectionUids = map(state.collections, (c) => c.uid); const collection = action.payload; @@ -68,7 +48,7 @@ export const collectionsSlice = createSlice({ collection.name = action.payload.newName; } }, - deleteCollection: (state, action) => { + removeCollection: (state, action) => { state.collections = filter(state.collections, (c) => c.uid !== action.payload.collectionUid); }, addEnvironment: (state, action) => { @@ -80,28 +60,12 @@ export const collectionsSlice = createSlice({ collection.environments.push(environment); } }, - renameEnvironment: (state, action) => { - const { newName, environmentUid, collectionUid } = action.payload; - const collection = findCollectionByUid(state.collections, collectionUid); + collectionUnlinkEnvFileEvent: (state, action) => { + const { data: environment, meta } = action.payload; + const collection = findCollectionByUid(state.collections, meta.collectionUid); if (collection) { - const environment = findEnvironmentInCollection(collection, environmentUid); - - if (environment) { - environment.name = newName; - } - } - }, - deleteEnvironment: (state, action) => { - const { environmentUid, collectionUid } = action.payload; - const collection = findCollectionByUid(state.collections, collectionUid); - - if (collection) { - const environment = findEnvironmentInCollection(collection, environmentUid); - - if (environment) { - collection.environments = filter(collection.environments, (e) => e.uid !== environmentUid); - } + collection.environments = filter(collection.environments, (e) => e.uid !== environment.uid); } }, saveEnvironment: (state, action) => { @@ -669,7 +633,7 @@ export const collectionsSlice = createSlice({ } } }, - localCollectionAddFileEvent: (state, action) => { + collectionAddFileEvent: (state, action) => { const file = action.payload.file; const collection = findCollectionByUid(state.collections, file.meta.collectionUid); @@ -723,7 +687,7 @@ export const collectionsSlice = createSlice({ addDepth(collection.items); } }, - localCollectionAddDirectoryEvent: (state, action) => { + collectionAddDirectoryEvent: (state, action) => { const { dir } = action.payload; const collection = findCollectionByUid(state.collections, dir.meta.collectionUid); @@ -751,7 +715,7 @@ export const collectionsSlice = createSlice({ addDepth(collection.items); } }, - localCollectionChangeFileEvent: (state, action) => { + collectionChangeFileEvent: (state, action) => { const { file } = action.payload; const collection = findCollectionByUid(state.collections, file.meta.collectionUid); @@ -768,7 +732,7 @@ export const collectionsSlice = createSlice({ } } }, - localCollectionUnlinkFileEvent: (state, action) => { + collectionUnlinkFileEvent: (state, action) => { const { file } = action.payload; const collection = findCollectionByUid(state.collections, file.meta.collectionUid); @@ -780,7 +744,7 @@ export const collectionsSlice = createSlice({ } } }, - localCollectionUnlinkDirectoryEvent: (state, action) => { + collectionUnlinkDirectoryEvent: (state, action) => { const { directory } = action.payload; const collection = findCollectionByUid(state.collections, directory.meta.collectionUid); @@ -792,26 +756,31 @@ export const collectionsSlice = createSlice({ } } }, - localCollectionLoadEnvironmentsEvent: (state, action) => { - const { environments, collectionUid } = action.payload; + collectionAddEnvFileEvent: (state, action) => { + const { environment, collectionUid } = action.payload; const collection = findCollectionByUid(state.collections, collectionUid); if (collection) { - collection.environments = environments; + collection.environments = collection.environments || []; + + const existingEnv = collection.environments.find((e) => e.uid === environment.uid); + + if (existingEnv) { + existingEnv.variables = environment.variables; + } else { + collection.environments.push(environment); + } } } } }); export const { - collectionImported, createCollection, renameCollection, - deleteCollection, - loadCollections, + removeCollection, addEnvironment, - renameEnvironment, - deleteEnvironment, + collectionUnlinkEnvFileEvent, saveEnvironment, selectEnvironment, newItem, @@ -844,12 +813,12 @@ export const { updateRequestBody, updateRequestGraphqlQuery, updateRequestMethod, - localCollectionAddFileEvent, - localCollectionAddDirectoryEvent, - localCollectionChangeFileEvent, - localCollectionUnlinkFileEvent, - localCollectionUnlinkDirectoryEvent, - localCollectionLoadEnvironmentsEvent + collectionAddFileEvent, + collectionAddDirectoryEvent, + collectionChangeFileEvent, + collectionUnlinkFileEvent, + collectionUnlinkDirectoryEvent, + collectionAddEnvFileEvent } = collectionsSlice.actions; export default collectionsSlice.reducer; diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js b/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js deleted file mode 100644 index ac0e559c..00000000 --- a/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js +++ /dev/null @@ -1,222 +0,0 @@ -import find from 'lodash/find'; -import filter from 'lodash/filter'; -import { uuid } from 'utils/common'; -import cloneDeep from 'lodash/cloneDeep'; -import { workspaceSchema } from '@usebruno/schema'; -import { findCollectionInWorkspace } from 'utils/workspaces'; -import { getWorkspacesFromIdb, saveWorkspaceToIdb, deleteWorkspaceInIdb } from 'utils/idb/workspaces'; -import { BrunoError } from 'utils/common/error'; -import { - loadWorkspaces, - addWorkspace as _addWorkspace, - renameWorkspace as _renameWorkspace, - deleteWorkspace as _deleteWorkspace, - addCollectionToWorkspace as _addCollectionToWorkspace, - removeCollectionFromWorkspace as _removeCollectionFromWorkspace -} from './index'; - -const seedWorkpace = () => { - const uid = uuid(); - const workspace = { - uid: uid, - name: 'My workspace', - collections: [] - }; - - return new Promise((resolve, reject) => { - workspaceSchema - .validate(workspace) - .then(() => saveWorkspaceToIdb(window.__idb, workspace)) - .then(() => resolve([workspace])) - .catch(reject); - }); -}; - -export const loadWorkspacesFromIdb = () => (dispatch) => { - return new Promise((resolve, reject) => { - getWorkspacesFromIdb(window.__idb) - .then((workspaces) => { - if (!workspaces || !workspaces.length) { - return seedWorkpace(); - } - - return workspaces; - }) - .then((workspaces) => - dispatch( - loadWorkspaces({ - workspaces: workspaces - }) - ) - ) - .then(resolve) - .catch(reject); - }); -}; - -export const addWorkspace = (workspaceName) => (dispatch) => { - const newWorkspace = { - uid: uuid(), - name: workspaceName, - collections: [] - }; - - return new Promise((resolve, reject) => { - workspaceSchema - .validate(newWorkspace) - .then(() => saveWorkspaceToIdb(window.__idb, newWorkspace)) - .then(() => - dispatch( - _addWorkspace({ - workspace: newWorkspace - }) - ) - ) - .then(resolve) - .catch(reject); - }); -}; - -export const renameWorkspace = (newName, uid) => (dispatch, getState) => { - const state = getState(); - - return new Promise((resolve, reject) => { - const workspace = find(state.workspaces.workspaces, (w) => w.uid === uid); - - if (!workspace) { - return reject(new Error('Workspace not found')); - } - - const workspaceCopy = cloneDeep(workspace); - workspaceCopy.name = newName; - - workspaceSchema - .validate(workspaceCopy) - .then(() => saveWorkspaceToIdb(window.__idb, workspaceCopy)) - .then(() => - dispatch( - _renameWorkspace({ - uid: uid, - name: newName - }) - ) - ) - .then(resolve) - .catch(reject); - }); -}; - -export const deleteWorkspace = (workspaceUid) => (dispatch, getState) => { - const state = getState(); - - return new Promise((resolve, reject) => { - if (state.workspaces.activeWorkspaceUid === workspaceUid) { - throw new BrunoError('Cannot delete current workspace'); - } - - const workspace = find(state.workspaces.workspaces, (w) => w.uid === workspaceUid); - - if (!workspace) { - return reject(new Error('Workspace not found')); - } - - deleteWorkspaceInIdb(window.__idb, workspaceUid) - .then(() => - dispatch( - _deleteWorkspace({ - workspaceUid: workspaceUid - }) - ) - ) - .then(resolve) - .catch(reject); - }); -}; - -export const addCollectionToWorkspace = (workspaceUid, collectionUid) => (dispatch, getState) => { - const state = getState(); - - return new Promise((resolve, reject) => { - const workspace = find(state.workspaces.workspaces, (w) => w.uid === workspaceUid); - const collection = find(state.collections.collections, (c) => c.uid === collectionUid); - - if (!workspace) { - return reject(new Error('Workspace not found')); - } - - if (!collection) { - return reject(new Error('Collection not found')); - } - - const workspaceCopy = cloneDeep(workspace); - if (workspaceCopy.collections && workspace.collections.length) { - if (!findCollectionInWorkspace(workspace, collectionUid)) { - workspaceCopy.collections.push({ - uid: collectionUid - }); - } - } else { - workspaceCopy.collections = [ - { - uid: collectionUid - } - ]; - } - - workspaceSchema - .validate(workspaceCopy) - .then(() => saveWorkspaceToIdb(window.__idb, workspaceCopy)) - .then(() => - dispatch( - _addCollectionToWorkspace({ - workspaceUid: workspaceUid, - collectionUid: collectionUid - }) - ) - ) - .then(resolve) - .catch(reject); - }); -}; - -export const removeCollectionFromWorkspace = (workspaceUid, collectionUid) => (dispatch, getState) => { - const state = getState(); - - return new Promise((resolve, reject) => { - const workspace = find(state.workspaces.workspaces, (w) => w.uid === workspaceUid); - const collection = find(state.collections.collections, (c) => c.uid === collectionUid); - - if (!workspace) { - return reject(new Error('Workspace not found')); - } - - if (!collection) { - return reject(new Error('Collection not found')); - } - - const workspaceCopy = cloneDeep(workspace); - if (workspaceCopy.collections && workspace.collections.length) { - workspaceCopy.collections = filter(workspaceCopy.collections, (c) => c.uid !== collectionUid); - } - - workspaceSchema - .validate(workspaceCopy) - .then(() => saveWorkspaceToIdb(window.__idb, workspaceCopy)) - .then(() => - dispatch( - _removeCollectionFromWorkspace({ - workspaceUid: workspaceUid, - collectionUid: collectionUid - }) - ) - ) - .then(resolve) - .catch(reject); - }); -}; - -// TODO -// Workspaces can have collection uids that no longer exist -// or the user may have the collections access revoked (in teams) -// This action will have to be called at the beginning to purge any zombi collection references in the workspaces -export const removeZombieCollectionFromAllWorkspaces = (workspaceUid) => (dispatch, getState) => {}; diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/index.js b/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/index.js deleted file mode 100644 index 1be9e641..00000000 --- a/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/index.js +++ /dev/null @@ -1,85 +0,0 @@ -import { createSlice } from '@reduxjs/toolkit'; -import find from 'lodash/find'; -import map from 'lodash/map'; -import filter from 'lodash/filter'; -import { findCollectionInWorkspace } from 'utils/workspaces'; -import cache from 'utils/common/cache'; - -const initialState = { - workspaces: [], - activeWorkspaceUid: null -}; - -export const workspacesSlice = createSlice({ - name: 'workspaces', - initialState, - reducers: { - loadWorkspaces: (state, action) => { - state.workspaces = action.payload.workspaces; - - if (state.workspaces && state.workspaces.length) { - const workspaceUids = map(state.workspaces, (w) => w.uid); - const activeWorkspaceUid = cache.getActiveWorkspaceUid(); - if (activeWorkspaceUid && workspaceUids.includes(activeWorkspaceUid)) { - state.activeWorkspaceUid = activeWorkspaceUid; - } else { - state.activeWorkspaceUid = state.workspaces[0].uid; - cache.setActiveWorkspaceUid(state.activeWorkspaceUid); - } - } - }, - selectWorkspace: (state, action) => { - state.activeWorkspaceUid = action.payload.workspaceUid; - cache.setActiveWorkspaceUid(state.activeWorkspaceUid); - }, - renameWorkspace: (state, action) => { - const { name, uid } = action.payload; - const workspace = find(state.workspaces, (w) => w.uid === uid); - - if (workspace) { - workspace.name = name; - } - }, - deleteWorkspace: (state, action) => { - if (state.activeWorkspaceUid === action.payload.workspaceUid) { - throw new Error('User cannot delete current workspace'); - } - state.workspaces = state.workspaces.filter((workspace) => workspace.uid !== action.payload.workspaceUid); - }, - addWorkspace: (state, action) => { - state.workspaces.push(action.payload.workspace); - }, - addCollectionToWorkspace: (state, action) => { - const { workspaceUid, collectionUid } = action.payload; - const workspace = find(state.workspaces, (w) => w.uid === workspaceUid); - - if (workspace) { - if (workspace.collections && workspace.collections.length) { - if (!findCollectionInWorkspace(workspace, collectionUid)) { - workspace.collections.push({ - uid: collectionUid - }); - } - } else { - workspace.collections = [ - { - uid: collectionUid - } - ]; - } - } - }, - removeCollectionFromWorkspace: (state, action) => { - const { workspaceUid, collectionUid } = action.payload; - const workspace = find(state.workspaces, (w) => w.uid === workspaceUid); - - if (workspace && workspace.collections && workspace.collections.length) { - workspace.collections = filter(workspace.collections, (c) => c.uid !== collectionUid); - } - } - } -}); - -export const { loadWorkspaces, selectWorkspace, renameWorkspace, deleteWorkspace, addWorkspace, addCollectionToWorkspace, removeCollectionFromWorkspace } = workspacesSlice.actions; - -export default workspacesSlice.reducer; diff --git a/packages/bruno-app/src/themes/dark.js b/packages/bruno-app/src/themes/dark.js index 16cccca4..dff763d7 100644 --- a/packages/bruno-app/src/themes/dark.js +++ b/packages/bruno-app/src/themes/dark.js @@ -24,7 +24,7 @@ const darkTheme = { bg: '#252526', dragbar: '#8a8a8a', - workspace: { + badge: { bg: '#3D3D3D' }, diff --git a/packages/bruno-app/src/themes/light.js b/packages/bruno-app/src/themes/light.js index 6c7578dc..da6afd73 100644 --- a/packages/bruno-app/src/themes/light.js +++ b/packages/bruno-app/src/themes/light.js @@ -24,7 +24,7 @@ const lightTheme = { bg: '#F3F3F3', dragbar: 'rgb(200, 200, 200)', - workspace: { + badge: { bg: '#e1e1e1' }, diff --git a/packages/bruno-app/src/utils/collections/export.js b/packages/bruno-app/src/utils/collections/export.js index 579feaeb..43cc4f96 100644 --- a/packages/bruno-app/src/utils/collections/export.js +++ b/packages/bruno-app/src/utils/collections/export.js @@ -1,6 +1,37 @@ import * as FileSaver from 'file-saver'; +import get from 'lodash/get'; +import each from 'lodash/each'; + +const deleteUidsInItems = (items) => { + each(items, (item) => { + delete item.uid; + + if (['http-request', 'graphql-request'].includes(item.type)) { + each(get(item, 'request.headers'), (header) => delete header.uid); + each(get(item, 'request.params'), (param) => delete param.uid); + each(get(item, 'request.body.multipartForm'), (param) => delete param.uid); + each(get(item, 'request.body.formUrlEncoded'), (param) => delete param.uid); + } + + if (item.items && item.items.length) { + deleteUidsInItems(item.items); + } + }); +}; + +const deleteUidsInEnvs = (envs) => { + each(envs, (env) => { + delete env.uid; + each(env.variables, (variable) => delete variable.uid); + }); +}; const exportCollection = (collection) => { + // delete uids + delete collection.uid; + deleteUidsInItems(collection.items); + deleteUidsInEnvs(collection.environments); + const fileName = `${collection.name}.json`; const fileBlob = new Blob([JSON.stringify(collection, null, 2)], { type: 'application/json' }); diff --git a/packages/bruno-app/src/utils/common/cache.js b/packages/bruno-app/src/utils/common/cache.js index 88517f20..d8cee9e5 100644 --- a/packages/bruno-app/src/utils/common/cache.js +++ b/packages/bruno-app/src/utils/common/cache.js @@ -5,14 +5,6 @@ class Cache { set(key, val) { window.localStorage.setItem(key, val); } - - getActiveWorkspaceUid() { - return this.get('bruno.activeWorkspaceUid'); - } - - setActiveWorkspaceUid(workspaceUid) { - this.set('bruno.activeWorkspaceUid', workspaceUid); - } } module.exports = new Cache(); diff --git a/packages/bruno-app/src/utils/idb/index.js b/packages/bruno-app/src/utils/idb/index.js index 8e066668..28ef2790 100644 --- a/packages/bruno-app/src/utils/idb/index.js +++ b/packages/bruno-app/src/utils/idb/index.js @@ -13,20 +13,6 @@ 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(collectionUid); - tx.onerror = () => reject(tx.error); - }) - .catch((err) => reject(err)); - }); -}; - export const getCollectionsFromIdb = (connection) => { return new Promise((resolve, reject) => { connection diff --git a/packages/bruno-app/src/utils/idb/workspaces.js b/packages/bruno-app/src/utils/idb/workspaces.js deleted file mode 100644 index 29be46db..00000000 --- a/packages/bruno-app/src/utils/idb/workspaces.js +++ /dev/null @@ -1,59 +0,0 @@ -import isArray from 'lodash/isArray'; - -export const saveWorkspaceToIdb = (connection, workspace) => { - return new Promise((resolve, reject) => { - connection - .then((db) => { - let tx = db.transaction(`workspace`, 'readwrite'); - let workspaceStore = tx.objectStore('workspace'); - - if (isArray(workspace)) { - for (let c of workspace) { - workspaceStore.put(c); - } - } else { - workspaceStore.put(workspace); - } - - return new Promise((res, rej) => { - tx.oncomplete = () => res(); - tx.onerror = () => rej(tx.error); - }); - }) - .then(resolve) - .catch((err) => reject(err)); - }); -}; - -export const deleteWorkspaceInIdb = (connection, workspaceUid) => { - return new Promise((resolve, reject) => { - connection - .then((db) => { - let tx = db.transaction(`workspace`, 'readwrite'); - tx.objectStore('workspace').delete(workspaceUid); - - tx.oncomplete = () => resolve(); - tx.onerror = () => reject(tx.error); - }) - .catch((err) => reject(err)); - }); -}; - -export const getWorkspacesFromIdb = (connection) => { - return new Promise((resolve, reject) => { - connection - .then((db) => { - let tx = db.transaction('workspace'); - let workspaceStore = tx.objectStore('workspace'); - return workspaceStore.getAll(); - }) - .then((workspaces) => { - if (!Array.isArray(workspaces)) { - return new Error('IDB Corrupted'); - } - - return resolve(workspaces); - }) - .catch((err) => reject(err)); - }); -}; diff --git a/packages/bruno-app/src/utils/importers/bruno-collection.js b/packages/bruno-app/src/utils/importers/bruno-collection.js index 847b2f61..019314d5 100644 --- a/packages/bruno-app/src/utils/importers/bruno-collection.js +++ b/packages/bruno-app/src/utils/importers/bruno-collection.js @@ -1,8 +1,6 @@ import fileDialog from 'file-dialog'; -import { saveCollectionToIdb } from 'utils/idb'; import { BrunoError } from 'utils/common/error'; import { validateSchema, updateUidsInCollection } from './common'; -import sampleCollection from './samples/sample-collection.json'; const readFile = (files) => { return new Promise((resolve, reject) => { @@ -30,10 +28,8 @@ const importCollection = () => { fileDialog({ accept: 'application/json' }) .then(readFile) .then(parseJsonCollection) - .then(validateSchema) .then(updateUidsInCollection) .then(validateSchema) - .then((collection) => saveCollectionToIdb(window.__idb, collection)) .then((collection) => resolve(collection)) .catch((err) => { console.log(err); @@ -42,15 +38,4 @@ const importCollection = () => { }); }; -export const importSampleCollection = () => { - return new Promise((resolve, reject) => { - validateSchema(sampleCollection) - .then(updateUidsInCollection) - .then(validateSchema) - .then((collection) => saveCollectionToIdb(window.__idb, collection)) - .then(resolve) - .catch(reject); - }); -}; - export default importCollection; diff --git a/packages/bruno-app/src/utils/importers/common.js b/packages/bruno-app/src/utils/importers/common.js index eee7108f..e9995b73 100644 --- a/packages/bruno-app/src/utils/importers/common.js +++ b/packages/bruno-app/src/utils/importers/common.js @@ -40,5 +40,14 @@ export const updateUidsInCollection = (_collection) => { }; updateItemUids(collection.items); + const updateEnvUids = (envs = []) => { + each(envs, (env) => { + env.uid = uuid(); + each(env.variables, (variable) => (variable.uid = uuid())); + }); + }; + updateEnvUids(collection.environments); + updateEnvUids(collection.environments); + return collection; }; diff --git a/packages/bruno-app/src/utils/importers/postman-collection.js b/packages/bruno-app/src/utils/importers/postman-collection.js index e0976dd7..23265f55 100644 --- a/packages/bruno-app/src/utils/importers/postman-collection.js +++ b/packages/bruno-app/src/utils/importers/postman-collection.js @@ -2,7 +2,6 @@ import each from 'lodash/each'; import get from 'lodash/get'; import fileDialog from 'file-dialog'; import { uuid } from 'utils/common'; -import { saveCollectionToIdb } from 'utils/idb'; import { BrunoError } from 'utils/common/error'; import { validateSchema, updateUidsInCollection } from './common'; @@ -180,9 +179,6 @@ const importCollection = () => { .then(readFile) .then(parsePostmanCollection) .then(validateSchema) - .then(updateUidsInCollection) - .then(validateSchema) - .then((collection) => saveCollectionToIdb(window.__idb, collection)) .then((collection) => resolve(collection)) .catch((err) => { console.log(err); diff --git a/packages/bruno-app/src/utils/importers/samples/sample-collection.json b/packages/bruno-app/src/utils/importers/samples/sample-collection.json deleted file mode 100644 index 51468b5e..00000000 --- a/packages/bruno-app/src/utils/importers/samples/sample-collection.json +++ /dev/null @@ -1,129 +0,0 @@ -{ - "name": "sample-collection", - "uid": "c1PdISj460OeNmFLI8rCY", - "version": "1", - "items": [ - { - "uid": "myeFbgzNlwIhDpYcOVBWS", - "type": "http-request", - "name": "Users", - "request": { - "url": "https://reqres.in/api/users?page=2", - "method": "GET", - "headers": [], - "params": [ - { - "uid": "viHGWSpAQhpiwH9UQxb7W", - "name": "page", - "value": "2", - "enabled": true - } - ], - "body": { - "mode": "json", - "json": "", - "text": null, - "xml": null, - "formUrlEncoded": [], - "multipartForm": [] - } - } - }, - { - "uid": "ytzXIADbhEwLB0BqIQOKD", - "type": "http-request", - "name": "Single User", - "request": { - "url": "https://reqres.in/api/users/2", - "method": "GET", - "headers": [], - "params": [], - "body": { - "mode": "json", - "json": "", - "text": null, - "xml": null, - "formUrlEncoded": [], - "multipartForm": [] - } - } - }, - { - "uid": "DuEyHudhVuxrdplKLAMsU", - "type": "http-request", - "name": "User Not Found", - "request": { - "url": "https://reqres.in/api/users/23", - "method": "GET", - "headers": [], - "params": [], - "body": { - "mode": "json", - "json": "", - "text": null, - "xml": null, - "formUrlEncoded": [], - "multipartForm": [] - } - } - }, - { - "uid": "UZFjsr14q8iZ1Do90q02Q", - "type": "http-request", - "name": "Create", - "request": { - "url": "https://reqres.in/api/users", - "method": "POST", - "headers": [], - "params": [], - "body": { - "mode": "json", - "json": "{\n \"name\": \"morpheus\",\n \"job\": \"leader\"\n}", - "text": null, - "xml": null, - "formUrlEncoded": [], - "multipartForm": [] - } - } - }, - { - "uid": "lYLCTXaerD9etRDLJHbVN", - "type": "http-request", - "name": "Update", - "request": { - "url": "https://reqres.in/api/users/2", - "method": "PUT", - "headers": [], - "params": [], - "body": { - "mode": "json", - "json": "{\n \"name\": \"morpheus\",\n \"job\": \"zion resident\"\n}", - "text": null, - "xml": null, - "formUrlEncoded": [], - "multipartForm": [] - } - } - }, - { - "uid": "qVCKx5xUqxpBf8jeka8Gu", - "type": "http-request", - "name": "Remove", - "request": { - "url": "https://reqres.in/api/users/2", - "method": "DELETE", - "headers": [], - "params": [], - "body": { - "mode": "json", - "json": "{\n \"name\": \"morpheus\",\n \"job\": \"zion resident\"\n}", - "text": null, - "xml": null, - "formUrlEncoded": [], - "multipartForm": [] - } - } - } - ], - "environments": [] -} diff --git a/packages/bruno-app/src/utils/workspaces/index.js b/packages/bruno-app/src/utils/workspaces/index.js deleted file mode 100644 index 77f56a03..00000000 --- a/packages/bruno-app/src/utils/workspaces/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import find from 'lodash/find'; - -export const findCollectionInWorkspace = (workspace, collectionUid) => { - return find(workspace.collections, (c) => c.uid === collectionUid); -}; diff --git a/packages/bruno-electron/src/app/collections.js b/packages/bruno-electron/src/app/collections.js index 04dfd58f..870b1f5e 100644 --- a/packages/bruno-electron/src/app/collections.js +++ b/packages/bruno-electron/src/app/collections.js @@ -5,13 +5,14 @@ const Yup = require('yup'); const { isDirectory, normalizeAndResolvePath } = require('../utils/filesystem'); const { generateUidBasedOnHash } = require('../utils/common'); +// uid inside collections is deprecated, but we still need to validate it +// for backward compatibility const uidSchema = Yup.string() .length(21, 'uid must be 21 characters in length') - .matches(/^[a-zA-Z0-9]*$/, 'uid must be alphanumeric') - .required('uid is required') - .strict(); + .matches(/^[a-zA-Z0-9]*$/, 'uid must be alphanumeric'); const configSchema = Yup.object({ + uid: uidSchema, name: Yup.string().nullable().max(256, 'name must be 256 characters or less'), type: Yup.string().oneOf(['collection']).required('type is required'), version: Yup.string().oneOf(['1']).required('type is required') diff --git a/packages/bruno-electron/src/app/watcher.js b/packages/bruno-electron/src/app/watcher.js index 1a53c497..c156a62e 100644 --- a/packages/bruno-electron/src/app/watcher.js +++ b/packages/bruno-electron/src/app/watcher.js @@ -5,17 +5,27 @@ const chokidar = require('chokidar'); const { hasJsonExtension, hasBruExtension, writeFile } = require('../utils/filesystem'); const { bruToJson, - jsonToBru + jsonToBru, + bruToEnvJson, + envJsonToBru, } = require('@usebruno/bruno-lang'); const { itemSchema } = require('@usebruno/schema'); const { generateUidBasedOnHash, uuid } = require('../utils/common'); -const isEnvironmentConfig = (pathname, collectionPath) => { +const isJsonEnvironmentConfig = (pathname, collectionPath) => { const dirname = path.dirname(pathname); const basename = path.basename(pathname); return dirname === collectionPath && basename === 'environments.json'; -} +}; + +const isBruEnvironmentConfig = (pathname, collectionPath) => { + const dirname = path.dirname(pathname); + const envDirectory = path.join(collectionPath, 'environments'); + const basename = path.basename(pathname); + + return dirname === envDirectory && hasBruExtension(basename); +}; const hydrateRequestWithUuid = (request, pathname) => { request.uid = generateUidBasedOnHash(pathname); @@ -35,16 +45,21 @@ const hydrateRequestWithUuid = (request, pathname) => { const addEnvironmentFile = async (win, pathname, collectionUid) => { try { + const basename = path.basename(pathname); const file = { meta: { collectionUid, pathname, - name: path.basename(pathname), - } + name: basename + }, }; - const jsonData = fs.readFileSync(pathname, 'utf8'); - file.data = JSON.parse(jsonData); + const bruContent = fs.readFileSync(pathname, 'utf8'); + file.data = bruToEnvJson(bruContent); + file.data.name = basename.substring(0, basename.length - 4); + file.data.uid = generateUidBasedOnHash(pathname); + + _.each(_.get(file, 'data.variables', []), (variable) => variable.uid = uuid()); win.webContents.send('main:collection-tree-updated', 'addEnvironmentFile', file); } catch (err) { console.error(err) @@ -53,17 +68,25 @@ const addEnvironmentFile = async (win, pathname, collectionUid) => { const changeEnvironmentFile = async (win, pathname, collectionUid) => { try { + const basename = path.basename(pathname); const file = { meta: { collectionUid, pathname, - name: path.basename(pathname), + name: basename } }; - const jsonData = fs.readFileSync(pathname, 'utf8'); - file.data = JSON.parse(jsonData); - win.webContents.send('main:collection-tree-updated', 'changeEnvironmentFile', file); + const bruContent = fs.readFileSync(pathname, 'utf8'); + file.data = bruToEnvJson(bruContent); + file.data.name = basename.substring(0, basename.length - 4); + file.data.uid = generateUidBasedOnHash(pathname); + _.each(_.get(file, 'data.variables', []), (variable) => variable.uid = uuid()); + + // we are reusing the addEnvironmentFile event itself + // this is because the uid of the pathname remains the same + // and the collection tree will be able to update the existing environment + win.webContents.send('main:collection-tree-updated', 'addEnvironmentFile', file); } catch (err) { console.error(err) } @@ -77,23 +100,49 @@ const unlinkEnvironmentFile = async (win, pathname, collectionUid) => { pathname, name: path.basename(pathname), }, - data: [] + data: { + uid: generateUidBasedOnHash(pathname), + name: path.basename(pathname).substring(0, path.basename(pathname).length - 4), + } }; - win.webContents.send('main:collection-tree-updated', 'changeEnvironmentFile', file); + win.webContents.send('main:collection-tree-updated', 'unlinkEnvironmentFile', file); } catch (err) { console.error(err) } }; const add = async (win, pathname, collectionUid, collectionPath) => { - const isJson = hasJsonExtension(pathname); console.log(`watcher add: ${pathname}`); - if(isJson) { - if(isEnvironmentConfig(pathname, collectionPath)) { - return addEnvironmentFile(win, pathname, collectionUid); + if(isJsonEnvironmentConfig(pathname, collectionPath)) { + // migrate old env json to bru file + try { + const dirname = path.dirname(pathname); + const jsonStr = fs.readFileSync(pathname, 'utf8'); + const jsonData = JSON.parse(jsonStr); + + const envDirectory = path.join(dirname, 'environments'); + if (!fs.existsSync(envDirectory)) { + fs.mkdirSync(envDirectory); + } + + for(const env of jsonData) { + const bruEnvFilename = path.join(envDirectory, `${env.name}.bru`); + const bruContent = envJsonToBru(env); + await writeFile(bruEnvFilename, bruContent); + } + + await fs.unlinkSync(pathname); + } catch (err) { + // do nothing } + + return; + } + + if(isBruEnvironmentConfig(pathname, collectionPath)) { + return addEnvironmentFile(win, pathname, collectionUid); } // migrate old json files to bru @@ -137,8 +186,14 @@ const add = async (win, pathname, collectionUid, collectionPath) => { } }; -const addDirectory = (win, pathname, collectionUid) => { - console.log(`watcher addDirectory: ${pathname}`); +const addDirectory = (win, pathname, collectionUid, collectionPath) => { + const dirname = path.dirname(pathname); + const envDirectory = path.join(collectionPath, 'environments'); + + if(dirname === envDirectory) { + return; + } + const directory = { meta: { collectionUid, @@ -150,9 +205,7 @@ const addDirectory = (win, pathname, collectionUid) => { }; const change = async (win, pathname, collectionUid, collectionPath) => { - console.log(`watcher change: ${pathname}`); - - if(isEnvironmentConfig(pathname, collectionPath)) { + if(isBruEnvironmentConfig(pathname, collectionPath)) { return changeEnvironmentFile(win, pathname, collectionUid); } @@ -178,7 +231,7 @@ const change = async (win, pathname, collectionUid, collectionPath) => { }; const unlink = (win, pathname, collectionUid, collectionPath) => { - if(isEnvironmentConfig(pathname, collectionPath)) { + if(isBruEnvironmentConfig(pathname, collectionPath)) { return unlinkEnvironmentFile(win, pathname, collectionUid); } @@ -195,6 +248,13 @@ const unlink = (win, pathname, collectionUid, collectionPath) => { } const unlinkDir = (win, pathname, collectionUid) => { + const dirname = path.dirname(pathname); + const envDirectory = path.join(collectionPath, 'environments'); + + if(dirname === envDirectory) { + return; + } + const directory = { meta: { collectionUid, diff --git a/packages/bruno-electron/src/ipc/local-collection.js b/packages/bruno-electron/src/ipc/local-collection.js index 9cae43ef..918d7aa0 100644 --- a/packages/bruno-electron/src/ipc/local-collection.js +++ b/packages/bruno-electron/src/ipc/local-collection.js @@ -5,6 +5,7 @@ const { ipcMain } = require('electron'); const { jsonToBru, bruToJson, + envJsonToBru, } = require('@usebruno/bruno-lang'); const { isValidPathname, @@ -16,6 +17,7 @@ const { } = require('../utils/filesystem'); const { uuid, stringifyJson } = require('../utils/common'); const { openCollectionDialog, openCollection } = require('../app/collections'); +const { generateUidBasedOnHash } = require('../utils/common'); const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollections) => { // browse directory @@ -43,10 +45,9 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection await createDirectory(dirPath); - const uid = uuid(); + const uid = generateUidBasedOnHash(dirPath); const content = await stringifyJson({ version: '1', - uid: uid, name: collectionName, type: 'collection' }); @@ -89,18 +90,83 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection } }); - // save environment - ipcMain.handle('renderer:save-environment', async (event, collectionPathname, environments) => { + // create environment + ipcMain.handle('renderer:create-environment', async (event, collectionPathname, name) => { try { - const envFilePath = path.join(collectionPathname, 'environments.json'); + const envDirPath = path.join(collectionPathname, 'environments'); + if (!fs.existsSync(envDirPath)){ + await createDirectory(envDirPath); + } - const content = await stringifyJson(environments); + const envFilePath = path.join(envDirPath, `${name}.bru`); + if (fs.existsSync(envFilePath)){ + throw new Error(`environment: ${envFilePath} already exists`); + } + + const content = envJsonToBru({ + variables: [] + }); await writeFile(envFilePath, content); } catch (error) { return Promise.reject(error); } }); + // save environment + ipcMain.handle('renderer:save-environment', async (event, collectionPathname, environment) => { + try { + const envDirPath = path.join(collectionPathname, 'environments'); + if (!fs.existsSync(envDirPath)){ + await createDirectory(envDirPath); + } + + const envFilePath = path.join(envDirPath, `${environment.name}.bru`); + if (!fs.existsSync(envFilePath)){ + throw new Error(`environment: ${envFilePath} does not exist`); + } + + const content = envJsonToBru(environment); + await writeFile(envFilePath, content); + } catch (error) { + return Promise.reject(error); + } + }); + + // rename environment + ipcMain.handle('renderer:rename-environment', async (event, collectionPathname, environmentName, newName) => { + try { + const envDirPath = path.join(collectionPathname, 'environments'); + const envFilePath = path.join(envDirPath, `${environmentName}.bru`); + if (!fs.existsSync(envFilePath)){ + throw new Error(`environment: ${envFilePath} does not exist`); + } + + const newEnvFilePath = path.join(envDirPath, `${newName}.bru`); + if (fs.existsSync(newEnvFilePath)){ + throw new Error(`environment: ${newEnvFilePath} already exists`); + } + + fs.renameSync(envFilePath, newEnvFilePath); + } catch (error) { + return Promise.reject(error); + } + }); + + // delete environment + ipcMain.handle('renderer:delete-environment', async (event, collectionPathname, environmentName) => { + try { + const envDirPath = path.join(collectionPathname, 'environments'); + const envFilePath = path.join(envDirPath, `${environmentName}.bru`); + if (!fs.existsSync(envFilePath)){ + throw new Error(`environment: ${envFilePath} does not exist`); + } + + fs.unlinkSync(envFilePath); + } catch (error) { + return Promise.reject(error); + } + }); + // rename item ipcMain.handle('renderer:rename-item', async (event, oldPath, newPath, newName) => { try { @@ -177,6 +243,71 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection } }); + ipcMain.handle('renderer:import-collection', async (event, collection, collectionLocation) => { + try { + let collectionName = collection.name; + let collectionPath = path.join(collectionLocation, collectionName); + + if (fs.existsSync(collectionPath)){ + throw new Error(`collection: ${collectionPath} already exists`); + } + + // Recursive function to parse the collection items and create files/folders + const parseCollectionItems = (items = [], currentPath) => { + items.forEach(item => { + if (item.type === 'http-request') { + const content = jsonToBru(item); + const filePath = path.join(currentPath, `${item.name}.bru`); + fs.writeFileSync(filePath, content); + } + if (item.type === 'folder') { + const folderPath = path.join(currentPath, item.name); + fs.mkdirSync(folderPath); + + if(item.items && item.items.length) { + parseCollectionItems(item.items, folderPath); + } + } + }); + }; + + const parseEnvironments = (environments = [], collectionPath) => { + const envDirPath = path.join(collectionPath, 'environments'); + if(!fs.existsSync(envDirPath)){ + fs.mkdirSync(envDirPath); + } + + environments.forEach(env => { + const content = envJsonToBru(env); + const filePath = path.join(envDirPath, `${env.name}.bru`); + fs.writeFileSync(filePath, content); + }); + }; + + await createDirectory(collectionPath); + + const uid = generateUidBasedOnHash(collectionPath); + const content = await stringifyJson({ + version: '1', + name: collection.name, + type: 'collection' + }); + await writeFile(path.join(collectionPath, 'bruno.json'), content); + + mainWindow.webContents.send('main:collection-opened', collectionPath, uid, collectionName); + ipcMain.emit('main:collection-opened', mainWindow, collectionPath, uid); + + lastOpenedCollections.add(collectionPath); + + // create folder and files based on collection + await parseCollectionItems(collection.items, collectionPath); + await parseEnvironments(collection.environments, collectionPath); + + } catch (error) { + return Promise.reject(error); + } + }); + ipcMain.handle('renderer:ready', async (event) => { // reload last opened collections const lastOpened = lastOpenedCollections.getAll(); diff --git a/packages/bruno-lang/src/body-tag.js b/packages/bruno-lang/src/body-tag.js index 0dfbc338..ccc1caec 100644 --- a/packages/bruno-lang/src/body-tag.js +++ b/packages/bruno-lang/src/body-tag.js @@ -63,15 +63,16 @@ const bodyXmlTag = between(bodyXmlBegin)(bodyEnd)(everyCharUntil(bodyEnd)).map(( // generic key value parser const newline = regex(/^\r?\n/); const newLineOrEndOfInput = choice([newline, endOfInput]); -const word = regex(/^[^\s\t\n]+/g); +const wordWithoutWhitespace = regex(/^[^\s\t\n]+/g); +const wordWithWhitespace = regex(/^[^\n]+/g); const line = sequenceOf([ optionalWhitespace, digit, whitespace, - word, + wordWithoutWhitespace, whitespace, - word, + wordWithWhitespace, newLineOrEndOfInput ]).map(([_, enabled, __, key, ___, value]) => { return { diff --git a/packages/bruno-lang/src/env-vars-tag.js b/packages/bruno-lang/src/env-vars-tag.js new file mode 100644 index 00000000..3b81cff7 --- /dev/null +++ b/packages/bruno-lang/src/env-vars-tag.js @@ -0,0 +1,47 @@ +const { + sequenceOf, + whitespace, + optionalWhitespace, + choice, + endOfInput, + between, + digit, + many, + regex, + sepBy +} = require("arcsecond"); + +const newline = regex(/^\r?\n/); +const newLineOrEndOfInput = choice([newline, endOfInput]); + +const begin = regex(/^vars\s*\r?\n/); +const end = regex(/^[\r?\n]*\/vars\s*[\r?\n]*/); +const wordWithoutWhitespace = regex(/^[^\s\t\n]+/g); +const wordWithWhitespace = regex(/^[^\n]+/g); + +const line = sequenceOf([ + optionalWhitespace, + digit, + whitespace, + wordWithoutWhitespace, + whitespace, + wordWithWhitespace, + newLineOrEndOfInput +]).map(([_, enabled, __, key, ___, value]) => { + return { + "enabled": Number(enabled) ? true : false, + "name": key, + "value": value, + "type": "text" + }; +}); + +const lines = many(line); +const envVarsLines = sepBy(newline)(lines); +const envVarsTag = between(begin)(end)(envVarsLines).map(([variables]) => { + return { + variables + }; +}); + +module.exports = envVarsTag; diff --git a/packages/bruno-lang/src/headers-tag.js b/packages/bruno-lang/src/headers-tag.js index e9d1f394..825daf69 100644 --- a/packages/bruno-lang/src/headers-tag.js +++ b/packages/bruno-lang/src/headers-tag.js @@ -16,15 +16,16 @@ const newLineOrEndOfInput = choice([newline, endOfInput]); const begin = regex(/^headers\s*\r?\n/); const end = regex(/^[\r?\n]*\/headers\s*[\r?\n]*/); -const word = regex(/^[^\s\t\n]+/g); +const wordWithoutWhitespace = regex(/^[^\s\t\n]+/g); +const wordWithWhitespace = regex(/^[^\n]+/g); const line = sequenceOf([ optionalWhitespace, digit, whitespace, - word, + wordWithoutWhitespace, whitespace, - word, + wordWithWhitespace, newLineOrEndOfInput ]).map(([_, enabled, __, key, ___, value]) => { return { diff --git a/packages/bruno-lang/src/index.js b/packages/bruno-lang/src/index.js index 715be190..2258262e 100644 --- a/packages/bruno-lang/src/index.js +++ b/packages/bruno-lang/src/index.js @@ -51,7 +51,7 @@ const bruToJson = (fileContents) => { headers: parsed.headers || [], body: parsed.body || {mode: 'none'} } - } + }; const body = get(json, 'request.body'); @@ -161,7 +161,47 @@ ${body.multipartForm.map(item => ` ${item.enabled ? 1 : 0} ${item.name} ${item. return bru; }; +// env +const envVarsTag = require('./env-vars-tag'); + +const bruToEnvJson = (fileContents) => { + const parser = many(choice([ + envVarsTag, + anyChar + ])); + + const parsed = parser + .run(fileContents) + .result + .reduce((acc, item) => _.merge(acc, item), {}); + + const json = { + variables: parsed.variables || [] + }; + + return json; +}; + +const envJsonToBru = (json) => { + const { + variables + } = json; + + let bru = ''; + + if(variables && variables.length) { + bru += `vars +${variables.map(item => ` ${item.enabled ? 1 : 0} ${item.name} ${item.value}`).join('\n')} +/vars +`; + } + + return bru; +}; + module.exports = { bruToJson, - jsonToBru + jsonToBru, + bruToEnvJson, + envJsonToBru }; \ No newline at end of file diff --git a/packages/bruno-lang/src/params-tag.js b/packages/bruno-lang/src/params-tag.js index ac025baf..f5696262 100644 --- a/packages/bruno-lang/src/params-tag.js +++ b/packages/bruno-lang/src/params-tag.js @@ -17,15 +17,16 @@ const newLineOrEndOfInput = choice([newline, endOfInput]); const begin = regex(/^params\s*\r?\n/); const end = regex(/^[\r?\n]*\/params\s*[\r?\n]*/); -const word = regex(/^[^\s\t\n]+/g); +const wordWithoutWhitespace = regex(/^[^\s\t\n]+/g); +const wordWithWhitespace = regex(/^[^\n]+/g); const line = sequenceOf([ optionalWhitespace, digit, whitespace, - word, + wordWithoutWhitespace, whitespace, - word, + wordWithWhitespace, newLineOrEndOfInput ]).map(([_, enabled, __, key, ___, value]) => { return { diff --git a/packages/bruno-lang/tests/bru-to-env-json.spec.js b/packages/bruno-lang/tests/bru-to-env-json.spec.js new file mode 100644 index 00000000..67d633b5 --- /dev/null +++ b/packages/bruno-lang/tests/bru-to-env-json.spec.js @@ -0,0 +1,33 @@ +const fs = require('fs'); +const path = require('path'); + +const { + bruToEnvJson +} = require('../src'); + +describe('bruToEnvJson', () => { + it('should parse .bru file contents', () => { + const requestFile = fs.readFileSync(path.join(__dirname, 'fixtures', 'env.bru'), 'utf8'); + const result = bruToEnvJson(requestFile); + + expect(result).toEqual({ + "variables": [{ + "enabled": true, + "name": "host", + "value": "https://www.google.com", + "type": "text" + }, { + "enabled": true, + "name": "jwt", + "value": "secret", + "type": "text" + }, { + "enabled": false, + "name": "Content-type", + "value": "application/json", + "type": "text" + }] + }); + }); +}); + diff --git a/packages/bruno-lang/tests/env-json-to-bru.spec.js b/packages/bruno-lang/tests/env-json-to-bru.spec.js new file mode 100644 index 00000000..ea96beb2 --- /dev/null +++ b/packages/bruno-lang/tests/env-json-to-bru.spec.js @@ -0,0 +1,35 @@ +const fs = require('fs'); +const path = require('path'); + +const { + envJsonToBru +} = require('../src'); + +describe('envJsonToBru', () => { + it('should convert json file into .bru file', () => { + const env = { + "variables": [{ + "enabled": true, + "name": "host", + "value": "https://www.google.com", + "type": "text" + }, { + "enabled": true, + "name": "jwt", + "value": "secret", + "type": "text" + }, { + "enabled": false, + "name": "Content-type", + "value": "application/json", + "type": "text" + }] + }; + + const expectedBruFile = fs.readFileSync(path.join(__dirname, 'fixtures', 'env.bru'), 'utf8'); + const actualBruFile = envJsonToBru(env); + + expect(expectedBruFile).toEqual(actualBruFile); + }); +}); + diff --git a/packages/bruno-lang/tests/fixtures/env.bru b/packages/bruno-lang/tests/fixtures/env.bru new file mode 100644 index 00000000..bea55e9b --- /dev/null +++ b/packages/bruno-lang/tests/fixtures/env.bru @@ -0,0 +1,5 @@ +vars + 1 host https://www.google.com + 1 jwt secret + 0 Content-type application/json +/vars diff --git a/packages/bruno-schema/src/collections/index.js b/packages/bruno-schema/src/collections/index.js index e4481e6b..22494d52 100644 --- a/packages/bruno-schema/src/collections/index.js +++ b/packages/bruno-schema/src/collections/index.js @@ -12,7 +12,7 @@ const environmentVariablesSchema = Yup.object({ const environmentSchema = Yup.object({ uid: uidSchema, - name: Yup.string().min(1).max(50, 'name must be 50 characters or less').required('name is required'), + name: Yup.string().min(1).max(50, 'name must be 100 characters or less').required('name is required'), variables: Yup.array().of(environmentVariablesSchema).required('variables are required') }).noUnknown(true).strict(); @@ -91,6 +91,7 @@ const collectionSchema = Yup.object({ module.exports = { requestSchema, itemSchema, + environmentSchema, environmentsSchema, collectionSchema }; \ No newline at end of file diff --git a/packages/bruno-schema/src/index.js b/packages/bruno-schema/src/index.js index bfede823..ad25aaad 100644 --- a/packages/bruno-schema/src/index.js +++ b/packages/bruno-schema/src/index.js @@ -1,8 +1,9 @@ const { workspaceSchema } = require("./workspaces"); -const { collectionSchema, itemSchema, environmentsSchema } = require("./collections"); +const { collectionSchema, itemSchema, environmentSchema, environmentsSchema } = require("./collections"); module.exports = { itemSchema, + environmentSchema, environmentsSchema, collectionSchema, workspaceSchema