mirror of
https://github.com/usebruno/bruno.git
synced 2025-02-18 02:30:58 +01:00
feat: Add Folder to Collection
This commit is contained in:
parent
84e675dec4
commit
33ff9e603b
@ -1,15 +1,22 @@
|
|||||||
import React, { useRef, forwardRef } from 'react';
|
import React, { useRef, forwardRef } from 'react';
|
||||||
import range from 'lodash/range';
|
import range from 'lodash/range';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
|
import actions from 'providers/Store/actions'
|
||||||
|
import { useStore } from 'providers/Store';
|
||||||
import { IconChevronRight, IconDots } from '@tabler/icons';
|
import { IconChevronRight, IconDots } from '@tabler/icons';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import Dropdown from '../../../../Dropdown';
|
import Dropdown from 'components/Dropdown';
|
||||||
|
|
||||||
import StyledWrapper from './StyledWrapper';
|
import StyledWrapper from './StyledWrapper';
|
||||||
|
|
||||||
const CollectionItem = ({item, collectionId, actions, dispatch, activeRequestTabId}) => {
|
const CollectionItem = ({item, collectionId}) => {
|
||||||
const dropdownTippyRef = useRef();
|
const [store, storeDispatch] = useStore();
|
||||||
|
|
||||||
|
const {
|
||||||
|
activeRequestTabId
|
||||||
|
} = store;
|
||||||
|
|
||||||
|
const dropdownTippyRef = useRef();
|
||||||
const MenuIcon = forwardRef((props, ref) => {
|
const MenuIcon = forwardRef((props, ref) => {
|
||||||
return (
|
return (
|
||||||
<div ref={ref}>
|
<div ref={ref}>
|
||||||
@ -32,7 +39,7 @@ const CollectionItem = ({item, collectionId, actions, dispatch, activeRequestTab
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch({
|
storeDispatch({
|
||||||
type: actions.SIDEBAR_COLLECTION_ITEM_CLICK,
|
type: actions.SIDEBAR_COLLECTION_ITEM_CLICK,
|
||||||
itemId: item.id,
|
itemId: item.id,
|
||||||
collectionId: collectionId
|
collectionId: collectionId
|
||||||
@ -40,7 +47,7 @@ const CollectionItem = ({item, collectionId, actions, dispatch, activeRequestTab
|
|||||||
};
|
};
|
||||||
|
|
||||||
const addRequest = () => {
|
const addRequest = () => {
|
||||||
dispatch({
|
storeDispatch({
|
||||||
type: actions.ADD_REQUEST,
|
type: actions.ADD_REQUEST,
|
||||||
itemId: item.id,
|
itemId: item.id,
|
||||||
collectionId: collectionId
|
collectionId: collectionId
|
||||||
@ -48,7 +55,6 @@ const CollectionItem = ({item, collectionId, actions, dispatch, activeRequestTab
|
|||||||
};
|
};
|
||||||
|
|
||||||
let indents = range(item.depth);
|
let indents = range(item.depth);
|
||||||
|
|
||||||
const onDropdownCreate = (ref) => dropdownTippyRef.current = ref;
|
const onDropdownCreate = (ref) => dropdownTippyRef.current = ref;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -121,9 +127,6 @@ const CollectionItem = ({item, collectionId, actions, dispatch, activeRequestTab
|
|||||||
key={i.id}
|
key={i.id}
|
||||||
item={i}
|
item={i}
|
||||||
collectionId={collectionId}
|
collectionId={collectionId}
|
||||||
actions={actions}
|
|
||||||
dispatch={dispatch}
|
|
||||||
activeRequestTabId={activeRequestTabId}
|
|
||||||
/>
|
/>
|
||||||
}) : null}
|
}) : null}
|
||||||
</div>
|
</div>
|
||||||
|
@ -29,6 +29,12 @@ const Wrapper = styled.div`
|
|||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.tippy-box {
|
||||||
|
position: relative;
|
||||||
|
top: -0.625rem;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -1,14 +1,20 @@
|
|||||||
import React, { forwardRef, useRef } from 'react';
|
import React, { forwardRef, useRef } from 'react';
|
||||||
import { IconChevronRight, IconDots } from '@tabler/icons';
|
|
||||||
import CollectionItem from './CollectionItem';
|
|
||||||
import Dropdown from '../../../Dropdown';
|
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
import { IconChevronRight, IconDots } from '@tabler/icons';
|
||||||
|
import Dropdown from 'components/Dropdown';
|
||||||
|
import actions from 'providers/Store/actions'
|
||||||
|
import { useStore } from 'providers/Store';
|
||||||
|
import CollectionItem from './CollectionItem';
|
||||||
|
|
||||||
import StyledWrapper from './StyledWrapper';
|
import StyledWrapper from './StyledWrapper';
|
||||||
|
|
||||||
const Collection = ({collection, actions, dispatch, activeRequestTabId}) => {
|
const Collection = ({collection}) => {
|
||||||
const envDropdownTippyRef = useRef();
|
const [store, storeDispatch] = useStore();
|
||||||
|
|
||||||
|
const {
|
||||||
|
activeRequestTabId
|
||||||
|
} = store;
|
||||||
|
|
||||||
const menuDropdownTippyRef = useRef();
|
const menuDropdownTippyRef = useRef();
|
||||||
const onMenuDropdownCreate = (ref) => menuDropdownTippyRef.current = ref;
|
const onMenuDropdownCreate = (ref) => menuDropdownTippyRef.current = ref;
|
||||||
@ -25,22 +31,31 @@ const Collection = ({collection, actions, dispatch, activeRequestTabId}) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleClick = (event) => {
|
const handleClick = (event) => {
|
||||||
let envTippyEl = get(envDropdownTippyRef, 'current.reference');
|
let envTippyEl = get(menuDropdownTippyRef, 'current.reference');
|
||||||
if(envTippyEl && envTippyEl.contains && envTippyEl.contains(event.target)) {
|
if(envTippyEl && envTippyEl.contains && envTippyEl.contains(event.target)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch({
|
storeDispatch({
|
||||||
type: actions.SIDEBAR_COLLECTION_CLICK,
|
type: actions.SIDEBAR_COLLECTION_CLICK,
|
||||||
id: collection.id
|
collectionUid: collection.uid
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const addFolder = () => {
|
||||||
|
storeDispatch({
|
||||||
|
type: actions.SIDEBAR_COLLECTION_ADD_FOLDER,
|
||||||
|
collectionUid: collection.uid
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const collectionItems = get(collection, 'current.items');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledWrapper className="flex flex-col">
|
<StyledWrapper className="flex flex-col">
|
||||||
<div className="flex py-1 collection-name items-center" onClick={handleClick}>
|
<div className="flex py-1 collection-name items-center" onClick={handleClick}>
|
||||||
<IconChevronRight size={16} strokeWidth={2} className={iconClassName} style={{width:16, color: 'rgb(160 160 160)'}}/>
|
<IconChevronRight size={16} strokeWidth={2} className={iconClassName} style={{width:16, color: 'rgb(160 160 160)'}}/>
|
||||||
<span className="ml-1">{collection.name}</span>
|
<span className="ml-1">{collection.current.name}</span>
|
||||||
<div className="collection-actions">
|
<div className="collection-actions">
|
||||||
<Dropdown onCreate={onMenuDropdownCreate} icon={<MenuIcon />} placement='bottom-start'>
|
<Dropdown onCreate={onMenuDropdownCreate} icon={<MenuIcon />} placement='bottom-start'>
|
||||||
<div>
|
<div>
|
||||||
@ -53,6 +68,7 @@ const Collection = ({collection, actions, dispatch, activeRequestTabId}) => {
|
|||||||
<div>
|
<div>
|
||||||
<div className="dropdown-item" onClick={(e) => {
|
<div className="dropdown-item" onClick={(e) => {
|
||||||
menuDropdownTippyRef.current.hide();
|
menuDropdownTippyRef.current.hide();
|
||||||
|
addFolder();
|
||||||
}}>
|
}}>
|
||||||
Add Folder
|
Add Folder
|
||||||
</div>
|
</div>
|
||||||
@ -64,13 +80,13 @@ const Collection = ({collection, actions, dispatch, activeRequestTabId}) => {
|
|||||||
<div>
|
<div>
|
||||||
{collection.collapsed ? (
|
{collection.collapsed ? (
|
||||||
<div>
|
<div>
|
||||||
{collection.items && collection.items.length ? collection.items.map((i) => {
|
{collectionItems && collectionItems.length ? collectionItems.map((i) => {
|
||||||
return <CollectionItem
|
return <CollectionItem
|
||||||
key={i.name}
|
key={i.uid}
|
||||||
item={i}
|
item={i}
|
||||||
collectionId={collection.id}
|
collectionId={collection.id}
|
||||||
actions={actions}
|
actions={actions}
|
||||||
dispatch={dispatch}
|
dispatch={storeDispatch}
|
||||||
activeRequestTabId={activeRequestTabId}
|
activeRequestTabId={activeRequestTabId}
|
||||||
/>
|
/>
|
||||||
}) : null}
|
}) : null}
|
||||||
|
@ -7,7 +7,7 @@ const Collections = ({collections, actions, dispatch, activeRequestTabId}) => {
|
|||||||
{collections && collections.length ? collections.map((c) => {
|
{collections && collections.length ? collections.map((c) => {
|
||||||
return <Collection
|
return <Collection
|
||||||
collection={c}
|
collection={c}
|
||||||
key={c.id}
|
key={c.uid}
|
||||||
actions={actions}
|
actions={actions}
|
||||||
dispatch={dispatch}
|
dispatch={dispatch}
|
||||||
activeRequestTabId={activeRequestTabId}
|
activeRequestTabId={activeRequestTabId}
|
||||||
|
@ -47,11 +47,13 @@ const TitleBar = ({dispatch, actions}) => {
|
|||||||
uid: collectionUid,
|
uid: collectionUid,
|
||||||
base: null,
|
base: null,
|
||||||
current: {
|
current: {
|
||||||
id: collectionUid,
|
uid: collectionUid,
|
||||||
name: values.collectionName,
|
name: values.collectionName,
|
||||||
items: []
|
items: []
|
||||||
},
|
},
|
||||||
requestSync: true
|
userId: null,
|
||||||
|
hasChangedSinceLastSync: false,
|
||||||
|
disableSync: true
|
||||||
};
|
};
|
||||||
|
|
||||||
saveCollectionToIdb(store.idbConnection, newCollection)
|
saveCollectionToIdb(store.idbConnection, newCollection)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
const SIDEBAR_COLLECTION_CLICK = "SIDEBAR_COLLECTION_CLICK";
|
const SIDEBAR_COLLECTION_CLICK = "SIDEBAR_COLLECTION_CLICK";
|
||||||
const SIDEBAR_COLLECTION_ITEM_CLICK = "SIDEBAR_COLLECTION_ITEM_CLICK";
|
const SIDEBAR_COLLECTION_ITEM_CLICK = "SIDEBAR_COLLECTION_ITEM_CLICK";
|
||||||
|
const SIDEBAR_COLLECTION_ADD_FOLDER = "SIDEBAR_COLLECTION_ADD_FOLDER";
|
||||||
|
const LOAD_COLLECTIONS_FROM_IDB = "LOAD_COLLECTIONS_FROM_IDB";
|
||||||
const COLLECTION_CREATE = "COLLECTION_CREATE";
|
const COLLECTION_CREATE = "COLLECTION_CREATE";
|
||||||
const REQUEST_TAB_CLICK = "REQUEST_TAB_CLICK";
|
const REQUEST_TAB_CLICK = "REQUEST_TAB_CLICK";
|
||||||
const REQUEST_TAB_CLOSE = "REQUEST_TAB_CLOSE";
|
const REQUEST_TAB_CLOSE = "REQUEST_TAB_CLOSE";
|
||||||
@ -16,6 +18,8 @@ const IDB_CONNECTION_READY = "IDB_CONNECTION_READY";
|
|||||||
export default {
|
export default {
|
||||||
SIDEBAR_COLLECTION_CLICK,
|
SIDEBAR_COLLECTION_CLICK,
|
||||||
SIDEBAR_COLLECTION_ITEM_CLICK,
|
SIDEBAR_COLLECTION_ITEM_CLICK,
|
||||||
|
SIDEBAR_COLLECTION_ADD_FOLDER,
|
||||||
|
LOAD_COLLECTIONS_FROM_IDB,
|
||||||
COLLECTION_CREATE,
|
COLLECTION_CREATE,
|
||||||
REQUEST_TAB_CLICK,
|
REQUEST_TAB_CLICK,
|
||||||
REQUEST_TAB_CLOSE,
|
REQUEST_TAB_CLOSE,
|
||||||
|
@ -13,7 +13,7 @@ export const saveCollectionToIdb = (connection, collection) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getCollectionsFromIdb = (connection, domain) => {
|
export const getCollectionsFromIdb = (connection) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection
|
connection
|
||||||
.then((db) => {
|
.then((db) => {
|
||||||
|
@ -3,6 +3,8 @@ import reducer from './reducer';
|
|||||||
import useIdb from './useIdb';
|
import useIdb from './useIdb';
|
||||||
import { sendRequest } from '../../network';
|
import { sendRequest } from '../../network';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
|
import actions from './actions';
|
||||||
|
import {getCollectionsFromIdb} from './idb';
|
||||||
|
|
||||||
export const StoreContext = createContext();
|
export const StoreContext = createContext();
|
||||||
|
|
||||||
@ -112,7 +114,7 @@ const collection2 = {
|
|||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
idbConnection: null,
|
idbConnection: null,
|
||||||
collections: [collection, collection2],
|
collections: [],
|
||||||
activeRequestTabId: null,
|
activeRequestTabId: null,
|
||||||
requestQueuedToSend: null,
|
requestQueuedToSend: null,
|
||||||
requestTabs: []
|
requestTabs: []
|
||||||
@ -120,6 +122,10 @@ const initialState = {
|
|||||||
|
|
||||||
export const StoreProvider = props => {
|
export const StoreProvider = props => {
|
||||||
const [state, dispatch] = useReducer(reducer, initialState);
|
const [state, dispatch] = useReducer(reducer, initialState);
|
||||||
|
|
||||||
|
const {
|
||||||
|
idbConnection
|
||||||
|
} = state;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(state.requestQueuedToSend) {
|
if(state.requestQueuedToSend) {
|
||||||
@ -132,6 +138,19 @@ export const StoreProvider = props => {
|
|||||||
}
|
}
|
||||||
}, [state.requestQueuedToSend]);
|
}, [state.requestQueuedToSend]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(idbConnection) {
|
||||||
|
getCollectionsFromIdb(idbConnection)
|
||||||
|
.then((collections) => {
|
||||||
|
dispatch({
|
||||||
|
type: actions.LOAD_COLLECTIONS_FROM_IDB,
|
||||||
|
collections: collections
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) => console.log(err));
|
||||||
|
}
|
||||||
|
}, [idbConnection]);
|
||||||
|
|
||||||
useIdb(dispatch);
|
useIdb(dispatch);
|
||||||
|
|
||||||
return <StoreContext.Provider value={[state, dispatch]} {...props} />;
|
return <StoreContext.Provider value={[state, dispatch]} {...props} />;
|
||||||
|
@ -21,6 +21,13 @@ const reducer = (state, action) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case actions.LOAD_COLLECTIONS_FROM_IDB: {
|
||||||
|
return produce(state, (draft) => {
|
||||||
|
console.log(action.collections);
|
||||||
|
draft.collections = action.collections;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
case actions.SIDEBAR_COLLECTION_CLICK: {
|
case actions.SIDEBAR_COLLECTION_CLICK: {
|
||||||
return produce(state, (draft) => {
|
return produce(state, (draft) => {
|
||||||
const collection = find(draft.collections, (c) => c.id === action.id);
|
const collection = find(draft.collections, (c) => c.id === action.id);
|
||||||
@ -61,6 +68,22 @@ const reducer = (state, action) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case actions.SIDEBAR_COLLECTION_ADD_FOLDER: {
|
||||||
|
return produce(state, (draft) => {
|
||||||
|
const collection = find(draft.collections, (c) => c.uid === action.collectionUid);
|
||||||
|
console.log(collection.current.items);
|
||||||
|
|
||||||
|
if(collection) {
|
||||||
|
collection.current.items.push({
|
||||||
|
"uid": nanoid(),
|
||||||
|
"name": "New Folder",
|
||||||
|
"depth": 1,
|
||||||
|
"items": []
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
case actions.COLLECTION_CREATE: {
|
case actions.COLLECTION_CREATE: {
|
||||||
return produce(state, (draft) => {
|
return produce(state, (draft) => {
|
||||||
// todo: collection names must be unique across a user account
|
// todo: collection names must be unique across a user account
|
||||||
|
Loading…
Reference in New Issue
Block a user