Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ REACT_APP_LOCAL_SERVICE_PORT=8081
REACT_APP_APP_SERVE_PORT=5111

REACT_APP_POLLING_INTERVAL_TIME=500
REACT_APP_API_TIMEOUT_TIME=5000
REACT_APP_AUTO_RELOAD_INTERVAL_TIME=10000
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import { combineReducers } from 'redux';
import { of, from } from 'rxjs';
import { of } from 'rxjs';
import { mergeMap, map, mapTo, filter, catchError } from 'rxjs/operators';

import { combineEpics, ofType } from 'redux-observable';
Expand Down Expand Up @@ -43,7 +43,7 @@ const fetchEpic = ( action$, state$ ) => action$.pipe(
mergeMap(action =>{
let { value: { accountdetailPage: { accountdetail: { params } }}} = state$;

return from(apiRpc("get_account_details", params)).pipe(
return apiRpc("get_account_details", params).pipe(
map(res => fetchFulfilled(res)),
catchError(error => {
errorLog("Accounts page/ get account detail error ", error);
Expand All @@ -69,7 +69,7 @@ const fetchContractEpic = ( action$, state$ ) => action$.pipe(
errorLog("Accounts page/ get abi error ", error);
return of(fetchContractRejected(error.response, { status: error.status }))
})
)
)
})
);

Expand Down
27 changes: 13 additions & 14 deletions src/pages/ActionlistPage/components/Actionlist/Actionlist.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { connect } from 'react-redux';
import { Row, Col, CardTitle, Form } from 'reactstrap';
import styled from 'styled-components';
import { push } from 'connected-react-router'
import { pollingStart, pollingStop, smartContractNameSearch, recordsUpdate } from './ActionlistReducer';
import { fetchStart, smartContractNameSearch, recordsUpdate } from './ActionlistReducer';
import { LoadingSpinner, LimitSelectDropdown } from 'components';
import isObjectEmpty from 'helpers/is-object-empty';
import { TableStyled, ButtonPrimary, InputStyled, ErrorButton } from 'styled';
Expand All @@ -21,19 +21,19 @@ const FilterInputStyled = styled(InputStyled)`
const Actionlist = (props) => {

useEffect(()=>{
props.pollingStart();
return () => { props.pollingStop() }
props.fetchStart();
return () => { }
}, [])

const [inputValue, setInputValue] = useState("");
let { actionlist: { isFetching, data, smartContractName, records } } = props;
let { payload = [], error } = data;

return (
<div className="Actionlist">
<Row>
<Col xs="12" className="text-right">
<CardTitle>
<CardTitle>
<FormStyled onSubmit={(e) => {
e.preventDefault();
if(smartContractName) {
Expand All @@ -46,10 +46,10 @@ const Actionlist = (props) => {
}
}}>
<FilterInputStyled
disabled={!!smartContractName}
name="smartContractNameSearch"
placeholder="Smart Contract Name..."
defaultValue={smartContractName}
disabled={!!smartContractName}
name="smartContractNameSearch"
placeholder="Smart Contract Name..."
defaultValue={smartContractName}
onChange={evt=>{setInputValue(evt.target.value)}}/>
<ButtonPrimary color="primary">{smartContractName ? "CLEAR" : "FILTER"}</ButtonPrimary>
</FormStyled>
Expand All @@ -58,10 +58,10 @@ const Actionlist = (props) => {
</Row>
<Row>
<Col xs="12">
{ error ?
{ error ?
<>
{!isObjectEmpty(error) && <p className="text-danger">{JSON.stringify(error)}</p>}
<ErrorButton onClick={props.pollingStart}>Connection error, click to reload</ErrorButton>
<ErrorButton onClick={props.fetchStart}>Connection error, click to reload</ErrorButton>
</>
: isFetching ? (
<LoadingSpinner />
Expand All @@ -77,7 +77,7 @@ const Actionlist = (props) => {
</tr>
</thead>
<tbody className="hashText">
{payload.length < 1
{payload.length < 1
? <tr><td colSpan="3" className="text-center">No actions found for the Smart Contract Name</td></tr>
: payload.map((action, index)=>
<tr onClick={evt=>props.push(`/action/${action.block_num}/${action.receipt.global_sequence}`)} key={index}>
Expand Down Expand Up @@ -106,8 +106,7 @@ export default connect(
actionlist
}),
{
pollingStart,
pollingStop,
fetchStart,
smartContractNameSearch,
recordsUpdate,
push
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,17 @@ const actionPrefix = `ActionlistPage/Actionlist/`;
const FETCH_START = actionPrefix + `FETCH_START`;
const FETCH_FULFILLED = actionPrefix + `FETCH_FULFILLED`;
const FETCH_REJECTED = actionPrefix + `FETCH_REJECTED`;
const POLLING_START = actionPrefix + `POLLING_START`;
const POLLING_STOP = actionPrefix + `POLLING_STOP`;
const SMART_CONTRACT_NAME_UPDATE = actionPrefix + `SMART_CONTRACT_NAME_UPDATE`;
const RECORDS_UPDATE = actionPrefix + `RECORDS_UPDATE`;

//Action Creator
export const fetchStart = () => ({ type: FETCH_START });
export const fetchFulfilled = payload => ({ type: FETCH_FULFILLED, payload });
export const fetchRejected = ( payload, error ) => ({ type: FETCH_REJECTED, payload, error });
export const pollingStart = () => ({ type: POLLING_START });
export const pollingStop = () => ({ type: POLLING_STOP });
export const smartContractNameSearch = (name) => ({ type: SMART_CONTRACT_NAME_UPDATE , smartContractName: name});
export const recordsUpdate = (count) => ({ type: RECORDS_UPDATE, recordsCount: count });

//Epic
const startEpic = action$ => action$.pipe(
ofType(POLLING_START),
mapTo(fetchStart()),
);

const fetchEpic = ( action$, state$ ) => action$.pipe(
ofType(FETCH_START),
mergeMap(action => {
Expand All @@ -64,16 +55,15 @@ const fetchEpic = ( action$, state$ ) => action$.pipe(

const smartContractNameToggleEpic = action$ => action$.pipe(
ofType(SMART_CONTRACT_NAME_UPDATE),
mapTo(pollingStart()),
mapTo(fetchStart()),
);

const recordsUpdateEpic = action$ => action$.pipe(
ofType(RECORDS_UPDATE),
mapTo(pollingStart()),
mapTo(fetchStart()),
);

export const combinedEpic = combineEpics(
startEpic,
fetchEpic,
smartContractNameToggleEpic,
recordsUpdateEpic
Expand Down
16 changes: 8 additions & 8 deletions src/pages/BlocklistPage/components/Blocklist/Blocklist.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ const Blocklist = (props) => {

const [inputValue, setInputValue] = useState("");

let { blocklist: { isFetching, data, filter, records } } = props;
let { blocklist: { isPolling, data, filter, records } } = props;
let { payload = [], error } = data;

return (
<div className="Blocklist">
<FirstCardStyled>
Expand All @@ -58,16 +58,16 @@ const Blocklist = (props) => {
evt => {
if (evt.key === 'Enter') {
setInputValue("");
if(inputValue !== "")
props.push('/block/'+inputValue)
if(inputValue !== "")
props.push('/block/'+inputValue)
}
}
}
onChange={evt=>{setInputValue(evt.target.value)}}/>
<ButtonPrimary
onClick={evt=> {
setInputValue("");
if(inputValue !== "")
if(inputValue !== "")
props.push('/block/'+inputValue)
}}>
SEARCH</ButtonPrimary>
Expand All @@ -76,12 +76,12 @@ const Blocklist = (props) => {
</Row>
<div>
{ error
?
?
<>
{!isObjectEmpty(error) && <p className="text-danger">{JSON.stringify(error)}</p>}
<ErrorButton onClick={props.pollingStart}>Connection error, click to reload</ErrorButton>
</>
:
:
<Row>
<Col xs="12">
<TableStyled borderless>
Expand All @@ -94,7 +94,7 @@ const Blocklist = (props) => {
</tr>
</thead>
<tbody className="hashText">
{(isFetching || payload.length <= 0) ? (
{(isPolling || payload.length <= 0) ? (
<tr><td colSpan="4" className="text-center"><LoadingSpinner /></td></tr>
) : payload.map(eachBlock=>
<tr onClick={evt=>props.push(`/block/${eachBlock.block_id}`)} key={eachBlock.block_id}>
Expand Down
82 changes: 53 additions & 29 deletions src/pages/BlocklistPage/components/Blocklist/BlocklistReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@
*/

import { combineReducers } from 'redux';
import { interval, of } from 'rxjs';
import { mergeMap, mapTo, map, takeUntil, catchError, delay, startWith } from 'rxjs/operators';

import { interval, of, empty } from 'rxjs';
import { switchMap, mergeMap, mapTo, map, takeUntil, catchError, delay, startWith, finalize } from 'rxjs/operators';
import { combineEpics, ofType } from 'redux-observable';
import store from 'store';

import apiMongodb from 'services/api-mongodb';
import { errorLog } from 'helpers/error-logger';
import paramsToQuery from 'helpers/params-to-query';


// IMPORTANT
// Must modify action prefix since action types must be unique in the whole app
const actionPrefix = `BlocklistPage/Blocklist/`;
Expand All @@ -22,6 +23,7 @@ const actionPrefix = `BlocklistPage/Blocklist/`;
const FETCH_START = actionPrefix + `FETCH_START`;
const FETCH_FULFILLED = actionPrefix + `FETCH_FULFILLED`;
const FETCH_REJECTED = actionPrefix + `FETCH_REJECTED`;
const FETCH_END = actionPrefix + `FETCH_END`;
const POLLING_START = actionPrefix + `POLLING_START`;
const POLLING_STOP = actionPrefix + `POLLING_STOP`;
const FILTER_SET = actionPrefix + `FILTER_SET`;
Expand All @@ -30,50 +32,52 @@ const RECORDS_UPDATE = actionPrefix + `RECORDS_UPDATE`;

//Action Creator
export const fetchStart = () => ({ type: FETCH_START });
export const fetchFulfilled = payload => ({ type: FETCH_FULFILLED, payload });
export const fetchFulfilled = (payload) => ({ type: FETCH_FULFILLED, payload });
export const fetchRejected = ( payload, error ) => ({ type: FETCH_REJECTED, payload, error });
export const pollingStart = () => ({ type: POLLING_START });
export const fetchEnd = ( ) => ({ type: FETCH_END });
export const pollingStart = (autoReload) => ({ type: POLLING_START, autoReload });
export const pollingStop = () => ({ type: POLLING_STOP });
export const filterSet = (enabled) => ({ type: FILTER_SET, enabled});
export const filterToggle = () => ({ type: FILTER_TOGGLE });
export const recordsUpdate = (count) => ({ type: RECORDS_UPDATE, recordsCount: count });

//Epic
const startEpic = action$ => action$.pipe(
ofType(POLLING_START),
mapTo(fetchStart()),
);

const fetchEpic = ( action$, state$ ) => action$.pipe(
const pollingEpic = ( action$, state$ ) => action$.pipe(
ofType(POLLING_START),
mergeMap(action =>
switchMap(action =>
interval(process.env.REACT_APP_POLLING_INTERVAL_TIME).pipe(
startWith(0),
mergeMap(action => {
let { value: { blocklistPage: { blocklist: { filter, records } } }} = state$;
startWith(-1),
mergeMap(index => {
let { value: { blocklistPage: { blocklist: { isFetching, filter, records } } }} = state$;
// let { value: { actionlistPage: { actionlist: { smartContractName, records } }} } = state$;
let params = { records_count: records, show_empty: !filter };
let query = paramsToQuery(params);

return apiMongodb(`get_blocks${query}`).pipe(
map(res => fetchFulfilled(res.response)),

return isFetching ? empty() : apiMongodb(`get_blocks${query}`).pipe(
startWith("fetchStart"),
map(res => { return res === "fetchStart" ? fetchStart() : fetchFulfilled(res.response)}),
catchError(error => {
errorLog("Blocks page/ get block list error",error);
return of(fetchRejected(error.response, { status: error.status }))
})
)
}),
takeUntil(action$.pipe(
ofType(POLLING_STOP, POLLING_START, FETCH_REJECTED)
))
ofType(POLLING_STOP, POLLING_START, FETCH_REJECTED),
)),

finalize(() => {
store.dispatch(fetchEnd());
})
)
),
);

const repollEpic = action$ => action$.pipe(
const autoReloadEpic = action$ => action$.pipe(
ofType(FETCH_REJECTED),
delay(10000),
mapTo(pollingStart()),
delay(process.env.REACT_APP_AUTO_RELOAD_INTERVAL_TIME),
mapTo(pollingStart(true)),
);

const filterToggleEpic = action$ => action$.pipe(
Expand All @@ -88,9 +92,8 @@ const recordsUpdateEpic = action$ => action$.pipe(


export const combinedEpic = combineEpics(
startEpic,
fetchEpic,
repollEpic,
pollingEpic,
autoReloadEpic,
filterToggleEpic,
recordsUpdateEpic
);
Expand All @@ -104,8 +107,10 @@ const dataInitState = {

const dataReducer = (state=dataInitState, action) => {
switch (action.type) {
case FETCH_START:
return dataInitState;
case POLLING_START:

//If this is a polling started from the auto reload, do not reinit the state.
return !action.autoReload ? dataInitState : state;

case FETCH_FULFILLED:
return {
Expand All @@ -117,8 +122,9 @@ const dataReducer = (state=dataInitState, action) => {
case FETCH_REJECTED:
return {
...state,
payload: action.payload,
error: action.error

//If current payload is having previous data, do not show the error
error: state.payload.length > 0 ? undefined : action.error
};

case RECORDS_UPDATE:
Expand All @@ -136,6 +142,23 @@ const isFetchingReducer = (state = false, action) => {
case FETCH_START:
return true;

case FETCH_FULFILLED:
case FETCH_REJECTED:
case FETCH_END:
return false;

default:
return state;
}
};

const isPollingReducer = (state = false, action) => {
switch (action.type) {
case POLLING_START:

//If this is a polling started from the auto reload, keep the flag false.
return !action.autoReload;

case FETCH_FULFILLED:
case FETCH_REJECTED:
return false;
Expand Down Expand Up @@ -171,6 +194,7 @@ const recordsReducer = (state = 100, action) => {
export const combinedReducer = combineReducers({
data: dataReducer,
isFetching: isFetchingReducer,
isPolling: isPollingReducer,
filter: filterReducer,
records: recordsReducer
})
Loading