refactor: ids -> uids + NewRequest functionality

This commit is contained in:
Anoop M D 2022-03-14 02:43:36 +05:30
parent 686894e0bd
commit 92692c766a
18 changed files with 250 additions and 148 deletions

View File

@ -21,7 +21,7 @@ const EnvironmentSelector = () => {
return ( return (
<StyledWrapper> <StyledWrapper>
<div className="flex items-center cursor-pointer environment-selector pr-3"> <div className="flex items-center cursor-pointer environment-selector pr-3">
<Dropdown onCreate={onDropdownCreate} icon={<Icon />} placement='bottom-start'> <Dropdown onCreate={onDropdownCreate} icon={<Icon />} placement='bottom-end'>
<div className="dropdown-item" onClick={() => { <div className="dropdown-item" onClick={() => {
dropdownTippyRef.current.hide(); dropdownTippyRef.current.hide();
}}> }}>

View File

@ -1,10 +1,12 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import find from 'lodash/find'; import find from 'lodash/find';
import QueryUrl from '../QueryUrl'; import { useStore } from 'providers/Store';
import GraphQLRequestPane from '../GraphQLRequestPane'; import actions from 'providers/Store/actions';
import HttpRequestPane from '../HttpRequestPane'; import QueryUrl from 'components/QueryUrl';
import ResponsePane from '../ResponsePane'; import GraphQLRequestPane from 'components/GraphQLRequestPane';
import Welcome from '../Welcome'; import HttpRequestPane from 'components/HttpRequestPane';
import ResponsePane from 'components/ResponsePane';
import Welcome from 'components/Welcome';
import { import {
flattenItems, flattenItems,
findItem findItem
@ -13,10 +15,17 @@ import useGraphqlSchema from '../../hooks/useGraphqlSchema';
import StyledWrapper from './StyledWrapper'; import StyledWrapper from './StyledWrapper';
const RequestTabPanel = ({dispatch, actions, collections, activeRequestTabId, requestTabs}) => { const RequestTabPanel = () => {
if(typeof window == 'undefined') { if(typeof window == 'undefined') {
return <div></div>; return <div></div>;
} }
const [store, storeDispatch] = useStore();
const {
collections,
requestTabs,
activeRequestTabUid
} = store;
let asideWidth = 270; let asideWidth = 270;
let { let {
@ -54,32 +63,32 @@ const RequestTabPanel = ({dispatch, actions, collections, activeRequestTabId, re
}, [dragging, leftPaneWidth]); }, [dragging, leftPaneWidth]);
const onUrlChange = (value) => { const onUrlChange = (value) => {
dispatch({ storeDispatch({
type: actions.REQUEST_URL_CHANGED, type: actions.REQUEST_URL_CHANGED,
url: value, url: value,
requestTab: focusedTab, requestTab: focusedTab,
collectionId: collection ? collection.id : null collectionUid: collection ? collection.uid : null
}); });
}; };
const onGraphqlQueryChange = (value) => { const onGraphqlQueryChange = (value) => {
dispatch({ storeDispatch({
type: actions.REQUEST_GQL_QUERY_CHANGED, type: actions.REQUEST_GQL_QUERY_CHANGED,
query: value, query: value,
requestTab: focusedTab, requestTab: focusedTab,
collectionId: collection ? collection.id : null collectionUid: collection ? collection.uid : null
}); });
}; };
if(!activeRequestTabId) { if(!activeRequestTabUid) {
return ( return (
<Welcome dispatch={dispatch} actions={actions}/> <Welcome dispatch={storeDispatch} actions={actions}/>
); );
} }
const focusedTab = find(requestTabs, (rt) => rt.id === activeRequestTabId); const focusedTab = find(requestTabs, (rt) => rt.uid === activeRequestTabUid);
if(!focusedTab || !focusedTab.id) { if(!focusedTab || !focusedTab.uid) {
return ( return (
<div className="pb-4 px-4">An error occured!</div> <div className="pb-4 px-4">An error occured!</div>
); );
@ -88,19 +97,19 @@ const RequestTabPanel = ({dispatch, actions, collections, activeRequestTabId, re
let collection; let collection;
let item; let item;
if(focusedTab.collectionId) { if(focusedTab.collectionUid) {
collection = find(collections, (c) => c.id === focusedTab.collectionId); collection = find(collections, (c) => c.uid === focusedTab.collectionUid);
let flattenedItems = flattenItems(collection.items); let flattenedItems = flattenItems(collection.items);
item = findItem(flattenedItems, activeRequestTabId); item = findItem(flattenedItems, activeRequestTabUid);
} else { } else {
item = focusedTab; item = focusedTab;
} }
const runQuery = async () => { const runQuery = async () => {
dispatch({ storeDispatch({
type: actions.SEND_REQUEST, type: actions.SEND_REQUEST,
requestTab: focusedTab, requestTab: focusedTab,
collectionId: collection ? collection.id : null collectionUid: collection ? collection.uid : null
}); });
}; };

View File

@ -14,12 +14,12 @@ const RequestTabs = () => {
const { const {
collections, collections,
requestTabs, requestTabs,
activeRequestTabId activeRequestTabUid
} = store; } = store;
const getTabClassname = (tab, index) => { const getTabClassname = (tab, index) => {
return classnames("request-tab select-none", { return classnames("request-tab select-none", {
'active': tab.id === activeRequestTabId, 'active': tab.uid === activeRequestTabUid,
'last-tab': requestTabs && requestTabs.length && (index === requestTabs.length - 1) 'last-tab': requestTabs && requestTabs.length && (index === requestTabs.length - 1)
}); });
}; };
@ -62,21 +62,29 @@ const RequestTabs = () => {
}); });
}; };
if(!activeRequestTabId) { if(!activeRequestTabUid) {
return null; return null;
} }
const activeRequestTab = find(requestTabs, (t) => t.id === activeRequestTabId); const activeRequestTab = find(requestTabs, (t) => t.uid === activeRequestTabUid);
const activeCollection = find(collections, (c) => c.id === activeRequestTab.collectionId); console.log(requestTabs);
const collectionRequestTabs = filter(requestTabs, (t) => t.collectionId === activeRequestTab.collectionId); if(!activeRequestTab) {
console.log(activeRequestTab); return (
<StyledWrapper>
Something went wrong!
</StyledWrapper>
);
}
const activeCollection = find(collections, (c) => c.uid === activeRequestTab.collectionUid);
const collectionRequestTabs = filter(requestTabs, (t) => t.collectionUid === activeRequestTab.collectionUid);
return ( return (
<StyledWrapper> <StyledWrapper>
{collectionRequestTabs && collectionRequestTabs.length ? ( {collectionRequestTabs && collectionRequestTabs.length ? (
<> <>
<CollectionToolBar collection={activeCollection}/> <CollectionToolBar collection={activeCollection}/>
<div className="mt-1 flex items-center"> <div className="flex items-center">
<ul role="tablist"> <ul role="tablist">
<li className="select-none new-tab mr-1" onClick={createNewTab}> <li className="select-none new-tab mr-1" onClick={createNewTab}>
<div className="flex items-center home-icon-container"> <div className="flex items-center home-icon-container">
@ -84,7 +92,7 @@ const RequestTabs = () => {
</div> </div>
</li> </li>
{collectionRequestTabs && collectionRequestTabs.length ? collectionRequestTabs.map((rt, index) => { {collectionRequestTabs && collectionRequestTabs.length ? collectionRequestTabs.map((rt, index) => {
return <li key={rt.id} className={getTabClassname(rt, index)} role="tab" onClick={() => handleClick(rt)}> return <li key={rt.uid} className={getTabClassname(rt, index)} role="tab" onClick={() => handleClick(rt)}>
<div className="flex items-center justify-between tab-container px-1"> <div className="flex items-center justify-between tab-container px-1">
<div className="flex items-center tab-label pl-2"> <div className="flex items-center tab-label pl-2">
<span className="tab-method" style={{color: getMethodColor(rt.method)}}>{rt.method}</span> <span className="tab-method" style={{color: getMethodColor(rt.method)}}>{rt.method}</span>

View File

@ -46,7 +46,7 @@ const SaveRequestButton = ({folders}) => {
<div className="folder-list"> <div className="folder-list">
{showFolders && showFolders.length ? showFolders.map((folder) => ( {showFolders && showFolders.length ? showFolders.map((folder) => (
<div <div
key={folder.id} key={folder.uid}
className="folder-name" className="folder-name"
onClick={() => handleFolderClick(folder)} onClick={() => handleFolderClick(folder)}
> >

View File

@ -9,11 +9,11 @@ import Dropdown from 'components/Dropdown';
import StyledWrapper from './StyledWrapper'; import StyledWrapper from './StyledWrapper';
const CollectionItem = ({item, collectionId}) => { const CollectionItem = ({item, collectionUid}) => {
const [store, storeDispatch] = useStore(); const [store, storeDispatch] = useStore();
const { const {
activeRequestTabId activeRequestTabUid
} = store; } = store;
const dropdownTippyRef = useRef(); const dropdownTippyRef = useRef();
@ -30,7 +30,7 @@ const CollectionItem = ({item, collectionId}) => {
}); });
const itemRowClassName = classnames('flex collection-item-name items-center', { const itemRowClassName = classnames('flex collection-item-name items-center', {
'item-focused-in-tab': item.id == activeRequestTabId 'item-focused-in-tab': item.uid == activeRequestTabUid
}); });
const handleClick = (event) => { const handleClick = (event) => {
@ -41,16 +41,16 @@ const CollectionItem = ({item, collectionId}) => {
storeDispatch({ storeDispatch({
type: actions.SIDEBAR_COLLECTION_ITEM_CLICK, type: actions.SIDEBAR_COLLECTION_ITEM_CLICK,
itemId: item.id, itemUid: item.uid,
collectionId: collectionId collectionUid: collectionUid
}); });
}; };
const addRequest = () => { const addRequest = () => {
storeDispatch({ storeDispatch({
type: actions.ADD_REQUEST, type: actions.ADD_REQUEST,
itemId: item.id, itemUid: item.uid,
collectionId: collectionId collectionUid: collectionUid
}); });
}; };
@ -124,9 +124,9 @@ const CollectionItem = ({item, collectionId}) => {
<div> <div>
{item.items && item.items.length ? item.items.map((i) => { {item.items && item.items.length ? item.items.map((i) => {
return <CollectionItem return <CollectionItem
key={i.id} key={i.uid}
item={i} item={i}
collectionId={collectionId} collectionUid={collectionUid}
/> />
}) : null} }) : null}
</div> </div>

View File

@ -5,6 +5,7 @@ import { IconChevronRight, IconDots } from '@tabler/icons';
import Dropdown from 'components/Dropdown'; import Dropdown from 'components/Dropdown';
import actions from 'providers/Store/actions' import actions from 'providers/Store/actions'
import { useStore } from 'providers/Store'; import { useStore } from 'providers/Store';
import NewRequest from 'components/Sidebar/NewRequest';
import NewFolder from 'components/Sidebar/NewFolder'; import NewFolder from 'components/Sidebar/NewFolder';
import CollectionItem from './CollectionItem'; import CollectionItem from './CollectionItem';
@ -12,12 +13,9 @@ import StyledWrapper from './StyledWrapper';
const Collection = ({collection}) => { const Collection = ({collection}) => {
const [showNewFolderModal, setShowNewFolderModal] = useState(false); const [showNewFolderModal, setShowNewFolderModal] = useState(false);
const [showNewRequestModal, setShowNewRequestModal] = useState(false);
const [store, storeDispatch] = useStore(); 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;
const MenuIcon = forwardRef((props, ref) => { const MenuIcon = forwardRef((props, ref) => {
@ -48,25 +46,33 @@ const Collection = ({collection}) => {
}); });
}; };
const hideAddFolderModal = () => setShowNewFolderModal(false); const hideNewFolderModal = () => setShowNewFolderModal(false);
const collectionItems = get(collection, 'current.items'); const hideNewRequestModal = () => setShowNewRequestModal(false);
return ( return (
<StyledWrapper className="flex flex-col"> <StyledWrapper className="flex flex-col">
{showNewRequestModal && (
<NewRequest
collectionUid={collection.uid}
handleCancel={hideNewRequestModal}
handleClose={hideNewRequestModal}
/>
)}
{showNewFolderModal && ( {showNewFolderModal && (
<NewFolder <NewFolder
collectionUid={collection.uid} collectionUid={collection.uid}
handleCancel={hideAddFolderModal} handleCancel={hideNewFolderModal}
handleClose={hideAddFolderModal} handleClose={hideNewFolderModal}
/> />
)} )}
<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.current.name}</span> <span className="ml-1">{collection.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 className="dropdown-item" onClick={(e) => { <div className="dropdown-item" onClick={(e) => {
menuDropdownTippyRef.current.hide(); menuDropdownTippyRef.current.hide();
setShowNewRequestModal(true)
}}> }}>
New Request New Request
</div> </div>
@ -83,11 +89,11 @@ const Collection = ({collection}) => {
<div> <div>
{collection.collapsed ? ( {collection.collapsed ? (
<div> <div>
{collectionItems && collectionItems.length ? collectionItems.map((i) => { {collection.items && collection.items.length ? collection.items.map((i) => {
return <CollectionItem return <CollectionItem
key={i.uid} key={i.uid}
item={i} item={i}
collectionId={collection.id} collectionUid={collection.uid}
/> />
}) : null} }) : null}
</div> </div>

View File

@ -1,16 +1,19 @@
import React from 'react'; import React from 'react';
import { useStore } from 'providers/Store';
import Collection from './Collection'; import Collection from './Collection';
const Collections = ({collections, actions, dispatch, activeRequestTabId}) => { const Collections = () => {
const [store, storeDispatch] = useStore();
const {
collections
} = store;
return ( return (
<div className="mt-4 flex flex-col"> <div className="mt-4 flex flex-col">
{collections && collections.length ? collections.map((c) => { {collections && collections.length ? collections.map((c) => {
return <Collection return <Collection
collection={c} collection={c}
key={c.uid} key={c.uid}
actions={actions}
dispatch={dispatch}
activeRequestTabId={activeRequestTabId}
/> />
}) : null} }) : null}
</div> </div>

View File

@ -1,9 +1,10 @@
import React from 'react'; import React, { useRef, useEffect } from 'react';
import {useFormik} from 'formik'; import { useFormik } from 'formik';
import * as Yup from 'yup'; import * as Yup from 'yup';
import Modal from '../../Modal'; import Modal from '../../Modal';
const CreateCollection = ({handleConfirm, handleCancel, actions, dispatch}) => { const CreateCollection = ({handleConfirm, handleCancel, actions, dispatch}) => {
const inputRef = useRef();
const formik = useFormik({ const formik = useFormik({
enableReinitialize: true, enableReinitialize: true,
initialValues: { initialValues: {
@ -20,6 +21,12 @@ const CreateCollection = ({handleConfirm, handleCancel, actions, dispatch}) => {
} }
}); });
useEffect(() => {
if(inputRef && inputRef.current) {
inputRef.current.focus();
}
}, [inputRef]);
const onSubmit = () => formik.handleSubmit(); const onSubmit = () => formik.handleSubmit();
return ( return (
@ -33,7 +40,10 @@ const CreateCollection = ({handleConfirm, handleCancel, actions, dispatch}) => {
<div> <div>
<label htmlFor="collectionName" className="block font-semibold">Name</label> <label htmlFor="collectionName" className="block font-semibold">Name</label>
<input <input
id="collection-name" type="text" name="collectionName" id="collection-name"
type="text"
name="collectionName"
ref={inputRef}
className="block textbox mt-2 w-full" className="block textbox mt-2 w-full"
onChange={formik.handleChange} onChange={formik.handleChange}
value={formik.values.collectionName || ''} value={formik.values.collectionName || ''}

View File

@ -21,7 +21,7 @@ const NewFolder = ({collectionUid, handleCancel, handleClose}) => {
}), }),
onSubmit: (values) => { onSubmit: (values) => {
storeDispatch({ storeDispatch({
type: actions.SIDEBAR_COLLECTION_ADD_FOLDER, type: actions.SIDEBAR_COLLECTION_NEW_FOLDER,
collectionUid: collectionUid, collectionUid: collectionUid,
folderName: values.folderName folderName: values.folderName
}); });

View File

@ -0,0 +1,67 @@
import React, { useRef, useEffect } from 'react';
import { useFormik } from 'formik';
import * as Yup from 'yup';
import Modal from 'components/Modal';
import actions from 'providers/Store/actions'
import { useStore } from 'providers/Store';
const NewRequest = ({collectionUid, handleCancel, handleClose}) => {
const [store, storeDispatch] = useStore();
const inputRef = useRef();
const formik = useFormik({
enableReinitialize: true,
initialValues: {
requestName: ''
},
validationSchema: Yup.object({
requestName: Yup.string()
.min(1, 'must be atleast 1 characters')
.max(50, 'must be 50 characters or less')
.required('name is required')
}),
onSubmit: (values) => {
storeDispatch({
type: actions.SIDEBAR_COLLECTION_NEW_REQUEST,
collectionUid: collectionUid,
requestName: values.requestName
});
handleClose();
}
});
useEffect(() => {
if(inputRef && inputRef.current) {
inputRef.current.focus();
}
}, [inputRef]);
const onSubmit = () => formik.handleSubmit();
return (
<Modal
size="sm"
title='New Request'
confirmText='Create'
handleConfirm={onSubmit}
handleCancel={handleCancel}
>
<form className="grafnode-form" onSubmit={formik.handleSubmit}>
<div>
<label htmlFor="requestName" className="block font-semibold">Request Name</label>
<input
id="collection-name" type="text" name="requestName"
ref={inputRef}
className="block textbox mt-2 w-full"
onChange={formik.handleChange}
value={formik.values.requestName || ''}
/>
{formik.touched.requestName && formik.errors.requestName ? (
<div className="text-red-500">{formik.errors.requestName}</div>
) : null}
</div>
</form>
</Modal>
);
};
export default NewRequest;

View File

@ -2,13 +2,14 @@ import React, { useState, forwardRef, useRef } from 'react';
import {nanoid} from 'nanoid'; import {nanoid} from 'nanoid';
import Toast from 'components/Toast'; import Toast from 'components/Toast';
import Dropdown from 'components/Dropdown'; import Dropdown from 'components/Dropdown';
import actions from 'providers/Store/actions'
import { saveCollectionToIdb } from 'providers/Store/idb'; import { saveCollectionToIdb } from 'providers/Store/idb';
import { useStore } from 'providers/Store'; import { useStore } from 'providers/Store';
import { IconDots } from '@tabler/icons'; import { IconDots } from '@tabler/icons';
import CreateCollection from '../CreateCollection'; import CreateCollection from '../CreateCollection';
import StyledWrapper from './StyledWrapper'; import StyledWrapper from './StyledWrapper';
const TitleBar = ({dispatch, actions}) => { const TitleBar = () => {
const [modalOpen, setModalOpen] = useState(false); const [modalOpen, setModalOpen] = useState(false);
const [store, storeDispatch] = useStore(); const [store, storeDispatch] = useStore();
const [showToast, setShowToast] = useState({show: false}); const [showToast, setShowToast] = useState({show: false});
@ -32,7 +33,6 @@ const TitleBar = ({dispatch, actions}) => {
// type: actions.COLLECTION_CREATE // type: actions.COLLECTION_CREATE
// }); // });
setModalOpen(false); setModalOpen(false);
console.log(store.idbConnection);
if(!store.idbConnection) { if(!store.idbConnection) {
setShowToast({ setShowToast({
show: true, show: true,
@ -42,18 +42,12 @@ const TitleBar = ({dispatch, actions}) => {
return; return;
} }
const collectionUid = nanoid();
const newCollection = { const newCollection = {
uid: collectionUid, uid: nanoid(),
base: null,
current: {
uid: collectionUid,
name: values.collectionName, name: values.collectionName,
items: [] items: [],
}, environments: [],
userId: null, userId: null
hasChangedSinceLastSync: false,
disableSync: true
}; };
saveCollectionToIdb(store.idbConnection, newCollection) saveCollectionToIdb(store.idbConnection, newCollection)
@ -76,7 +70,7 @@ const TitleBar = ({dispatch, actions}) => {
handleCancel={handleCancel} handleCancel={handleCancel}
handleConfirm={handleConfirm} handleConfirm={handleConfirm}
actions={actions} actions={actions}
dispatch={dispatch} dispatch={storeDispatch}
/> />
) : null} ) : null}

View File

@ -5,18 +5,14 @@ import TitleBar from './TitleBar';
import { IconSearch } from '@tabler/icons'; import { IconSearch } from '@tabler/icons';
import StyledWrapper from './StyledWrapper'; import StyledWrapper from './StyledWrapper';
const Sidebar = ({collections, actions, dispatch, activeRequestTabId}) => { const Sidebar = () => {
return ( return (
<StyledWrapper> <StyledWrapper>
<div className="flex flex-row h-full"> <div className="flex flex-row h-full">
<MenuBar /> <MenuBar />
<div className="flex flex-col flex-grow"> <div className="flex flex-col flex-grow">
<TitleBar <TitleBar />
actions={actions}
dispatch={dispatch}
/>
<div className="mt-4 relative collection-filter px-2"> <div className="mt-4 relative collection-filter px-2">
<div className="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none"> <div className="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none">
@ -33,12 +29,7 @@ const Sidebar = ({collections, actions, dispatch, activeRequestTabId}) => {
/> />
</div> </div>
<Collections <Collections />
collections={collections}
actions={actions}
dispatch={dispatch}
activeRequestTabId={activeRequestTabId}
/>
</div> </div>
</div> </div>
</StyledWrapper> </StyledWrapper>

View File

@ -2,8 +2,6 @@ import React from 'react';
import RequestTabs from 'components/RequestTabs'; import RequestTabs from 'components/RequestTabs';
import RequestTabPanel from 'components/RequestTabPanel'; import RequestTabPanel from 'components/RequestTabPanel';
import Sidebar from 'components/Sidebar'; import Sidebar from 'components/Sidebar';
import actions from 'providers/Store/actions';
import { useStore } from 'providers/Store';
import StyledWrapper from './StyledWrapper'; import StyledWrapper from './StyledWrapper';
const SERVER_RENDERED = typeof navigator === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true; const SERVER_RENDERED = typeof navigator === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true;
@ -31,36 +29,17 @@ if(!SERVER_RENDERED) {
export default function Main() { export default function Main() {
const [state, dispatch] = useStore();
if (SERVER_RENDERED) { if (SERVER_RENDERED) {
return null; return null;
} }
const {
collections,
requestTabs,
activeRequestTabId
} = state;
return ( return (
<div> <div>
<StyledWrapper> <StyledWrapper>
<Sidebar <Sidebar />
collections={collections}
actions={actions}
dispatch={dispatch}
activeRequestTabId={activeRequestTabId}
/>
<section className='flex flex-grow flex-col'> <section className='flex flex-grow flex-col'>
<RequestTabs/> <RequestTabs />
<RequestTabPanel <RequestTabPanel />
actions={actions}
dispatch={dispatch}
collections={collections}
requestTabs={requestTabs}
activeRequestTabId={activeRequestTabId}
/>
</section> </section>
</StyledWrapper> </StyledWrapper>
</div> </div>

View File

@ -1,6 +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 SIDEBAR_COLLECTION_NEW_FOLDER = "SIDEBAR_COLLECTION_NEW_FOLDER";
const SIDEBAR_COLLECTION_NEW_REQUEST = "SIDEBAR_COLLECTION_NEW_REQUEST";
const LOAD_COLLECTIONS_FROM_IDB = "LOAD_COLLECTIONS_FROM_IDB"; 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";
@ -20,7 +21,8 @@ const IDB_COLLECTIONS_SYNC_ERROR = "IDB_COLLECTIONS_SYNC_ERROR";
export default { export default {
SIDEBAR_COLLECTION_CLICK, SIDEBAR_COLLECTION_CLICK,
SIDEBAR_COLLECTION_ITEM_CLICK, SIDEBAR_COLLECTION_ITEM_CLICK,
SIDEBAR_COLLECTION_ADD_FOLDER, SIDEBAR_COLLECTION_NEW_FOLDER,
SIDEBAR_COLLECTION_NEW_REQUEST,
LOAD_COLLECTIONS_FROM_IDB, LOAD_COLLECTIONS_FROM_IDB,
COLLECTION_CREATE, COLLECTION_CREATE,
REQUEST_TAB_CLICK, REQUEST_TAB_CLICK,

View File

@ -116,7 +116,7 @@ const collection2 = {
const initialState = { const initialState = {
idbConnection: null, idbConnection: null,
collections: [], collections: [],
activeRequestTabId: null, activeRequestTabUid: null,
requestQueuedToSend: null, requestQueuedToSend: null,
requestTabs: [], requestTabs: [],
collectionsToSyncToIdb: [] collectionsToSyncToIdb: []
@ -135,10 +135,10 @@ export const StoreProvider = props => {
if(state.requestQueuedToSend) { if(state.requestQueuedToSend) {
const { const {
request, request,
collectionId collectionUid
} = state.requestQueuedToSend; } = state.requestQueuedToSend;
sendRequest(request, collectionId, dispatch) sendRequest(request, collectionUid, dispatch)
} }
}, [state.requestQueuedToSend]); }, [state.requestQueuedToSend]);

View File

@ -1,6 +1,5 @@
import produce from 'immer'; import produce from 'immer';
import {nanoid} from 'nanoid'; import {nanoid} from 'nanoid';
import find from 'lodash/find';
import union from 'lodash/union'; import union from 'lodash/union';
import filter from 'lodash/filter'; import filter from 'lodash/filter';
import last from 'lodash/last'; import last from 'lodash/last';
@ -57,23 +56,23 @@ const reducer = (state, action) => {
if(collection) { if(collection) {
let flattenedItems = flattenItems(collection.items); let flattenedItems = flattenItems(collection.items);
let item = findItem(flattenedItems, action.itemId); let item = findItem(flattenedItems, action.itemUid);
if(item) { if(item) {
item.collapsed = !item.collapsed; item.collapsed = !item.collapsed;
if(isItemARequest(item)) { if(isItemARequest(item)) {
if(itemIsOpenedInTabs(item, draft.requestTabs)) { if(itemIsOpenedInTabs(item, draft.requestTabs)) {
draft.activeRequestTabId = item.id; draft.activeRequestTabUid = item.uid;
} else { } else {
draft.requestTabs.push({ draft.requestTabs.push({
id: item.id, uid: item.uid,
name: item.name, name: item.name,
method: item.request.method, method: item.request.method,
collectionId: collection.id, collectionUid: collection.uid,
hasChanges: false hasChanges: false
}); });
draft.activeRequestTabId = item.id; draft.activeRequestTabUid = item.uid;
} }
} }
} }
@ -81,16 +80,50 @@ const reducer = (state, action) => {
}); });
} }
case actions.SIDEBAR_COLLECTION_ADD_FOLDER: { case actions.SIDEBAR_COLLECTION_NEW_REQUEST: {
return produce(state, (draft) => { return produce(state, (draft) => {
const collection = findCollectionByUid(draft.collections, action.collectionUid); const collection = findCollectionByUid(draft.collections, action.collectionUid);
if(collection) { if(collection) {
collection.current.items.push({ const uid = nanoid();
"uid": nanoid(), const item = {
"name": action.folderName, uid: uid,
"depth": 1, name: action.requestName,
"items": [] request: {
type: 'http',
method: 'GET',
url: 'https://reqbin.com/echo/get/json',
headers: [],
body: null
},
depth: 1
};
collection.items.push(item);
draft.requestTabs.push({
uid: item.uid,
name: item.name,
method: item.request.method,
collectionUid: collection.uid,
hasChanges: false
});
draft.activeRequestTabUid = uid;
draft.collectionsToSyncToIdb.push(collection.uid);
}
});
}
case actions.SIDEBAR_COLLECTION_NEW_FOLDER: {
return produce(state, (draft) => {
const collection = findCollectionByUid(draft.collections, action.collectionUid);
if(collection) {
collection.items.push({
uid: nanoid(),
name: action.folderName,
items: [],
// todo: this will be autoassigned
depth: 1
}); });
draft.collectionsToSyncToIdb.push(collection.uid); draft.collectionsToSyncToIdb.push(collection.uid);
} }
@ -102,7 +135,7 @@ const reducer = (state, action) => {
// todo: collection names must be unique across a user account // todo: collection names must be unique across a user account
draft.collections = draft.collections || []; draft.collections = draft.collections || [];
draft.collections.push({ draft.collections.push({
id: nanoid(), uid: nanoid(),
name: action.name, name: action.name,
items: [] items: []
}); });
@ -111,7 +144,7 @@ const reducer = (state, action) => {
case actions.REQUEST_TAB_CLICK: { case actions.REQUEST_TAB_CLICK: {
return produce(state, (draft) => { return produce(state, (draft) => {
draft.activeRequestTabId = action.requestTab.id; draft.activeRequestTabUid = action.requestTab.uid;
}); });
} }
@ -153,7 +186,7 @@ const reducer = (state, action) => {
return produce(state, (draft) => { return produce(state, (draft) => {
const uid = nanoid(); const uid = nanoid();
draft.requestTabs.push({ draft.requestTabs.push({
id: uid, uid: uid,
name: 'New Tab', name: 'New Tab',
method: 'GET', method: 'GET',
request: { request: {
@ -161,9 +194,9 @@ const reducer = (state, action) => {
url: 'https://api.spacex.land/graphql/', url: 'https://api.spacex.land/graphql/',
body: {} body: {}
}, },
collectionId: null collectionUid: null
}); });
draft.activeRequestTabId = uid; draft.activeRequestTabUid = uid;
}); });
} }
@ -171,7 +204,7 @@ const reducer = (state, action) => {
return produce(state, (draft) => { return produce(state, (draft) => {
const uid = nanoid(); const uid = nanoid();
draft.requestTabs.push({ draft.requestTabs.push({
id: uid, uid: uid,
name: 'New Tab', name: 'New Tab',
method: 'GET', method: 'GET',
request: { request: {
@ -183,9 +216,9 @@ const reducer = (state, action) => {
} }
} }
}, },
collectionId: null collectionUid: null
}); });
draft.activeRequestTabId = uid; draft.activeRequestTabUid = uid;
}); });
} }
@ -201,7 +234,7 @@ const reducer = (state, action) => {
item.response = item.response || {}; item.response = item.response || {};
item.response.state = 'queued'; item.response.state = 'queued';
draft.requestQueuedToSend = { draft.requestQueuedToSend = {
collectionId: action.collectionId, collectionUid: action.collectionUid,
request: item request: item
} }
} }
@ -246,9 +279,9 @@ const reducer = (state, action) => {
if(draft.requestTabs && draft.requestTabs.length) { if(draft.requestTabs && draft.requestTabs.length) {
// todo: closing tab needs to focus on the right adjacent tab // todo: closing tab needs to focus on the right adjacent tab
draft.activeRequestTabId = last(draft.requestTabs).id; draft.activeRequestTabUid = last(draft.requestTabs).uid;
} else { } else {
draft.activeRequestTabId = null; draft.activeRequestTabUid = null;
} }
}); });
} }
@ -264,7 +297,7 @@ const reducer = (state, action) => {
if(item) { if(item) {
if(!isItemARequest(item)) { if(!isItemARequest(item)) {
let newRequest = { let newRequest = {
"id": nanoid(), "uid": nanoid(),
"depth": 2, "depth": 2,
"name": "Capsules 2", "name": "Capsules 2",
"request": { "request": {
@ -282,13 +315,13 @@ const reducer = (state, action) => {
}, },
"response": null "response": null
}; };
draft.activeRequestTabId = newRequest.id; draft.activeRequestTabUid = newRequest.uid;
item.items.push(newRequest); item.items.push(newRequest);
draft.requestTabs.push({ draft.requestTabs.push({
id: newRequest.id, uid: newRequest.uid,
name: newRequest.name, name: newRequest.name,
method: newRequest.request.method, method: newRequest.request.method,
collectionId: collection.id collectionUid: collection.id
}); });
} }
} }

View File

@ -20,8 +20,8 @@ export const flattenItems = (items = []) => {
return flattenedItems; return flattenedItems;
}; };
export const findItem = (items = [], itemId) => { export const findItem = (items = [], itemUid) => {
return find(items, (i) => i.id === itemId); return find(items, (i) => i.uid === itemUid);
}; };
export const isItemARequest = (item) => { export const isItemARequest = (item) => {
@ -29,15 +29,15 @@ export const isItemARequest = (item) => {
}; };
export const itemIsOpenedInTabs = (item, tabs) => { export const itemIsOpenedInTabs = (item, tabs) => {
return find(tabs, (t) => t.id === item.id); return find(tabs, (t) => t.uid === item.uid);
}; };
export const cloneItem = (item) => { export const cloneItem = (item) => {
return cloneDeep(item); return cloneDeep(item);
}; };
export const updateRequestTabAsChanged = (requestTabs, itemId) => { export const updateRequestTabAsChanged = (requestTabs, itemUid) => {
let currentTab = find(requestTabs, (rt) => rt.id == itemId); let currentTab = find(requestTabs, (rt) => rt.uid == itemUid);
if(currentTab) { if(currentTab) {
currentTab.hasChanges = true; currentTab.hasChanges = true;
} }

View File

@ -19,8 +19,8 @@ export const flattenItems = (items = []) => {
return flattenedItems; return flattenedItems;
}; };
export const findItem = (items = [], itemId) => { export const findItem = (items = [], itemUid) => {
return find(items, (i) => i.id === itemId); return find(items, (i) => i.uid === itemUid);
}; };
export const isItemARequest = (item) => { export const isItemARequest = (item) => {
@ -28,5 +28,5 @@ export const isItemARequest = (item) => {
}; };
export const itemIsOpenedInTabs = (item, tabs) => { export const itemIsOpenedInTabs = (item, tabs) => {
return find(tabs, (t) => t.id === item.id); return find(tabs, (t) => t.uid === item.uid);
}; };