From 914927bbfd2535341be25d50cf40eb53b5c62f55 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Fri, 18 Mar 2022 04:43:35 +0530 Subject: [PATCH] refactor: redux migration - request tabs --- renderer/components/RequestTabs/index.js | 69 ++++++----- .../Collection/CollectionItem/index.js | 47 ++++---- .../Sidebar/Collections/Collection/index.js | 2 +- renderer/providers/ReduxStore/index.js | 4 +- .../ReduxStore/slices/collections.js | 2 +- renderer/providers/ReduxStore/slices/tabs.js | 45 +++++++ renderer/providers/Store/actions.js | 10 -- renderer/providers/Store/reducer.js | 114 ------------------ renderer/utils/collections/index.js | 29 +++++ renderer/utils/tabs/index.js | 9 ++ 10 files changed, 147 insertions(+), 184 deletions(-) create mode 100644 renderer/providers/ReduxStore/slices/tabs.js create mode 100644 renderer/utils/tabs/index.js diff --git a/renderer/components/RequestTabs/index.js b/renderer/components/RequestTabs/index.js index 1c21ae4f..f031e5c4 100644 --- a/renderer/components/RequestTabs/index.js +++ b/renderer/components/RequestTabs/index.js @@ -3,24 +3,22 @@ import find from 'lodash/find'; import filter from 'lodash/filter'; import classnames from 'classnames'; import { IconHome2 } from '@tabler/icons'; -import { useStore } from 'providers/Store'; -import actions from 'providers/Store/actions'; +import { useSelector, useDispatch } from 'react-redux'; +import { focusTab, closeTab } from 'providers/ReduxStore/slices/tabs'; +import { findItemInCollection } from 'utils/collections'; import CollectionToolBar from './CollectionToolBar'; import StyledWrapper from './StyledWrapper'; const RequestTabs = () => { - const [store, storeDispatch] = useStore(); - - const { - collections, - requestTabs, - activeRequestTabUid - } = store; + const tabs = useSelector((state) => state.tabs.tabs); + const activeTabUid = useSelector((state) => state.tabs.activeTabUid); + const collections = useSelector((state) => state.collections.collections); + const dispatch = useDispatch(); const getTabClassname = (tab, index) => { return classnames("request-tab select-none", { - 'active': tab.uid === activeRequestTabUid, - 'last-tab': requestTabs && requestTabs.length && (index === requestTabs.length - 1) + 'active': tab.uid === activeTabUid, + 'last-tab': tabs && tabs.length && (index === tabs.length - 1) }); }; @@ -41,33 +39,27 @@ const RequestTabs = () => { }; const handleClick = (tab) => { - storeDispatch({ - type: actions.REQUEST_TAB_CLICK, - requestTab: tab - }); + dispatch(focusTab({ + uid: tab.uid + })); }; const handleCloseClick = (event, tab) => { event.stopPropagation(); event.preventDefault(); - storeDispatch({ - type: actions.REQUEST_TAB_CLOSE, - requestTab: tab - }); + dispatch(closeTab(tab.uid)) }; const createNewTab = () => { - storeDispatch({ - type: actions.ADD_NEW_HTTP_REQUEST - }); + // todo }; - if(!activeRequestTabUid) { + if(!activeTabUid) { return null; } - const activeRequestTab = find(requestTabs, (t) => t.uid === activeRequestTabUid); - if(!activeRequestTab) { + const activeTab = find(tabs, (t) => t.uid === activeTabUid); + if(!activeTab) { return ( Something went wrong! @@ -75,8 +67,19 @@ const RequestTabs = () => { ); } - const activeCollection = find(collections, (c) => c.uid === activeRequestTab.collectionUid); - const collectionRequestTabs = filter(requestTabs, (t) => t.collectionUid === activeRequestTab.collectionUid); + const activeCollection = find(collections, (c) => c.uid === activeTab.collectionUid); + const collectionRequestTabs = filter(tabs, (t) => t.collectionUid === activeTab.collectionUid); + const item = findItemInCollection(activeCollection, activeTab.uid); + + const getRequestName = (tab) => { + const item = findItemInCollection(activeCollection, tab.uid); + return item.name; + } + + const getRequestMethod = (tab) => { + const item = findItemInCollection(activeCollection, tab.uid); + return item.request.name; + } return ( @@ -90,15 +93,15 @@ const RequestTabs = () => { - {collectionRequestTabs && collectionRequestTabs.length ? collectionRequestTabs.map((rt, index) => { - return
  • handleClick(rt)}> + {collectionRequestTabs && collectionRequestTabs.length ? collectionRequestTabs.map((tab, index) => { + return
  • handleClick(tab)}>
    - {rt.method} - {rt.name} + {getRequestMethod(tab)} + {getRequestName(tab)}
    -
    handleCloseClick(e, rt)}> - {!rt.hasChanges ? ( +
    handleCloseClick(e, tab)}> + {!tab.hasChanges ? ( diff --git a/renderer/components/Sidebar/Collections/Collection/CollectionItem/index.js b/renderer/components/Sidebar/Collections/Collection/CollectionItem/index.js index 0cb7d993..ce8843af 100644 --- a/renderer/components/Sidebar/Collections/Collection/CollectionItem/index.js +++ b/renderer/components/Sidebar/Collections/Collection/CollectionItem/index.js @@ -1,21 +1,20 @@ import React, { useRef, forwardRef } from 'react'; import range from 'lodash/range'; import get from 'lodash/get'; -import actions from 'providers/Store/actions' -import { useStore } from 'providers/Store'; import { IconChevronRight, IconDots } from '@tabler/icons'; import classnames from 'classnames'; +import { useSelector, useDispatch } from 'react-redux'; +import { addTab, focusTab } from 'providers/ReduxStore/slices/tabs'; +import { isItemARequest, itemIsOpenedInTabs } from 'utils/tabs'; import Dropdown from 'components/Dropdown'; import RequestMethod from './RequestMethod'; import StyledWrapper from './StyledWrapper'; -const CollectionItem = ({item, collectionUid}) => { - const [store, storeDispatch] = useStore(); - - const { - activeRequestTabUid - } = store; +const CollectionItem = ({item, collection}) => { + const tabs = useSelector((state) => state.tabs.tabs); + const activeTabUid = useSelector((state) => state.tabs.activeTabUid); + const dispatch = useDispatch(); const dropdownTippyRef = useRef(); const MenuIcon = forwardRef((props, ref) => { @@ -31,7 +30,7 @@ const CollectionItem = ({item, collectionUid}) => { }); const itemRowClassName = classnames('flex collection-item-name items-center', { - 'item-focused-in-tab': item.uid == activeRequestTabUid + 'item-focused-in-tab': item.uid == activeTabUid }); const handleClick = (event) => { @@ -40,19 +39,20 @@ const CollectionItem = ({item, collectionUid}) => { return; } - storeDispatch({ - type: actions.SIDEBAR_COLLECTION_ITEM_CLICK, - itemUid: item.uid, - collectionUid: collectionUid - }); - }; - - const addRequest = () => { - storeDispatch({ - type: actions.ADD_REQUEST, - itemUid: item.uid, - collectionUid: collectionUid - }); + if(isItemARequest(item)) { + if(itemIsOpenedInTabs(item, tabs)) { + dispatch(focusTab({ + uid: item.uid + })); + } else { + dispatch(addTab({ + uid: item.uid, + collectionUid: collection.uid + })); + } + } else { + // todo for folder: must expand folder : item.collapsed = !item.collapsed; + } }; let indents = range(item.depth); @@ -100,7 +100,6 @@ const CollectionItem = ({item, collectionUid}) => { } placement='bottom-start'>
    { dropdownTippyRef.current.hide(); - addRequest(); }}> New Request
    @@ -130,7 +129,7 @@ const CollectionItem = ({item, collectionUid}) => { return }) : null}
    diff --git a/renderer/components/Sidebar/Collections/Collection/index.js b/renderer/components/Sidebar/Collections/Collection/index.js index 8fecbf85..16188be5 100644 --- a/renderer/components/Sidebar/Collections/Collection/index.js +++ b/renderer/components/Sidebar/Collections/Collection/index.js @@ -90,7 +90,7 @@ const Collection = ({collection}) => { return }) : null}
    diff --git a/renderer/providers/ReduxStore/index.js b/renderer/providers/ReduxStore/index.js index 4c4ffe90..d86b18fc 100644 --- a/renderer/providers/ReduxStore/index.js +++ b/renderer/providers/ReduxStore/index.js @@ -1,11 +1,13 @@ import { configureStore } from '@reduxjs/toolkit'; import appReducer from './slices/app'; import collectionsReducer from './slices/collections'; +import tabsReducer from './slices/tabs'; export const store = configureStore({ reducer: { app: appReducer, - collections: collectionsReducer + collections: collectionsReducer, + tabs: tabsReducer } }); diff --git a/renderer/providers/ReduxStore/slices/collections.js b/renderer/providers/ReduxStore/slices/collections.js index 818b01c7..7c0da366 100644 --- a/renderer/providers/ReduxStore/slices/collections.js +++ b/renderer/providers/ReduxStore/slices/collections.js @@ -10,7 +10,7 @@ const initialState = { }; export const collectionsSlice = createSlice({ - name: 'app', + name: 'collections', initialState, reducers: { _loadCollections: (state, action) => { diff --git a/renderer/providers/ReduxStore/slices/tabs.js b/renderer/providers/ReduxStore/slices/tabs.js new file mode 100644 index 00000000..5f98deaf --- /dev/null +++ b/renderer/providers/ReduxStore/slices/tabs.js @@ -0,0 +1,45 @@ +import filter from 'lodash/filter'; +import last from 'lodash/last'; +import { createSlice } from '@reduxjs/toolkit' + +// todo: errors should be tracked in each slice and displayed as toasts + +const initialState = { + tabs: [], + activeTabUid: null +}; + +export const tabsSlice = createSlice({ + name: 'tabs', + initialState, + reducers: { + addTab: (state, action) => { + state.tabs.push({ + uid: action.payload.uid, + collectionUid: action.payload.collectionUid + }); + state.activeTabUid = action.payload.uid; + }, + focusTab: (state, action) => { + state.activeTabUid = action.payload.uid; + }, + closeTab: (state, action) => { + state.tabs = filter(state.tabs, (t) => t.uid !== action.payload); + + if(state.tabs && state.tabs.length) { + // todo: closing tab needs to focus on the right adjacent tab + state.activeTabUid = last(state.tabs).uid; + } else { + state.activeTabUid = null; + } + } + } +}); + +export const { + addTab, + focusTab, + closeTab +} = tabsSlice.actions; + +export default tabsSlice.reducer; diff --git a/renderer/providers/Store/actions.js b/renderer/providers/Store/actions.js index 7579a0fd..4d63f4ba 100644 --- a/renderer/providers/Store/actions.js +++ b/renderer/providers/Store/actions.js @@ -1,16 +1,11 @@ -const SIDEBAR_COLLECTION_ITEM_CLICK = "SIDEBAR_COLLECTION_ITEM_CLICK"; 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 REQUEST_TAB_CLICK = "REQUEST_TAB_CLICK"; -const REQUEST_TAB_CLOSE = "REQUEST_TAB_CLOSE"; const REQUEST_URL_CHANGED = "REQUEST_URL_CHANGED"; const REQUEST_GQL_QUERY_CHANGED = "REQUEST_GQL_QUERY_CHANGED"; const RESPONSE_RECEIVED = "RESPONSE_RECEIVED"; const SEND_REQUEST = "SEND_REQUEST"; const SENDING_REQUEST = "SENDING_REQUEST"; -const ADD_REQUEST = "ADD_REQUEST"; -const ADD_NEW_HTTP_REQUEST = "ADD_NEW_HTTP_REQUEST"; const ADD_NEW_GQL_REQUEST = "ADD_NEW_GQL_REQUEST"; const IDB_CONNECTION_READY = "IDB_CONNECTION_READY"; const IDB_COLLECTIONS_SYNC_STARTED = "IDB_COLLECTIONS_SYNC_STARTED"; @@ -18,19 +13,14 @@ const IDB_COLLECTIONS_SYNC_ERROR = "IDB_COLLECTIONS_SYNC_ERROR"; const HOTKEY_SAVE = "HOTKEY_SAVE"; export default { - SIDEBAR_COLLECTION_ITEM_CLICK, SIDEBAR_COLLECTION_NEW_FOLDER, SIDEBAR_COLLECTION_NEW_REQUEST, LOAD_COLLECTIONS_FROM_IDB, - REQUEST_TAB_CLICK, - REQUEST_TAB_CLOSE, REQUEST_URL_CHANGED, REQUEST_GQL_QUERY_CHANGED, RESPONSE_RECEIVED, SEND_REQUEST, SENDING_REQUEST, - ADD_REQUEST, - ADD_NEW_HTTP_REQUEST, ADD_NEW_GQL_REQUEST, IDB_CONNECTION_READY, IDB_COLLECTIONS_SYNC_STARTED, diff --git a/renderer/providers/Store/reducer.js b/renderer/providers/Store/reducer.js index d2c3eb88..ad69cdce 100644 --- a/renderer/providers/Store/reducer.js +++ b/renderer/providers/Store/reducer.js @@ -2,14 +2,10 @@ import produce from 'immer'; import {nanoid} from 'nanoid'; import union from 'lodash/union'; import find from 'lodash/find'; -import filter from 'lodash/filter'; -import last from 'lodash/last'; import actions from './actions'; import { flattenItems, findItem, - isItemARequest, - itemIsOpenedInTabs, cloneItem, updateRequestTabAsChanged, findCollectionByUid @@ -41,36 +37,6 @@ const reducer = (state, action) => { }); } - case actions.SIDEBAR_COLLECTION_ITEM_CLICK: { - return produce(state, (draft) => { - const collection = findCollectionByUid(draft.collections, action.collectionUid); - - if(collection) { - let flattenedItems = flattenItems(collection.items); - let item = findItem(flattenedItems, action.itemUid); - - if(item) { - item.collapsed = !item.collapsed; - - if(isItemARequest(item)) { - if(itemIsOpenedInTabs(item, draft.requestTabs)) { - draft.activeRequestTabUid = item.uid; - } else { - draft.requestTabs.push({ - uid: item.uid, - name: item.name, - method: item.request.method, - collectionUid: collection.uid, - hasChanges: false - }); - draft.activeRequestTabUid = item.uid; - } - } - } - } - }); - } - case actions.SIDEBAR_COLLECTION_NEW_REQUEST: { return produce(state, (draft) => { const collection = findCollectionByUid(draft.collections, action.collectionUid); @@ -122,12 +88,6 @@ const reducer = (state, action) => { }); } - case actions.REQUEST_TAB_CLICK: { - return produce(state, (draft) => { - draft.activeRequestTabUid = action.requestTab.uid; - }); - } - case actions.REQUEST_URL_CHANGED: { return produce(state, (draft) => { const collection = findCollectionByUid(draft.collections, action.collectionUid); @@ -162,24 +122,6 @@ const reducer = (state, action) => { }); } - case actions.ADD_NEW_HTTP_REQUEST: { - return produce(state, (draft) => { - const uid = nanoid(); - draft.requestTabs.push({ - uid: uid, - name: 'New Tab', - type: 'http-request', - request: { - method: 'GET', - url: 'https://api.spacex.land/graphql/', - body: {} - }, - collectionUid: null - }); - draft.activeRequestTabUid = uid; - }); - } - case actions.ADD_NEW_GQL_REQUEST: { return produce(state, (draft) => { const uid = nanoid(); @@ -257,62 +199,6 @@ const reducer = (state, action) => { }); } - case actions.REQUEST_TAB_CLOSE: { - return produce(state, (draft) => { - draft.requestTabs = filter(draft.requestTabs, (rt) => rt.id !== action.requestTab.id); - - if(draft.requestTabs && draft.requestTabs.length) { - // todo: closing tab needs to focus on the right adjacent tab - draft.activeRequestTabUid = last(draft.requestTabs).uid; - } else { - draft.activeRequestTabUid = null; - } - }); - } - - case actions.ADD_REQUEST: { - return produce(state, (draft) => { - const collection = findCollectionByUid(draft.collections, action.collectionUid); - - if(collection) { - let flattenedItems = flattenItems(collection.items); - let item = findItem(flattenedItems, action.itemId); - - if(item) { - if(!isItemARequest(item)) { - let newRequest = { - "uid": nanoid(), - "depth": 2, - "name": "Capsules 2", - "type": "graphql-request", - "request": { - "url": "https://api.spacex.land/graphql/", - "method": "POST", - "headers": [], - "body": { - "mimeType": "application/graphql", - "graphql": { - "query": "{\n launchesPast(limit: 10) {\n mission_name\n launch_date_local\n launch_site {\n site_name_long\n }\n links {\n article_link\n video_link\n }\n rocket {\n rocket_name\n first_stage {\n cores {\n flight\n core {\n reuse_count\n status\n }\n }\n }\n second_stage {\n payloads {\n payload_type\n payload_mass_kg\n payload_mass_lbs\n }\n }\n }\n ships {\n name\n home_port\n image\n }\n }\n}", - "variables": "" - } - } - }, - "response": null - }; - draft.activeRequestTabUid = newRequest.uid; - item.items.push(newRequest); - draft.requestTabs.push({ - uid: newRequest.uid, - name: newRequest.name, - method: newRequest.request.method, - collectionUid: collection.id - }); - } - } - } - }); - } - case actions.HOTKEY_SAVE: { return produce(state, (draft) => { if(!draft.activeRequestTabUid) { diff --git a/renderer/utils/collections/index.js b/renderer/utils/collections/index.js index 65ee095f..590c6870 100644 --- a/renderer/utils/collections/index.js +++ b/renderer/utils/collections/index.js @@ -1,5 +1,34 @@ +import each from 'lodash/each'; import find from 'lodash/find'; +export const flattenItems = (items = []) => { + const flattenedItems = []; + + const flatten = (itms, flattened) => { + each(itms, (i) => { + flattened.push(i); + + if(i.items && i.items.length) { + flatten(i.items, flattened); + } + }) + } + + flatten(items, flattenedItems); + + return flattenedItems; +}; + +export const findItem = (items = [], itemUid) => { + return find(items, (i) => i.uid === itemUid); +}; + export const findCollectionByUid = (collections, collectionUid) => { return find(collections, (c) => c.uid === collectionUid); }; + +export const findItemInCollection = (collection, itemUid) => { + let flattenedItems = flattenItems(collection.items); + + return findItem(flattenedItems, itemUid); +} \ No newline at end of file diff --git a/renderer/utils/tabs/index.js b/renderer/utils/tabs/index.js new file mode 100644 index 00000000..546f26b5 --- /dev/null +++ b/renderer/utils/tabs/index.js @@ -0,0 +1,9 @@ +import find from 'lodash/find'; + +export const isItemARequest = (item) => { + return item.hasOwnProperty('request'); +}; + +export const itemIsOpenedInTabs = (item, tabs) => { + return find(tabs, (t) => t.uid === item.uid); +};