Skip to content

Commit

Permalink
Added search functonality to dashboard so user can search with Txn ha…
Browse files Browse the repository at this point in the history
…sh/Block no from there itself

Signed-off-by: saksham1203 <saksham.s1203@gmail.com>
  • Loading branch information
saksham1203 committed May 29, 2023
1 parent 2d6bb44 commit 3cfd1d3
Show file tree
Hide file tree
Showing 9 changed files with 292 additions and 2 deletions.
144 changes: 144 additions & 0 deletions client/src/components/Lists/SearchByQuery.js
@@ -0,0 +1,144 @@

import React, { useEffect, useState } from 'react'
import { txnListType } from '../types';
import { IconButton, TextField, Select, MenuItem, InputAdornment, makeStyles } from '@material-ui/core';
import SearchIcon from '@material-ui/icons/Search';
import { withRouter } from 'react-router-dom';
import Dialog from '@material-ui/core/Dialog';
import TransactionView from '../View/TransactionView';
import BlockView from '../View/BlockView';

const useStyles = makeStyles((theme) => ({
searchField: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
'& .MuiOutlinedInput-input': {
padding: '16px 14px'
}
},
searchInput: {
marginRight: theme.spacing(0),
'& > div': {
paddingRight: '24px !important',
}
},
iconButton: {
height: 40,
width: 40,
color: '#21295c',
backgroundColor: '#b9d6e1',
borderRadius: 15
}
}));


const SearchByQuery = (props) => {
let { txnList } = props;
let { blockSearch } = props;
const classes = useStyles();
const options = ["Txn Hash", "Block No"]
const [search, setSearch] = useState("")
const [selectedOption, setSelectedOption] = useState("Txn Hash")
const [dialogOpen, setDialogOpen] = useState(false)
const [error, setError] = useState(props.searchError)
const [searchClick, setSearchClick] = useState(false);

useEffect(() => {
if (props.searchError || searchClick) {
setSearchClick(false); setError(props.searchError) }
}, [props.searchError, searchClick])

const searchData = async () => {
if (selectedOption === "Txn Hash") {
await props.getTxnList(props.currentChannel, search)
} else if (selectedOption === "Block No") {
await props.getBlockSearch(props.currentChannel, search)
}
handleDialogOpen();
setSearchClick(true)
}

const handleSubmit = async (e) => {
e.preventDefault();
if (!search || (selectedOption === "Block No" && (isNaN(search) || search.length > 9))) {
setError("Please enter valid txn hash/block no")
return
}
searchData();

}

const handleDialogOpen = () => {
setDialogOpen(true)

}

const handleDialogClose = () => {
setDialogOpen(false)
}

return (
<div className={classes.searchField}>
<form onSubmit={handleSubmit}>
<Select
value={selectedOption}
onChange={(e) => { setSelectedOption(e.target.value); if (error) { setDialogOpen(false); setError('') } }}
className={classes.searchInput}
displayEmpty
variant='outlined'
style={{ width: 110 }}
MenuProps={{
anchorOrigin: {
vertical: "bottom",
horizontal: "left"
},
getContentAnchorEl: null
}}
>
{options.map((option) => (
<MenuItem key={option} value={option}>
{option}
</MenuItem>

))}
</Select>
<TextField
value={search}
onChange={(e) => { setSearch(e.target.value); if (error) { setDialogOpen(false); setError(''); } }}
onKeyPress={(e) => e.key === 'Enter' && handleSubmit(e)}
label=" Search by Txn Hash / Block"
variant='outlined'
style={{ width: 550 }}
error={error}
helperText={error}
InputProps={{
endAdornment: (
<InputAdornment position='end'>
<IconButton onClick={handleSubmit} className={classes.iconButton}>
<SearchIcon />
</IconButton>
</InputAdornment>
)
}}
/>
</form>
<Dialog
open={dialogOpen && !error}
onClose={handleDialogClose}
fullWidth
maxWidth="md"
>
{!error && selectedOption === 'Block No' ? <BlockView blockHash={blockSearch} onClose={handleDialogClose} />
: <TransactionView transaction={txnList} onClose={handleDialogClose} />
}
</Dialog>
</div>
)
}
SearchByQuery.propTypes = {
txnList: txnListType.isRequired
};


