Skip to content

Commit 3cfd1d3

Browse files
committed
Added search functonality to dashboard so user can search with Txn hash/Block no from there itself
Signed-off-by: saksham1203 <[email protected]>
1 parent 2d6bb44 commit 3cfd1d3

File tree

9 files changed

+292
-2
lines changed

9 files changed

+292
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
2+
import React, { useEffect, useState } from 'react'
3+
import { txnListType } from '../types';
4+
import { IconButton, TextField, Select, MenuItem, InputAdornment, makeStyles } from '@material-ui/core';
5+
import SearchIcon from '@material-ui/icons/Search';
6+
import { withRouter } from 'react-router-dom';
7+
import Dialog from '@material-ui/core/Dialog';
8+
import TransactionView from '../View/TransactionView';
9+
import BlockView from '../View/BlockView';
10+
11+
const useStyles = makeStyles((theme) => ({
12+
searchField: {
13+
display: 'flex',
14+
alignItems: 'center',
15+
justifyContent: 'center',
16+
'& .MuiOutlinedInput-input': {
17+
padding: '16px 14px'
18+
}
19+
},
20+
searchInput: {
21+
marginRight: theme.spacing(0),
22+
'& > div': {
23+
paddingRight: '24px !important',
24+
}
25+
},
26+
iconButton: {
27+
height: 40,
28+
width: 40,
29+
color: '#21295c',
30+
backgroundColor: '#b9d6e1',
31+
borderRadius: 15
32+
}
33+
}));
34+
35+
36+
const SearchByQuery = (props) => {
37+
let { txnList } = props;
38+
let { blockSearch } = props;
39+
const classes = useStyles();
40+
const options = ["Txn Hash", "Block No"]
41+
const [search, setSearch] = useState("")
42+
const [selectedOption, setSelectedOption] = useState("Txn Hash")
43+
const [dialogOpen, setDialogOpen] = useState(false)
44+
const [error, setError] = useState(props.searchError)
45+
const [searchClick, setSearchClick] = useState(false);
46+
47+
useEffect(() => {
48+
if (props.searchError || searchClick) {
49+
setSearchClick(false); setError(props.searchError) }
50+
}, [props.searchError, searchClick])
51+
52+
const searchData = async () => {
53+
if (selectedOption === "Txn Hash") {
54+
await props.getTxnList(props.currentChannel, search)
55+
} else if (selectedOption === "Block No") {
56+
await props.getBlockSearch(props.currentChannel, search)
57+
}
58+
handleDialogOpen();
59+
setSearchClick(true)
60+
}
61+
62+
const handleSubmit = async (e) => {
63+
e.preventDefault();
64+
if (!search || (selectedOption === "Block No" && (isNaN(search) || search.length > 9))) {
65+
setError("Please enter valid txn hash/block no")
66+
return
67+
}
68+
searchData();
69+
70+
}
71+
72+
const handleDialogOpen = () => {
73+
setDialogOpen(true)
74+
75+
}
76+
77+
const handleDialogClose = () => {
78+
setDialogOpen(false)
79+
}
80+
81+
return (
82+
<div className={classes.searchField}>
83+
<form onSubmit={handleSubmit}>
84+
<Select
85+
value={selectedOption}
86+
onChange={(e) => { setSelectedOption(e.target.value); if (error) { setDialogOpen(false); setError('') } }}
87+
className={classes.searchInput}
88+
displayEmpty
89+
variant='outlined'
90+
style={{ width: 110 }}
91+
MenuProps={{
92+
anchorOrigin: {
93+
vertical: "bottom",
94+
horizontal: "left"
95+
},
96+
getContentAnchorEl: null
97+
}}
98+
>
99+
{options.map((option) => (
100+
<MenuItem key={option} value={option}>
101+
{option}
102+
</MenuItem>
103+
104+
))}
105+
</Select>
106+
<TextField
107+
value={search}
108+
onChange={(e) => { setSearch(e.target.value); if (error) { setDialogOpen(false); setError(''); } }}
109+
onKeyPress={(e) => e.key === 'Enter' && handleSubmit(e)}
110+
label=" Search by Txn Hash / Block"
111+
variant='outlined'
112+
style={{ width: 550 }}
113+
error={error}
114+
helperText={error}
115+
InputProps={{
116+
endAdornment: (
117+
<InputAdornment position='end'>
118+
<IconButton onClick={handleSubmit} className={classes.iconButton}>
119+
<SearchIcon />
120+
</IconButton>
121+
</InputAdornment>
122+
)
123+
}}
124+
/>
125+
</form>
126+
<Dialog
127+
open={dialogOpen && !error}
128+
onClose={handleDialogClose}
129+
fullWidth
130+
maxWidth="md"
131+
>
132+
{!error && selectedOption === 'Block No' ? <BlockView blockHash={blockSearch} onClose={handleDialogClose} />
133+
: <TransactionView transaction={txnList} onClose={handleDialogClose} />
134+
}
135+
</Dialog>
136+
</div>
137+
)
138+
}
139+
SearchByQuery.propTypes = {
140+
txnList: txnListType.isRequired
141+
};
142+
143+
144+
export default withRouter(SearchByQuery)

