diff --git a/package.json b/package.json index 849a9f5..277fd8c 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "classnames": "^2.2.6", "connected-react-router": "^6.8.0", "dayjs": "^1.10.4", + "file-saver": "^2.0.5", "i18next": "^19.8.4", "i18next-browser-languagedetector": "^6.0.1", "i18next-http-backend": "^1.0.21", @@ -42,6 +43,7 @@ }, "devDependencies": { "@types/classnames": "^2.2.11", + "@types/file-saver": "^2.0.5", "@types/markdown-it": "^12.0.1", "@types/react-helmet": "^6.1.0", "@types/react-redux": "^7.1.12", diff --git a/src/modules/AddressTransactions/components/List/index.tsx b/src/modules/AddressTransactions/components/List/index.tsx index 62f74da..975bacc 100644 --- a/src/modules/AddressTransactions/components/List/index.tsx +++ b/src/modules/AddressTransactions/components/List/index.tsx @@ -8,13 +8,25 @@ import Pagination from '@/common/View/Pagination'; import Typography from '@material-ui/core/Typography'; import CenteredView from '@/common/View/CenteredView'; import { getNetwork } from '@/utils/helper'; +import FileSaver from 'file-saver'; +import { GetApp } from '@material-ui/icons'; +import Button from '@material-ui/core/Button'; import TransactionTable from '../Table'; + + const useStyles = () => createStyles({ pagerArea: { alignItems: 'center', display: 'flex', - justifyContent: 'flex-end', + justifyContent: 'space-between', + }, + csvExport: { + textAlign: 'left', + marginLeft: '12px' + }, + csvExportIcon: { + verticalAlign: 'middle', }, }); @@ -84,6 +96,44 @@ class Index extends PureComponent { window.history.replaceState(null, '', `/${getNetwork()}/address_transactions/${this.state.address}/${page}`); }; + csvExport = () => { + + const { addressTransactionList} = this.props; + const transactions = addressTransactionList && addressTransactionList.contents || []; + + const csvTitle = [ + 'block_hash', + 'block_number', + 'event_root_hash', + 'gas_used', + 'state_root_hash', + 'timestamp', + 'transaction_hash', + 'transaction_type' + ]; + + let csvData = ""; + let csvRow = "" + for (let index = 0; index < transactions.length; index++) { + const element = transactions[index]; + csvRow += `"${element.block_hash}",`; + csvRow += `"${element.block_number}",`; + csvRow += `"${element.event_root_hash}",`; + csvRow += `"${element.gas_used}",`; + csvRow += `"${element.state_root_hash}",`; + csvRow += `"${new Date(parseInt(element.timestamp, 10)).toLocaleString()} ${new Date().toTimeString().slice(9)}",`; + csvRow += `"${element.transaction_hash}",`; + csvRow += `"${element.transaction_type}"`; + + csvRow += `\r\n`; + } + + csvData = `${csvTitle}\r\n${csvRow}`; + const blob = new Blob([csvData], {type: "text/plain;charset=utf-8"}); + FileSaver.saveAs(blob, `${this.state.address}_${this.state.currentPage}.csv`); + + } + render() { const { addressTransactionList, isLoadingMore, className, classes, t } = this.props; const isInitialLoad = !addressTransactionList; @@ -116,7 +166,14 @@ class Index extends PureComponent { content={
{isInitialLoad ? : transactionsList} +
+
+ [ + ] +
wordBreak: 'break-all', overflow: 'auto', }, + csvExport: { + textAlign: 'end', + }, + csvExportIcon: { + verticalAlign: 'middle', + }, }); interface IndexState { @@ -358,9 +367,9 @@ class Index extends PureComponent { let args: any; let txn_type_args: any; let functionId: any; - let moduleAddress; - let moduleName; - let functionName; + let moduleAddress: any; + let moduleName: any; + let functionName: any; /* let arg0; let arg1; @@ -519,6 +528,68 @@ class Index extends PureComponent { columns.push([`${t('transaction.arg')} ${i+1}`, decodedArgs[i][1]]); } } + + const csvExport = () => { + + const savData = [ + [t('common.Hash'), source.transaction_hash], + [t('transaction.Type'), type], + [t('common.Time'),`${new Date(parseInt(source.timestamp, 10)).toLocaleString()} ${new Date().toTimeString().slice(9)}`], + [t('transaction.BlockHash'),source.block_hash], + [t('transaction.BlockHeight'),source.block_number], + [t('transaction.StateRootHash'), source.state_root_hash], + [t('transaction.Status'), source.status], + [t('common.GasUsed'), source.gas_used], + [t('transaction.Sender'), sender], + ]; + + if (moduleAddress) { + savData.push([t('transaction.FunctionModuleAddress'), moduleAddress]); + } + if (moduleName) { + savData.push([t('transaction.FunctionModuleName'), moduleName]); + } + if (functionName) { + savData.push([t('transaction.FunctionName'), functionName]); + } + if (txn_type_args) { + savData.push([t('transaction.TxnTypeArgs'), JSON.stringify(txn_type_args[0] || [])]); + } + + for (let i = 0; i < decodedArgs.length; i++) { + if (decodedArgs[i][0] === 'address') { + const address = decodedArgs[i][1]; + savData.push([`${t('transaction.arg')} ${i+1}`,address]); + } else { + savData.push([`${t('transaction.arg')} ${i+1}`, decodedArgs[i][1]]); + } + } + + let csvData = ""; + let csvTitle = ""; + let csvRow = "" + for (let index = 0; index < savData.length; index++) { + const element = savData[index]; + csvTitle += `"${element[0]}",`; + csvRow += `"${element[1]}",`; + } + csvData = `${csvTitle}\r\n${csvRow}`; + const blob = new Blob([csvData], {type: "text/plain;charset=utf-8"}); + FileSaver.saveAs(blob, `${source.transaction_hash}.csv`); + + } + + columns.push([ + ``, +
+ [ + ] +
+ ]); + + /* if (arg0) { columns.push([ diff --git a/yarn.lock b/yarn.lock index 3ff1bf3..1c42389 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2036,6 +2036,11 @@ resolved "https://registry.npm.taobao.org/@types/estree/download/@types/estree-0.0.39.tgz?cache=0&sync_timestamp=1605053042114&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Festree%2Fdownload%2F%40types%2Festree-0.0.39.tgz" integrity sha1-4Xfmme4bjCLSMXTKqnQiZEOJUJ8= +"@types/file-saver@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@types/file-saver/-/file-saver-2.0.5.tgz#9ee342a5d1314bb0928375424a2f162f97c310c7" + integrity sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ== + "@types/glob@^7.1.1": version "7.1.3" resolved "https://registry.npm.taobao.org/@types/glob/download/@types/glob-7.1.3.tgz" @@ -5640,6 +5645,11 @@ file-loader@6.1.1: loader-utils "^2.0.0" schema-utils "^3.0.0" +file-saver@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-2.0.5.tgz#d61cfe2ce059f414d899e9dd6d4107ee25670c38" + integrity sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA== + file-uri-to-path@1.0.0: version "1.0.0" resolved "https://registry.npm.taobao.org/file-uri-to-path/download/file-uri-to-path-1.0.0.tgz"