diff --git a/packages/bruno-app/src/components/Sidebar/Collections/index.js b/packages/bruno-app/src/components/Sidebar/Collections/index.js
index 8227ac9f..dfca61cc 100644
--- a/packages/bruno-app/src/components/Sidebar/Collections/index.js
+++ b/packages/bruno-app/src/components/Sidebar/Collections/index.js
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React from 'react';
import { useSelector } from 'react-redux';
import find from 'lodash/find';
import filter from 'lodash/filter';
diff --git a/packages/bruno-app/src/components/Sidebar/CreateCollection/index.js b/packages/bruno-app/src/components/Sidebar/CreateCollection/index.js
index f81d9984..e01fe173 100644
--- a/packages/bruno-app/src/components/Sidebar/CreateCollection/index.js
+++ b/packages/bruno-app/src/components/Sidebar/CreateCollection/index.js
@@ -1,10 +1,18 @@
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 toast from 'react-hot-toast';
import Modal from 'components/Modal';
-const CreateCollection = ({handleConfirm, handleCancel}) => {
+const CreateCollection = ({onClose, isLocal}) => {
const inputRef = useRef();
+ const dispatch = useDispatch();
+ const isPlatformElectron = isElectron();
+
const formik = useFormik({
enableReinitialize: true,
initialValues: {
@@ -18,9 +26,26 @@ const CreateCollection = ({handleConfirm, handleCancel}) => {
.required('name is required')
}),
onSubmit: (values) => {
- handleConfirm(values);
+ const action = isLocal && isPlatformElectron ? createLocalCollection : createCollection;
+ dispatch(action(values.collectionName, values.collectionLocation))
+ .then(() => {
+ toast.success("Collection created");
+ onClose();
+ })
+ .catch(() => toast.error("An error occured while creating the collection"));
}
});
+
+ const browse = () => {
+ dispatch(browserLocalDirectory())
+ .then((dirPath) => {
+ formik.setFieldValue('collectionLocation', dirPath);
+ })
+ .catch((error) => {
+ formik.setFieldValue('collectionLocation', '');
+ console.error(error);
+ });
+ };
useEffect(() => {
if(inputRef && inputRef.current) {
@@ -36,7 +61,7 @@ const CreateCollection = ({handleConfirm, handleCancel}) => {
title='Create Collection'
confirmText='Create'
handleConfirm={onSubmit}
- handleCancel={handleCancel}
+ handleCancel={onClose}
>
diff --git a/packages/bruno-app/src/components/Sidebar/LocalCollections/index.js b/packages/bruno-app/src/components/Sidebar/LocalCollections/index.js
index a010b254..d6ae5e87 100644
--- a/packages/bruno-app/src/components/Sidebar/LocalCollections/index.js
+++ b/packages/bruno-app/src/components/Sidebar/LocalCollections/index.js
@@ -1,15 +1,19 @@
-import React, { useRef, forwardRef } from 'react';
+import React, { useState, useRef, forwardRef } from 'react';
import filter from 'lodash/filter';
-import { useSelector } from 'react-redux';
+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));
@@ -35,17 +39,30 @@ const LocalCollections = ({searchText}) => {
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
-
{}}>
+
diff --git a/packages/bruno-app/src/components/Sidebar/TitleBar/StyledWrapper.js b/packages/bruno-app/src/components/Sidebar/TitleBar/StyledWrapper.js
index efdbe283..dfdcab3d 100644
--- a/packages/bruno-app/src/components/Sidebar/TitleBar/StyledWrapper.js
+++ b/packages/bruno-app/src/components/Sidebar/TitleBar/StyledWrapper.js
@@ -1,6 +1,15 @@
import styled from 'styled-components';
const StyledWrapper = styled.div`
+ .local-collection-label {
+ background-color: var(--color-sidebar-background);
+ }
+
+ .local-collections-unavailable {
+ padding: 0.35rem 0.6rem;
+ border-top: solid 1px #ddd;
+ font-size: 11px;
+ }
.collection-dropdown {
color: rgb(110 110 110);
diff --git a/packages/bruno-app/src/components/Sidebar/TitleBar/index.js b/packages/bruno-app/src/components/Sidebar/TitleBar/index.js
index e82ee3e5..737e46b0 100644
--- a/packages/bruno-app/src/components/Sidebar/TitleBar/index.js
+++ b/packages/bruno-app/src/components/Sidebar/TitleBar/index.js
@@ -2,21 +2,24 @@ import React, { useState, forwardRef, useRef } from 'react';
import toast from 'react-hot-toast';
import Dropdown from 'components/Dropdown';
import Bruno from 'components/Bruno';
+import { IconFolders } from '@tabler/icons';
import { useSelector, useDispatch } from 'react-redux';
import { collectionImported } from 'providers/ReduxStore/slices/collections';
-import { createCollection } from 'providers/ReduxStore/slices/collections/actions';
+import { openLocalCollection } from 'providers/ReduxStore/slices/collections/actions';
import { addCollectionToWorkspace } from 'providers/ReduxStore/slices/workspaces/actions';
import { showHomePage } from 'providers/ReduxStore/slices/app';
import { IconDots } from '@tabler/icons';
import CreateCollection from '../CreateCollection';
import SelectCollection from 'components/Sidebar/Collections/SelectCollection';
import importCollection from 'utils/collections/import';
+import { isElectron } from 'utils/common/platform';
import StyledWrapper from './StyledWrapper';
const TitleBar = () => {
const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false);
const [addCollectionToWSModalOpen, setAddCollectionToWSModalOpen] = useState(false);
const { activeWorkspaceUid } = useSelector((state) => state.workspaces);
+ const isPlatformElectron = isElectron();
const dispatch = useDispatch();
const menuDropdownTippyRef = useRef();
@@ -31,14 +34,10 @@ const TitleBar = () => {
const handleTitleClick = () => dispatch(showHomePage());
- 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 handleOpenLocalCollection = () => {
+ dispatch(openLocalCollection())
+ .catch((err) => console.log(err) && toast.error("An error occured while opening the local collection"));
+ }
const handleAddCollectionToWorkspace = (collectionUid) => {
setAddCollectionToWSModalOpen(false);
@@ -62,8 +61,8 @@ const TitleBar = () => {
{createCollectionModalOpen ? (
setCreateCollectionModalOpen(false)}
- handleConfirm={handleCreateCollection}
+ isLocal={createCollectionModalOpen === 'local' ? true : false}
+ onClose={() => setCreateCollectionModalOpen(false)}
/>
) : null}
@@ -106,6 +105,37 @@ const TitleBar = () => {
}}>
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/Welcome/index.js b/packages/bruno-app/src/components/Welcome/index.js
index 03543b6c..10fd70d9 100644
--- a/packages/bruno-app/src/components/Welcome/index.js
+++ b/packages/bruno-app/src/components/Welcome/index.js
@@ -12,7 +12,7 @@ import {
} from '@tabler/icons';
import { useSelector, useDispatch } from 'react-redux';
import { collectionImported } from 'providers/ReduxStore/slices/collections';
-import { createCollection } from 'providers/ReduxStore/slices/collections/actions';
+import { openLocalCollection } from 'providers/ReduxStore/slices/collections/actions';
import { addCollectionToWorkspace } from 'providers/ReduxStore/slices/workspaces/actions';
import Bruno from 'components/Bruno';
import CreateCollection from 'components/Sidebar/CreateCollection';
@@ -29,15 +29,6 @@ const Welcome = () => {
const { activeWorkspaceUid } = useSelector((state) => state.workspaces);
const isPlatformElectron = isElectron();
- 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))
@@ -69,12 +60,17 @@ const Welcome = () => {
});
};
+ const handleOpenLocalCollection = () => {
+ dispatch(openLocalCollection())
+ .catch((err) => console.log(err) && toast.error("An error occured while opening the local collection"));
+ }
+
return (
{createCollectionModalOpen ? (
setCreateCollectionModalOpen(false)}
- handleConfirm={handleCreateCollection}
+ isLocal={createCollectionModalOpen === 'local' ? true : false}
+ onClose={() => setCreateCollectionModalOpen(false)}
/>
) : null}
@@ -112,10 +108,10 @@ const Welcome = () => {
{isPlatformElectron ? (
- setCreateCollectionModalOpen(true)}>Create Collection
+ setCreateCollectionModalOpen('local')}>Create Collection
- Open Collection
+ Open Collection
) : (
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 a78853c9..8fd4ce7c 100644
--- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js
+++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js
@@ -801,4 +801,37 @@ export const removeLocalCollection = (collectionUid) => (dispatch, getState) =>
.then(resolve)
.catch(reject);
});
+};
+
+export const browserLocalDirectory = () => (dispatch, getState) => {
+ const { ipcRenderer } = window;
+
+ return new Promise((resolve, reject) => {
+ ipcRenderer
+ .invoke('renderer:browse-directory')
+ .then(resolve)
+ .catch(reject);
+ });
+}
+
+export const createLocalCollection = (collectionName, collectionLocation) => () => {
+ const { ipcRenderer } = window;
+
+ return new Promise((resolve, reject) => {
+ ipcRenderer
+ .invoke('renderer:create-collection', collectionName, collectionLocation)
+ .then(resolve)
+ .catch(reject);
+ });
+};
+
+export const openLocalCollection = () => () => {
+ return new Promise((resolve, reject) => {
+ const { ipcRenderer } = window;
+
+ ipcRenderer
+ .invoke('renderer:open-collection')
+ .then(resolve)
+ .catch(reject);
+ });
};
\ No newline at end of file
diff --git a/packages/bruno-electron/src/ipc/local-collection.js b/packages/bruno-electron/src/ipc/local-collection.js
index 0032df1c..81962308 100644
--- a/packages/bruno-electron/src/ipc/local-collection.js
+++ b/packages/bruno-electron/src/ipc/local-collection.js
@@ -30,22 +30,24 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
try {
const dirPath = path.join(collectionLocation, collectionName);
if (fs.existsSync(dirPath)){
- throw new Error(`collection: ${dir} already exists`);
+ throw new Error(`collection: ${dirPath} already exists`);
}
if(!isValidPathname(dirPath)) {
- throw new Error(`collection: invaid pathname - ${dir}`);
+ throw new Error(`collection: invalid pathname - ${dir}`);
}
await createDirectory(dirPath);
+ const uid = uuid();
const content = await stringifyJson({
version: '1.0',
+ uid: uid,
+ name: collectionName,
type: 'collection'
});
await writeFile(path.join(dirPath, 'bruno.json'), content);
- const uid = uuid();
mainWindow.webContents.send('main:collection-opened', dirPath, uid);
ipcMain.emit('main:collection-opened', mainWindow, dirPath, uid);