client/src/components/Main.js

+12
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import {
2222
dashStatsType,
2323
getTransactionType,
2424
peerListType,
25+
txnListType,
26+
blockSearchType,
2527
peerStatusType,
2628
blockRangeSearchType,
2729
blockListSearchType,
@@ -46,6 +48,8 @@ const {
4648
chaincodeListSelector,
4749
channelsSelector,
4850
peerListSelector,
51+
txnListSelector,
52+
blockSearchSelector,
4953
transactionSelector,
5054
transactionListSelector,
5155
blockRangeSearchSelector,
@@ -81,6 +85,8 @@ export const Main = props => {
8185
dashStats,
8286
getTransaction,
8387
peerList,
88+
txnList,
89+
blockSearch,
8490
peerStatus,
8591
txnList,//s
8692
transaction,
@@ -131,6 +137,8 @@ export const Main = props => {
131137
blockListSearch,
132138
dashStats,
133139
peerStatus,
140+
txnList,
141+
blockSearch,
134142
transactionByOrg,
135143
blockActivity
136144
};
@@ -242,6 +250,8 @@ Main.propTypes = {
242250
dashStats: dashStatsType.isRequired,
243251
getTransaction: getTransactionType.isRequired,
244252
peerList: peerListType.isRequired,
253+
txnList: txnListType.isRequired,
254+
blockSearch: blockSearchType.isRequired,
245255
peerStatus: peerStatusType.isRequired,
246256
transaction: transactionType.isRequired,
247257
transactionByOrg: transactionByOrgType.isRequired,
@@ -256,6 +266,8 @@ const connectedComponent = connect(
256266
currentChannel: currentChannelSelector(state),
257267
dashStats: dashStatsSelector(state),
258268
peerList: peerListSelector(state),
269+
txnList: txnListSelector(state),
270+
blockSearch: blockSearchSelector(state),
259271
peerStatus: peerStatusSelector(state),
260272
transaction: transactionSelector(state),
261273
transactionByOrg: transactionByOrgSelector(state),

client/src/components/View/DashboardView.js

+43-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,16 @@ import {
1616
blockListSearchType,
1717
dashStatsType,
1818
peerStatusType,
19+
txnListType,
20+
blockSearchType,
1921
transactionByOrgType
2022
} from '../types';
23+
import SearchByQuery from '../Lists/SearchByQuery';
24+
import { connect } from 'react-redux';
25+
import { currentChannelSelector } from '../../state/redux/charts/selectors';
26+
import { tableOperations } from '../../state/redux/tables';
27+
28+
const {txnList, blockSearch} =tableOperations
2129

2230
/* istanbul ignore next */
2331
const styles = theme => {
@@ -34,6 +42,13 @@ const styles = theme => {
3442
marginLeft: '10%',
3543
marginRight: '10%'
3644
},
45+
dashboardSearch:{
46+
position: 'absolute',
47+
width: '80%'
48+
},
49+
search :{
50+
marginLeft:'10px'
51+
},
3752
blocks: {
3853
height: 175,
3954
marginBottom: 20,
@@ -155,8 +170,11 @@ export class DashboardView extends Component {
155170
};
156171

157172
render() {
158-
const { dashStats, peerStatus, blockActivity, transactionByOrg } = this.props;
173+
const { dashStats, peerStatus, txnList, blockSearch, blockActivity, transactionByOrg } = this.props;
159174
const { hasDbError, notifications } = this.state;
175+
var searchError = ''
176+
if(typeof txnList==='string'){searchError='Txn not found'; }
177+
else if(typeof blockSearch==='string'){searchError='Block not found'}
160178
if (hasDbError) {
161179
return (
162180
<div
@@ -177,6 +195,14 @@ export class DashboardView extends Component {
177195
const { classes } = this.props;
178196
return (
179197
<div className={classes.background}>
198+
<div className={classes.view}>
199+
<div className={classes.dashboardSearch}>
200+
<SearchByQuery getTxnList={this.props.getTxnList} getBlockSearch={this.props.getBlockSearch}
201+
currentChannel={this.props.currentChannel}
202+
txnList={txnList} blockSearch={blockSearch}
203+
searchError={searchError} />
204+
</div>
205+
</div>
180206
<div className={classes.view}>
181207
<Row>
182208
<Col sm="12">
@@ -269,7 +295,22 @@ DashboardView.propTypes = {
269295
blockListSearch: blockListSearchType.isRequired,
270296
dashStats: dashStatsType.isRequired,
271297
peerStatus: peerStatusType.isRequired,
298+
txnList: txnListType.isRequired,
299+
blockSearch: blockSearchType.isRequired,
272300
transactionByOrg: transactionByOrgType.isRequired
273301
};
274302

275-
export default withStyles(styles)(DashboardView);
303+
const mapStateToProps = state => {
304+
return {
305+
currentChannel: currentChannelSelector(state)
306+
}
307+
}
308+
const mapDispatchToProps = {
309+
getTxnList: txnList,
310+
getBlockSearch: blockSearch
311+
};
312+
const connectedComponent = connect(
313+
mapStateToProps,
314+
mapDispatchToProps
315+
)(DashboardView)
316+
export default withStyles(styles)(connectedComponent);

client/src/components/types/index.js

+6
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ export const getChannelListType = func;
118118
export const getChannelsType = func;
119119
export const getDashStatsType = func;
120120
export const getPeerListType = func;
121+
export const getTxnListType = func;
122+
export const getBlockSearchType = func;
121123
export const getPeerStatusType = func;
122124
export const getTransactionInfoType = func;
123125
export const getTransactionListType = func;
@@ -153,6 +155,10 @@ export const peerListType = arrayOf(
153155
})
154156
);
155157

158+
export const txnListType = any;
159+
160+
export const blockSearchType = any;
161+
156162
export const peerStatusType = arrayOf(
157163
shape({
158164
server_hostname: string,

client/src/state/redux/tables/actions.js

+12
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ const getBlockRangeSearch = resp => ({
3434
payload: resp.data
3535
});
3636

37+
const getTxnList = resp => ({
38+
type: types.TXN_LIST,
39+
payload: resp.data,
40+
});
41+
42+
const getBlockSearch = resp => ({
43+
type: types.BLOCK_SEARCH,
44+
payload: resp.data,
45+
});
46+
3747
const getTransaction = transaction => ({
3848
type: types.TRANSACTION,
3949
payload: transaction,
@@ -53,6 +63,8 @@ export default {
5363
getChannels,
5464
getPeerList,
5565
getBlockRangeSearch,
66+
getTxnList,
67+
getBlockSearch,
5668
getTransaction,
5769
getTransactionList,
5870
getBlockListSearch,

client/src/state/redux/tables/operations.js

+42
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,46 @@ const peerList = channel => dispatch =>
8989
console.error(error);
9090
});
9191

92+
const txnList = (channel, query) => dispatch =>
93+
get(`/api/fetchDataByTxnId/${channel}/${query}`)
94+
.then(resp => {
95+
if (resp.status === 500) {
96+
dispatch(
97+
actions.getErroMessage(
98+
'500 Internal Server Error: The server has encountered an internal error and unable to complete your request'
99+
)
100+
);
101+
} else if (resp.status === 400) {
102+
dispatch(actions.getErroMessage(resp.error));
103+
} else {
104+
dispatch(actions.getTxnList(resp));
105+
}
106+
dispatch(actions.getBlockSearch({ data: {} }));
107+
})
108+
.catch(error => {
109+
console.error(error);
110+
});
111+
112+
const blockSearch = (channel, query) => dispatch =>
113+
get(`/api/fetchDataByBlockNo/${channel}/${query}`)
114+
.then(resp => {
115+
if (resp.status === 500) {
116+
dispatch(
117+
actions.getErroMessage(
118+
'500 Internal Server Error: The server has encountered an internal error and unable to complete your request'
119+
)
120+
);
121+
} else if (resp.status === 400) {
122+
dispatch(actions.getErroMessage(resp.error));
123+
} else {
124+
dispatch(actions.getBlockSearch(resp));
125+
}
126+
dispatch(actions.getTxnList({ data: {} }));
127+
})
128+
.catch(error => {
129+
console.error(error);
130+
});
131+
92132
/* istanbul ignore next */
93133
const transaction = (channel, transactionId) => dispatch =>
94134
get(`/api/transaction/${channel}/${transactionId}`)
@@ -163,6 +203,8 @@ export default {
163203
chaincodeList,
164204
channels,
165205
peerList,
206+
txnList,
207+
blockSearch,
166208
transaction,
167209
transactionList,
168210
transactionListSearch,

0 commit comments

Comments
 (0)