feat: wireup local collections open and create buttons

This commit is contained in:
Anoop M D 2022-10-18 01:27:53 +05:30
parent 9fae7f72d4
commit 8a96a0ce71
8 changed files with 173 additions and 36 deletions

View File

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

View File

@ -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,10 +26,27 @@ 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) {
inputRef.current.focus();
@ -36,7 +61,7 @@ const CreateCollection = ({handleConfirm, handleCancel}) => {
title='Create Collection'
confirmText='Create'
handleConfirm={onSubmit}
handleCancel={handleCancel}
handleCancel={onClose}
>
<form className="bruno-form" onSubmit={formik.handleSubmit}>
<div>
@ -54,6 +79,31 @@ const CreateCollection = ({handleConfirm, handleCancel}) => {
{formik.touched.collectionName && formik.errors.collectionName ? (
<div className="text-red-500">{formik.errors.collectionName}</div>
) : null}
{isLocal && isPlatformElectron ? (
<>
<label htmlFor="collectionLocation" className="block font-semibold mt-3">Location</label>
<input
id="collection-location"
type="text"
name="collectionLocation"
readOnly={true}
className="block textbox mt-2 w-full"
autoComplete="off" autoCorrect="off" autoCapitalize="off" spellCheck="false"
value={formik.values.collectionLocation || ''}
onClick={browse}
/>
</>
) : null}
{isLocal && isPlatformElectron && formik.touched.collectionLocation && formik.errors.collectionLocation ? (
<div className="text-red-500">{formik.errors.collectionLocation}</div>
) : null}
{isLocal && isPlatformElectron ? (
<div className="mt-1">
<span className="text-link cursor-pointer hover:underline" onClick={browse}>Browse</span>
</div>
) : null }
</div>
</form>
</Modal>

View File

@ -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 (
<StyledWrapper>
{createCollectionModalOpen ? (
<CreateCollection
isLocal={true}
onClose={() => setCreateCollectionModalOpen(false)}
/>
) : null}
<div className="items-center cursor-pointer mt-6 relative">
<Dropdown onCreate={onDropdownCreate} icon={<Icon />} placement='bottom-end'>
<div className="dropdown-item" onClick={() => {}}>
<div className="dropdown-item" onClick={() => setCreateCollectionModalOpen(true)}>
<div className="pr-2 text-gray-600">
<IconPlus size={18} strokeWidth={1.5}/>
</div>
<span>Create Collection</span>
</div>
<div className="dropdown-item" onClick={() => {}}>
<div className="dropdown-item" onClick={handleOpenLocalCollection}>
<div className="pr-2 text-gray-600">
<IconArrowForwardUp size={18} strokeWidth={1.5}/>
</div>

View File

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

View File

@ -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 = () => {
<StyledWrapper className="px-2 py-2">
{createCollectionModalOpen ? (
<CreateCollection
handleCancel={() => setCreateCollectionModalOpen(false)}
handleConfirm={handleCreateCollection}
isLocal={createCollectionModalOpen === 'local' ? true : false}
onClose={() => setCreateCollectionModalOpen(false)}
/>
) : null}
@ -106,6 +105,37 @@ const TitleBar = () => {
}}>
Add Collection to Workspace
</div>
{isPlatformElectron ? (
<>
<div className="font-medium label-item font-medium local-collection-label">
<div className='flex items-center'>
<span className='mr-2'>
<IconFolders size={18} strokeWidth={1.5}/>
</span>
<span>
Local Collections
</span>
</div>
</div>
<div className="dropdown-item" onClick={(e) => {
setCreateCollectionModalOpen('local');
menuDropdownTippyRef.current.hide();
}}>
Create Local Collection
</div>
<div className="dropdown-item" onClick={(e) => {
handleOpenLocalCollection();
menuDropdownTippyRef.current.hide();
}}>
Open Local Collection
</div>
</>
) : (
<div className="flex items-center select-none text-gray-400 text-xs local-collections-unavailable">
Note: Local collections are only available on the desktop app.
</div>
)}
</Dropdown>
</div>
</div>

View File

@ -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 (
<StyledWrapper className="pb-4 px-6 mt-6">
{createCollectionModalOpen ? (
<CreateCollection
handleCancel={() => setCreateCollectionModalOpen(false)}
handleConfirm={handleCreateCollection}
isLocal={createCollectionModalOpen === 'local' ? true : false}
onClose={() => setCreateCollectionModalOpen(false)}
/>
) : null}
@ -112,10 +108,10 @@ const Welcome = () => {
{isPlatformElectron ? (
<div className="mt-4 flex items-center collection-options select-none">
<div className="flex items-center">
<IconPlus size={18} strokeWidth={2}/><span className="label ml-2" onClick={() => setCreateCollectionModalOpen(true)}>Create Collection</span>
<IconPlus size={18} strokeWidth={2}/><span className="label ml-2" onClick={() => setCreateCollectionModalOpen('local')}>Create Collection</span>
</div>
<div className="flex items-center ml-6">
<IconFolders size={18} strokeWidth={2}/><span className="label ml-2">Open Collection</span>
<IconFolders size={18} strokeWidth={2}/><span className="label ml-2" onClick={handleOpenLocalCollection}>Open Collection</span>
</div>
</div>
) : (

View File

@ -802,3 +802,36 @@ export const removeLocalCollection = (collectionUid) => (dispatch, getState) =>
.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);
});
};

View File

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