export default withRouter(SearchByQuery)
12 changes: 12 additions & 0 deletions client/src/components/Main.js
Expand Up @@ -22,6 +22,8 @@ import {
dashStatsType,
getTransactionType,
peerListType,
txnListType,
blockSearchType,
peerStatusType,
blockRangeSearchType,
blockListSearchType,
Expand All @@ -46,6 +48,8 @@ const {
chaincodeListSelector,
channelsSelector,
peerListSelector,
txnListSelector,
blockSearchSelector,
transactionSelector,
transactionListSelector,
blockRangeSearchSelector,
Expand Down Expand Up @@ -81,6 +85,8 @@ export const Main = props => {
dashStats,
getTransaction,
peerList,
txnList,
blockSearch,
peerStatus,
txnList,//s
transaction,
Expand Down Expand Up @@ -131,6 +137,8 @@ export const Main = props => {
blockListSearch,
dashStats,
peerStatus,
txnList,
blockSearch,
transactionByOrg,
blockActivity
};
Expand Down Expand Up @@ -242,6 +250,8 @@ Main.propTypes = {
dashStats: dashStatsType.isRequired,
getTransaction: getTransactionType.isRequired,
peerList: peerListType.isRequired,
txnList: txnListType.isRequired,
blockSearch: blockSearchType.isRequired,
peerStatus: peerStatusType.isRequired,
transaction: transactionType.isRequired,
transactionByOrg: transactionByOrgType.isRequired,
Expand All @@ -256,6 +266,8 @@ const connectedComponent = connect(
currentChannel: currentChannelSelector(state),
dashStats: dashStatsSelector(state),
peerList: peerListSelector(state),
txnList: txnListSelector(state),
blockSearch: blockSearchSelector(state),
peerStatus: peerStatusSelector(state),
transaction: transactionSelector(state),
transactionByOrg: transactionByOrgSelector(state),
Expand Down
45 changes: 43 additions & 2 deletions client/src/components/View/DashboardView.js
Expand Up @@ -16,8 +16,16 @@ import {
blockListSearchType,
dashStatsType,
peerStatusType,
txnListType,
blockSearchType,
transactionByOrgType
} from '../types';
import SearchByQuery from '../Lists/SearchByQuery';
import { connect } from 'react-redux';
import { currentChannelSelector } from '../../state/redux/charts/selectors';
import { tableOperations } from '../../state/redux/tables';

const {txnList, blockSearch} =tableOperations

/* istanbul ignore next */
const styles = theme => {
Expand All @@ -34,6 +42,13 @@ const styles = theme => {
marginLeft: '10%',
marginRight: '10%'
},
dashboardSearch:{
position: 'absolute',
width: '80%'
},
search :{
marginLeft:'10px'
},
blocks: {
height: 175,
marginBottom: 20,
Expand Down Expand Up @@ -155,8 +170,11 @@ export class DashboardView extends Component {
};

render() {
const { dashStats, peerStatus, blockActivity, transactionByOrg } = this.props;
const { dashStats, peerStatus, txnList, blockSearch, blockActivity, transactionByOrg } = this.props;
const { hasDbError, notifications } = this.state;
var searchError = ''
if(typeof txnList==='string'){searchError='Txn not found'; }
else if(typeof blockSearch==='string'){searchError='Block not found'}
if (hasDbError) {
return (
<div
Expand All @@ -177,6 +195,14 @@ export class DashboardView extends Component {
const { classes } = this.props;
return (
<div className={classes.background}>
<div className={classes.view}>
<div className={classes.dashboardSearch}>
<SearchByQuery getTxnList={this.props.getTxnList} getBlockSearch={this.props.getBlockSearch}
currentChannel={this.props.currentChannel}
txnList={txnList} blockSearch={blockSearch}
searchError={searchError} />
</div>
</div>
<div className={classes.view}>
<Row>
<Col sm="12">
Expand Down Expand Up @@ -269,7 +295,22 @@ DashboardView.propTypes = {
blockListSearch: blockListSearchType.isRequired,
dashStats: dashStatsType.isRequired,
peerStatus: peerStatusType.isRequired,
txnList: txnListType.isRequired,
blockSearch: blockSearchType.isRequired,
transactionByOrg: transactionByOrgType.isRequired
};

export default withStyles(styles)(DashboardView);
const mapStateToProps = state => {
return {
currentChannel: currentChannelSelector(state)
}
}
const mapDispatchToProps = {
getTxnList: txnList,
getBlockSearch: blockSearch
};
const connectedComponent = connect(
mapStateToProps,
mapDispatchToProps
)(DashboardView)
export default withStyles(styles)(connectedComponent);
6 changes: 6 additions & 0 deletions client/src/components/types/index.js
Expand Up @@ -118,6 +118,8 @@ export const getChannelListType = func;
export const getChannelsType = func;
export const getDashStatsType = func;
export const getPeerListType = func;
export const getTxnListType = func;
export const getBlockSearchType = func;
export const getPeerStatusType = func;
export const getTransactionInfoType = func;
export const getTransactionListType = func;
Expand Down Expand Up @@ -153,6 +155,10 @@ export const peerListType = arrayOf(
})
);

export const txnListType = any;

export const blockSearchType = any;

export const peerStatusType = arrayOf(
shape({
server_hostname: string,
Expand Down
12 changes: 12 additions & 0 deletions client/src/state/redux/tables/actions.js
Expand Up @@ -34,6 +34,16 @@ const getBlockRangeSearch = resp => ({
payload: resp.data
});

const getTxnList = resp => ({
type: types.TXN_LIST,
payload: resp.data,
});

const getBlockSearch = resp => ({
type: types.BLOCK_SEARCH,
payload: resp.data,
});

const getTransaction = transaction => ({
type: types.TRANSACTION,
payload: transaction,
Expand All @@ -53,6 +63,8 @@ export default {
getChannels,
getPeerList,
getBlockRangeSearch,
getTxnList,
getBlockSearch,
getTransaction,
getTransactionList,
getBlockListSearch,
Expand Down
42 changes: 42 additions & 0 deletions client/src/state/redux/tables/operations.js
Expand Up @@ -89,6 +89,46 @@ const peerList = channel => dispatch =>
console.error(error);
});

const txnList = (channel, query) => dispatch =>
get(`/api/fetchDataByTxnId/${channel}/${query}`)
.then(resp => {
if (resp.status === 500) {
dispatch(
actions.getErroMessage(
'500 Internal Server Error: The server has encountered an internal error and unable to complete your request'
)
);
} else if (resp.status === 400) {
dispatch(actions.getErroMessage(resp.error));
} else {
dispatch(actions.getTxnList(resp));
}
dispatch(actions.getBlockSearch({ data: {} }));
})
.catch(error => {
console.error(error);
});

const blockSearch = (channel, query) => dispatch =>
get(`/api/fetchDataByBlockNo/${channel}/${query}`)
.then(resp => {
if (resp.status === 500) {
dispatch(
actions.getErroMessage(
'500 Internal Server Error: The server has encountered an internal error and unable to complete your request'
)
);
} else if (resp.status === 400) {
dispatch(actions.getErroMessage(resp.error));
} else {
dispatch(actions.getBlockSearch(resp));
}
dispatch(actions.getTxnList({ data: {} }));
})
.catch(error => {
console.error(error);
});

/* istanbul ignore next */
const transaction = (channel, transactionId) => dispatch =>
get(`/api/transaction/${channel}/${transactionId}`)
Expand Down Expand Up @@ -163,6 +203,8 @@ export default {
chaincodeList,
channels,
peerList,
txnList,
blockSearch,
transaction,
transactionList,
transactionListSearch,
Expand Down

0 comments on commit 3cfd1d3

Please sign in to comment.