refactor: redux migration - sending requests

This commit is contained in:
Anoop M D 2022-03-18 14:45:27 +05:30
parent 914927bbfd
commit 038eb47dda
10 changed files with 111 additions and 219 deletions

View File

@ -2,16 +2,14 @@ import React, { useState, useEffect } from 'react';
import find from 'lodash/find';
import { useStore } from 'providers/Store';
import actions from 'providers/Store/actions';
import { useSelector, useDispatch } from 'react-redux';
import QueryUrl from 'components/QueryUrl';
import GraphQLRequestPane from 'components/GraphQLRequestPane';
import HttpRequestPane from 'components/HttpRequestPane';
import ResponsePane from 'components/ResponsePane';
import Welcome from 'components/Welcome';
import {
flattenItems,
findItem
} from '../../utils';
import { sendRequest } from '../../network';
import { findItemInCollection } from 'utils/collections';
import { sendRequest } from 'providers/ReduxStore/slices/collections';
import useGraphqlSchema from '../../hooks/useGraphqlSchema';
import StyledWrapper from './StyledWrapper';
@ -20,14 +18,12 @@ const RequestTabPanel = () => {
if(typeof window == 'undefined') {
return <div></div>;
}
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 [store, storeDispatch] = useStore();
const {
collections,
requestTabs,
activeRequestTabUid
} = store;
let asideWidth = 270;
let {
schema
@ -72,13 +68,13 @@ const RequestTabPanel = () => {
});
};
if(!activeRequestTabUid) {
if(!activeTabUid) {
return (
<Welcome dispatch={storeDispatch} actions={actions}/>
);
}
const focusedTab = find(requestTabs, (rt) => rt.uid === activeRequestTabUid);
const focusedTab = find(tabs, (t) => t.uid === activeTabUid);
if(!focusedTab || !focusedTab.uid || !focusedTab.collectionUid) {
return (
@ -93,8 +89,7 @@ const RequestTabPanel = () => {
);
}
let flattenedItems = flattenItems(collection.items);
let item = findItem(flattenedItems, activeRequestTabUid);
const item = findItemInCollection(collection, activeTabUid);
const onUrlChange = (value) => {
storeDispatch({
@ -114,7 +109,7 @@ const RequestTabPanel = () => {
};
const sendNetworkRequest = async () => {
sendRequest(item, collection.uid, storeDispatch);
dispatch(sendRequest(item, collection.uid));
};
return (

View File

@ -12,4 +12,4 @@
}
},
"exclude": ["node_modules", "dist"]
}
}

View File

@ -1,88 +0,0 @@
import actions from '../providers/Store/actions';
import { rawRequest, gql } from 'graphql-request';
const sendRequest = async (item, collectionUid, dispatch) => {
if(item.type === 'http-request') {
dispatch({
type: actions.SENDING_REQUEST,
collectionUid: collectionUid,
itemUid: item.uid
});
const timeStart = Date.now();
sendHttpRequest(item.request)
.then((response) => {
console.log(response);
const timeEnd = Date.now();
dispatch({
type: actions.RESPONSE_RECEIVED,
response: {
state: 'success',
data: response.data,
headers: Object.entries(response.headers),
size: response.headers["content-length"],
status: response.status,
duration: timeEnd - timeStart
},
collectionUid: collectionUid,
itemUid: item.uid
});
})
.catch((err) => console.error(err));
}
};
const sendHttpRequest = async (request) => {
return new Promise((resolve, reject) => {
const { ipcRenderer } = window.require("electron");
console.log(request);
let options = {
method: request.method,
url: request.url,
};
ipcRenderer
.invoke('send-http-request', options)
.then(resolve)
.catch(reject);
});
};
const sendGraphqlRequest = async (request, collectionId, dispatch) => {
dispatch({
type: actions.SENDING_REQUEST,
request: request,
collectionId: collectionId
});
const query = gql`${request.request.body.graphql.query}`;
const timeStart = Date.now();
const { data, errors, extensions, headers, status } = await rawRequest(request.request.url, query);
const timeEnd = Date.now();
if(data && !errors) {
// todo: alternate way to calculate length when content length is not present
const size = headers.map["content-length"];
dispatch({
type: actions.RESPONSE_RECEIVED,
response: {
data: data,
headers: Object.entries(headers.map),
size: size,
status: status,
duration: timeEnd - timeStart
},
request: request,
collectionId: collectionId
});
}
};
export {
sendRequest,
sendGraphqlRequest
};

View File

@ -2,7 +2,7 @@ import React from 'react';
import RequestTabs from 'components/RequestTabs';
import RequestTabPanel from 'components/RequestTabPanel';
import Sidebar from 'components/Sidebar';
import { useStore } from 'providers/Store';
import { useSelector } from 'react-redux';
import StyledWrapper from './StyledWrapper';
const SERVER_RENDERED = typeof navigator === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true;
@ -30,10 +30,7 @@ if(!SERVER_RENDERED) {
export default function Main() {
const [store, storeDispatch] = useStore();
const {
activeRequestTabUid
} = store;
const activeTabUid = useSelector((state) => state.tabs.activeTabUid);
if (SERVER_RENDERED) {
return null;
@ -45,7 +42,7 @@ export default function Main() {
<Sidebar />
<section className='flex flex-grow flex-col'>
<RequestTabs />
<RequestTabPanel key={activeRequestTabUid}/>
<RequestTabPanel key={activeTabUid}/>
</section>
</StyledWrapper>
</div>

View File

@ -1,7 +1,8 @@
import { nanoid } from 'nanoid';
import { createSlice } from '@reduxjs/toolkit'
import { getCollectionsFromIdb, saveCollectionToIdb } from 'utils/idb';
import { findCollectionByUid } from 'utils/collections';
import { sendNetworkRequest } from 'utils/network';
import { findCollectionByUid, findItemInCollection } from 'utils/collections';
// todo: errors should be tracked in each slice and displayed as toasts
@ -19,6 +20,27 @@ export const collectionsSlice = createSlice({
_createCollection: (state, action) => {
state.collections.push(action.payload);
},
_requestSent: (state, action) => {
const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
if(collection) {
const item = findItemInCollection(collection, action.payload.itemUid);
if(item) {
item.response = item.response || {};
item.response.state = 'sending';
}
}
},
_responseReceived: (state, action) => {
const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
if(collection) {
const item = findItemInCollection(collection, action.payload.itemUid);
if(item) {
item.response = action.payload.response;
}
}
},
collectionClicked: (state, action) => {
const collection = findCollectionByUid(state.collections, action.payload);
@ -32,6 +54,8 @@ export const collectionsSlice = createSlice({
export const {
_loadCollections,
_createCollection,
_requestSent,
_responseReceived,
collectionClicked
} = collectionsSlice.actions;
@ -55,4 +79,18 @@ export const createCollection = (collectionName) => (dispatch) => {
.catch((err) => console.log(err));
};
export const sendRequest = (item, collectionUid) => (dispatch) => {
dispatch(_requestSent({
itemUid: item.uid,
collectionUid: collectionUid
}));
sendNetworkRequest(item)
.then((response) => dispatch(_responseReceived({
itemUid: item.uid,
collectionUid: collectionUid,
response: response
})))
.catch((err) => console.log(err));
};
export default collectionsSlice.reducer;

View File

@ -3,9 +3,6 @@ const SIDEBAR_COLLECTION_NEW_REQUEST = "SIDEBAR_COLLECTION_NEW_REQUEST";
const LOAD_COLLECTIONS_FROM_IDB = "LOAD_COLLECTIONS_FROM_IDB";
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_NEW_GQL_REQUEST = "ADD_NEW_GQL_REQUEST";
const IDB_CONNECTION_READY = "IDB_CONNECTION_READY";
const IDB_COLLECTIONS_SYNC_STARTED = "IDB_COLLECTIONS_SYNC_STARTED";
@ -18,9 +15,6 @@ export default {
LOAD_COLLECTIONS_FROM_IDB,
REQUEST_URL_CHANGED,
REQUEST_GQL_QUERY_CHANGED,
RESPONSE_RECEIVED,
SEND_REQUEST,
SENDING_REQUEST,
ADD_NEW_GQL_REQUEST,
IDB_CONNECTION_READY,
IDB_COLLECTIONS_SYNC_STARTED,

View File

@ -4,8 +4,6 @@ import reducer from './reducer';
import useIdb from './useIdb';
import useLoadCollectionsFromIdb from './useLoadCollectionsFromIdb';
import useSyncCollectionsToIdb from './useSyncCollectionsToIdb';
import { sendRequest } from '../../network';
export const StoreContext = createContext();
const collection = {
@ -116,7 +114,6 @@ const initialState = {
idbConnection: null,
collections: [],
activeRequestTabUid: null,
requestQueuedToSend: null,
requestTabs: [],
collectionsToSyncToIdb: []
};
@ -130,17 +127,6 @@ export const StoreProvider = props => {
collectionsToSyncToIdb
} = state;
useEffect(() => {
if(state.requestQueuedToSend) {
const {
request,
collectionUid
} = state.requestQueuedToSend;
sendRequest(request, collectionUid, dispatch)
}
}, [state.requestQueuedToSend]);
useIdb(dispatch);
useLoadCollectionsFromIdb(idbConnection, dispatch);
useSyncCollectionsToIdb(collectionsToSyncToIdb, collections, idbConnection, dispatch);

View File

@ -144,61 +144,6 @@ const reducer = (state, action) => {
});
}
case actions.SEND_REQUEST: {
return produce(state, (draft) => {
const collection = findCollectionByUid(draft.collections, action.collectionUid);
if(collection) {
let flattenedItems = flattenItems(collection.items);
let item = findItem(flattenedItems, action.requestTab.uid);
if(item) {
item.response = item.response || {};
item.response.state = 'queued';
draft.requestQueuedToSend = {
collectionUid: action.collectionUid,
request: item
}
}
}
});
}
case actions.SENDING_REQUEST: {
return produce(state, (draft) => {
const collection = findCollectionByUid(draft.collections, action.collectionUid);
console.log('collection');
console.log(collection);
if(collection) {
let flattenedItems = flattenItems(collection.items);
let item = findItem(flattenedItems, action.itemUid);
console.log('citemllection');
console.log(item);
if(item) {
item.response = item.response || {};
item.response.state = 'sending';
}
}
});
}
case actions.RESPONSE_RECEIVED: {
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.response = action.response;
}
}
});
}
case actions.HOTKEY_SAVE: {
return produce(state, (draft) => {
if(!draft.activeRequestTabUid) {

View File

@ -1,32 +0,0 @@
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 isItemARequest = (item) => {
return item.hasOwnProperty('request');
};
export const itemIsOpenedInTabs = (item, tabs) => {
return find(tabs, (t) => t.uid === item.uid);
};

View File

@ -0,0 +1,57 @@
import { rawRequest, gql } from 'graphql-request';
const sendNetworkRequest = async (item) => {
return new Promise((resolve, reject) => {
if(item.type === 'http-request') {
const timeStart = Date.now();
sendHttpRequest(item.request)
.then((response) => {
const timeEnd = Date.now();
resolve({
state: 'success',
data: response.data,
headers: Object.entries(response.headers),
size: response.headers["content-length"],
status: response.status,
duration: timeEnd - timeStart
});
})
.catch((err) => reject(err));
}
});
};
const sendHttpRequest = async (request) => {
return new Promise((resolve, reject) => {
const { ipcRenderer } = window.require("electron");
console.log(request);
let options = {
method: request.method,
url: request.url,
};
ipcRenderer
.invoke('send-http-request', options)
.then(resolve)
.catch(reject);
});
};
const sendGraphqlRequest = async (request,) => {
const query = gql`${request.request.body.graphql.query}`;
const { data, errors, extensions, headers, status } = await rawRequest(request.request.url, query);
return {
data,
headers,
data,
errors
}
};
export {
sendNetworkRequest
};