diff --git a/CHANGELOG.md b/CHANGELOG.md index bba5170e0b..ecd8e613a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,15 @@ - [#2151](https://github.com/poanetwork/blockscout/pull/2151) - hide dropdown menu then other networks list is empty - [#2191](https://github.com/poanetwork/blockscout/pull/2191) - allow to configure token metadata update interval - [#2146](https://github.com/poanetwork/blockscout/pull/2146) - feat: add eth_getLogs rpc endpoint +- [#2190](https://github.com/poanetwork/blockscout/pull/2190) - show all token transfers - [#2193](https://github.com/poanetwork/blockscout/pull/2193) - feat: add BLOCKSCOUT_HOST, and use it in API docs ### Fixes +- [#2263](https://github.com/poanetwork/blockscout/pull/2263) - added an ability to close network selector on outside click +- [#2257](https://github.com/poanetwork/blockscout/pull/2257) - 'download csv' button added to different tabs +- [#2242](https://github.com/poanetwork/blockscout/pull/2242) - added styles for 'download csv' button +- [#2261](https://github.com/poanetwork/blockscout/pull/2261) - header logo aligned to the center properly +- [#2254](https://github.com/poanetwork/blockscout/pull/2254) - search length issue, tile link wrapping issue - [#2238](https://github.com/poanetwork/blockscout/pull/2238) - header content alignment issue, hide navbar on outside click - [#2229](https://github.com/poanetwork/blockscout/pull/2229) - gap issue between qr and copy button in token transfers, top cards width and height issue - [#2201](https://github.com/poanetwork/blockscout/pull/2201) - footer columns fix @@ -53,12 +59,14 @@ ### Chore - [#2127](https://github.com/poanetwork/blockscout/pull/2127) - use previouse chromedriver version - [#2118](https://github.com/poanetwork/blockscout/pull/2118) - show only the last decompiled contract +- [#2256](https://github.com/poanetwork/blockscout/pull/2256) - use the latest version of chromedriver ### Chore ## 2.0.0-beta ### Features +- [#2044](https://github.com/poanetwork/blockscout/pull/2044) - New network selector. - [#2091](https://github.com/poanetwork/blockscout/pull/2091) - Added "Question" modal. - [#1963](https://github.com/poanetwork/blockscout/pull/1963), [#1959](https://github.com/poanetwork/blockscout/pull/1959), [#1948](https://github.com/poanetwork/blockscout/pull/1948), [#1936](https://github.com/poanetwork/blockscout/pull/1936), [#1925](https://github.com/poanetwork/blockscout/pull/1925), [#1922](https://github.com/poanetwork/blockscout/pull/1922), [#1903](https://github.com/poanetwork/blockscout/pull/1903), [#1874](https://github.com/poanetwork/blockscout/pull/1874), [#1895](https://github.com/poanetwork/blockscout/pull/1895), [#2031](https://github.com/poanetwork/blockscout/pull/2031), [#2073](https://github.com/poanetwork/blockscout/pull/2073), [#2074](https://github.com/poanetwork/blockscout/pull/2074), - added new themes and logos for poa, eth, rinkeby, goerli, ropsten, kovan, sokol, xdai, etc, rsk and default theme - [#1726](https://github.com/poanetwork/blockscout/pull/2071) - Updated styles for the new smart contract page. @@ -84,6 +92,9 @@ - [#2100](https://github.com/poanetwork/blockscout/pull/2100) - feat: eth_get_balance rpc endpoint ### Fixes +- [#2228](https://github.com/poanetwork/blockscout/pull/2228) - favorites duplication issues, active radio issue +- [#2207](https://github.com/poanetwork/blockscout/pull/2207) - new 'download csv' button design +- [#2206](https://github.com/poanetwork/blockscout/pull/2206) - added styles for 'Download All Transactions as CSV' button - [#2099](https://github.com/poanetwork/blockscout/pull/2099) - logs search input width - [#2098](https://github.com/poanetwork/blockscout/pull/2098) - nav dropdown issue, logo size issue - [#2082](https://github.com/poanetwork/blockscout/pull/2082) - dropdown styles, tooltip gap fix, 404 page added diff --git a/apps/block_scout_web/assets/css/app.scss b/apps/block_scout_web/assets/css/app.scss index aaa234a5b3..cf79ee46e8 100644 --- a/apps/block_scout_web/assets/css/app.scss +++ b/apps/block_scout_web/assets/css/app.scss @@ -123,8 +123,8 @@ $fa-font-path: "~@fortawesome/fontawesome-free/webfonts"; @import "components/verify_other_explorers"; @import "components/errors"; @import "components/log-search"; - - +@import "components/radio"; +@import "components/network-selector"; @import "components/new_smart_contract"; @import "components/radio_big"; @import "components/btn_no_border"; diff --git a/apps/block_scout_web/assets/css/components/_navbar.scss b/apps/block_scout_web/assets/css/components/_navbar.scss index 1058c529c6..48c6c50f02 100644 --- a/apps/block_scout_web/assets/css/components/_navbar.scss +++ b/apps/block_scout_web/assets/css/components/_navbar.scss @@ -151,19 +151,13 @@ $navbar-logo-width: auto !default; } @include media-breakpoint-up(xl) { - width: 280px; + width: 340px; } @media (min-width: 1366px) { - width: 330px; + width: 500px; } @media (min-width: 1440px) { - width: 380px; - } - @media (min-width: 1580px) { - width: 430px; - } - @media (min-width: 1800px) { - width: 520px; + width: 580px; } } .input-group-append { @@ -223,6 +217,7 @@ $navbar-logo-width: auto !default; .navbar-brand { margin-left: 0; flex-shrink: 1; + display: inline-flex; .navbar-logo { max-width: 100%; } diff --git a/apps/block_scout_web/assets/css/components/_network-selector.scss b/apps/block_scout_web/assets/css/components/_network-selector.scss new file mode 100644 index 0000000000..ad0864bf61 --- /dev/null +++ b/apps/block_scout_web/assets/css/components/_network-selector.scss @@ -0,0 +1,334 @@ +$network-selector-overlay-background: $modal-overlay-color !default; +$network-selector-close-color: $primary !default; +$network-selector-horizontal-padding: 28px; +$btn-network-selector-load-more-background: #fff !default; +$btn-network-selector-load-more-color: $primary !default; +$network-selector-search-input-color: #a3a9b5 !default; +$network-selector-tab-active-border-color: $primary !default; +$network-selector-item-icon-dimensions: 30px !default; + +.network-selector-visible { + bottom: 0; + left: 0; + position: fixed; + right: 0; + top: 0; +} + +.network-selector-overlay { + background-color: rgba($network-selector-overlay-background, 0.9); + bottom: 0; + display: none; + left: 0; + position: fixed; + right: 0; + top: 0; + z-index: 123; +} + +.network-selector-overlay-close { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +.network-selector-wrapper { + display: flex; + height: 100%; + width: 100%; +} + +.network-selector { + background-color: #fff; + display: flex; + flex-direction: column; + flex-grow: 1; + flex-shrink: 1; + margin-left: auto; + max-width: 398px; + min-width: 0; + padding-top: 28px; + position: relative; + transition: right 0.25s ease-out; + z-index: 2; +} + +.network-selector-close { + flex-shrink: 0; + padding: 0 $network-selector-horizontal-padding; + margin: 0 0 8px; + + svg { + cursor: pointer; + display: block; + margin-left: auto; + } + + path { + fill: $network-selector-close-color; + } +} + +.network-selector-text-container { + flex-shrink: 0; + margin: 0 0 15px; + padding: 0 $network-selector-horizontal-padding; +} + +.network-selector-title { + color: #333; + font-size: 18px; + font-weight: normal; + line-height: 1.2; + margin: 0 0 10px; + padding: 0; +} + +.network-selector-text { + color: #a3a9b5; + font-size: 12px; + font-weight: normal; + line-height: 1.67; + margin: 0; + padding: 0; +} + +.network-selector-search-container { + align-items: center; + background-color: #f5f6fa; + display: flex; + flex-shrink: 0; + height: 62px; + margin: 0; + padding: 0 $network-selector-horizontal-padding; + + path { + flex-grow: 0; + flex-shrink: 0; + fill: $network-selector-search-input-color; + } +} + +.network-selector-search-input { + background-color: transparent; + border-color: transparent; + color: #333; + flex-grow: 1; + font-size: 14px; + font-weight: 600; + height: 100%; + outline: none; + padding: 0 20px 0 10px; + + &[placeholder]{ + color: $network-selector-search-input-color !important; + } + &::-webkit-input-placeholder { /* Chrome/Opera/Safari */ + color: $network-selector-search-input-color !important; + } + &::-moz-placeholder { /* Firefox 19+ */ + color: $network-selector-search-input-color !important; + } + &:-ms-input-placeholder { /* IE 10+ */ + color: $network-selector-search-input-color !important; + } + &:-moz-placeholder { /* Firefox 18- */ + color: $network-selector-search-input-color !important; + } +} + +.network-selector-tabs-container { + border-bottom: 1px solid $base-border-color; + display: flex; + flex-shrink: 0; + margin: 0 $network-selector-horizontal-padding; +} + +.network-selector-tab { + color: #a3a9b5; + cursor: pointer; + flex-shrink: 1; + font-size: 14px; + font-weight: 600; + line-height: 1.2; + min-width: 0; + padding: 20px 18px 15px; + position: relative; + text-align: center; + user-select: none; + white-space: nowrap; + + &:hover { + color: #333; + } + + &.active { + color: #333; + cursor: default; + + &::after { + background-color: $network-selector-tab-active-border-color; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + bottom: 0; + content: ""; + height: 4px; + left: 0; + position: absolute; + right: 0; + } + } +} + +.network-selector-tab-content { + display: none; + + &.active { + display: block; + } +} + +.network-selector-item { + border-bottom: 1px solid $base-border-color; + display: flex; + position: relative; + + .radio { + cursor: pointer; + margin: 0 15px 0 0; + + input[type="radio"] { + cursor: pointer; + } + } + + .radio-icon { + margin: 0; + } + + &:last-child { + border-bottom: none; + } +} + +.network-selector-item-url { + align-items: center; + cursor: pointer; + display: flex; + flex-grow: 1; + margin: 0; + padding: 20px 0; + + &:hover { + .network-selector-item-type { + color: #333; + } + } +} + +.network-selector-item-icon { + background-color: #dfdfdf; + background-position: 50% 50%; + background-repeat: no-repeat; + background-size: contain; + border-radius: 50%; + flex-grow: 0; + flex-shrink: 0; + height: $network-selector-item-icon-dimensions; + margin: 0 15px 0 0; + width: $network-selector-item-icon-dimensions; +} + +.network-selector-item-title { + color: #333; + flex-grow: 1; + font-size: 14px; + font-weight: normal; + line-height: 1.2; + overflow: hidden; + text-align: left; + text-overflow: ellipsis; + user-select: none; + white-space: nowrap; +} + +.network-selector-item-type { + color: #a3a9b5; + flex-shrink: 0; + font-size: 14px; + font-weight: normal; + line-height: 1.2; + padding-left: 10px; + text-align: right; + user-select: none; + white-space: nowrap; +} + +.network-selector-item-content { + align-items: center; + display: flex; + flex-grow: 1; +} + +.network-selector-networks-container { + flex-grow: 1; + flex-shrink: 1; + min-height: 100px; + overflow: auto; + padding: 0 $network-selector-horizontal-padding; +} + +.network-selector-load-more-container { + flex-shrink: 1; + padding: 0 $network-selector-horizontal-padding; + + .btn-network-selector-load-more { + @include btn-line($btn-network-selector-load-more-background, $btn-network-selector-load-more-color); + width: 100%; + } +} + +.network-selector-item-favorite { + align-items: center; + cursor: pointer; + display: flex; + flex-grow: 1; + flex-shrink: 0; + margin: 0; + max-width: 36px; + padding-left: 20px; + position: relative; + + input[type="checkbox"] { + cursor: pointer; + height: 100%; + opacity: 0; + position: absolute; + width: 100%; + z-index: 5; + + &:checked + svg { + position: relative; + z-index: 1; + + path { + fill: #ffb20d; + } + } + } + + &:hover { + path { + fill: rgba(#ffb20d, 0.4); + } + } +} + +.network-selector-tab-content-empty { + font-size: 16px; + font-weight: 600; + padding: 40px; + text-align: center; +} \ No newline at end of file diff --git a/apps/block_scout_web/assets/css/components/_radio.scss b/apps/block_scout_web/assets/css/components/_radio.scss new file mode 100644 index 0000000000..ebcc2ac892 --- /dev/null +++ b/apps/block_scout_web/assets/css/components/_radio.scss @@ -0,0 +1,49 @@ +$radio-color: $primary !default; +$radio-dimensions: 20px !default; + +.radio { + align-items: center; + display: flex; + position: relative; + + input[type="radio"] { + height: 100%; + opacity: 0; + position: absolute; + width: 100%; + z-index: 5; + + &:checked + .radio-icon::before { + background-color: $radio-color; + border-radius: 50%; + content: ""; + height: 12px; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%); + width: 12px; + } + } + + .radio-icon { + border: 1px solid $base-border-color; + border-radius: 50%; + flex-grow: 0; + flex-shrink: 0; + height: $radio-dimensions; + margin: 0 10px 0 0; + position: relative; + width: $radio-dimensions; + z-index: 1; + } + + .radio-text { + font-size: 14px; + font-weight: normal; + line-height: 1.2; + position: relative; + white-space: nowrap; + z-index: 1; + } +} diff --git a/apps/block_scout_web/assets/css/components/_transaction.scss b/apps/block_scout_web/assets/css/components/_transaction.scss index 5214b0b301..ae0fbf5c17 100644 --- a/apps/block_scout_web/assets/css/components/_transaction.scss +++ b/apps/block_scout_web/assets/css/components/_transaction.scss @@ -1,6 +1,45 @@ -.transaction-details-address { - font-size: 12px; - font-weight: bold; - line-height: 1.2; - margin: 0 0 12px; +.transaction-bottom-panel { + display: flex; + flex-direction: column; + @media (min-width: 768px) { + flex-direction: row; + justify-content: space-between; + align-items: flex-end; + } } + +.transaction-bottom-panel { + display: flex; + flex-direction: column; + @media (min-width: 768px) { + flex-direction: row; + justify-content: space-between; + align-items: flex-end; + } +} + +.download-all-transactions { + text-align: center; + color: #a3a9b5; + font-size: 13px; + margin-top: 10px; + @media (min-width: 768px) { + margin-top: 30px; + } + .download-all-transactions-link { + text-decoration: none; + svg { + position: relative; + margin-left: 2px; + top: -3px; + path { + fill: $primary; + } + } + &:hover { + span { + text-decoration: underline; + } + } + } +} \ No newline at end of file diff --git a/apps/block_scout_web/assets/js/app.js b/apps/block_scout_web/assets/js/app.js index e791a6b7ff..cd690f31db 100644 --- a/apps/block_scout_web/assets/js/app.js +++ b/apps/block_scout_web/assets/js/app.js @@ -31,6 +31,8 @@ import './pages/chain' import './pages/pending_transactions' import './pages/transaction' import './pages/transactions' +import './pages/favorites' +import './pages/network-search' import './pages/layout' import './pages/admin/tasks.js' @@ -57,3 +59,4 @@ import './lib/tooltip' import './lib/modals' import './lib/try_api' import './lib/card_tabs' +import './lib/network_selector' diff --git a/apps/block_scout_web/assets/js/lib/async_listing_load.js b/apps/block_scout_web/assets/js/lib/async_listing_load.js index 3a3eb2fd6c..8610d901f6 100644 --- a/apps/block_scout_web/assets/js/lib/async_listing_load.js +++ b/apps/block_scout_web/assets/js/lib/async_listing_load.js @@ -219,6 +219,14 @@ export const elements = { $el.hide() } + }, + '[csv-download]': { + render ($el, state) { + if (state.emptyResponse) { + return $el.hide() + } + return $el.show() + } } } diff --git a/apps/block_scout_web/assets/js/lib/network_selector.js b/apps/block_scout_web/assets/js/lib/network_selector.js new file mode 100644 index 0000000000..20c8e3d206 --- /dev/null +++ b/apps/block_scout_web/assets/js/lib/network_selector.js @@ -0,0 +1,77 @@ +import $ from 'jquery' + +$(function () { + const mainBody = $('body') + const showNetworkSelector = $('.js-show-network-selector') + const hideNetworkSelector = $('.js-network-selector-close') + const hideNetworkSelectorOverlay = $('.js-network-selector-overlay-close') + const networkSelector = $('.js-network-selector') + const networkSelectorOverlay = $('.js-network-selector-overlay') + const networkSelectorTab = $('.js-network-selector-tab') + const networkSelectorTabContent = $('.js-network-selector-tab-content') + const networkSelectorItemURL = $('.js-network-selector-item-url') + const FADE_IN_DELAY = 250 + + showNetworkSelector.on('click', (e) => { + e.preventDefault() + openNetworkSelector() + }) + + hideNetworkSelector.on('click', (e) => { + e.preventDefault() + closeNetworkSelector() + }) + + hideNetworkSelectorOverlay.on('click', (e) => { + e.preventDefault() + closeNetworkSelector() + }) + + networkSelectorTab.on('click', function (e) { + e.preventDefault() + setNetworkTab($(this)) + }) + + networkSelectorItemURL.on('click', function (e) { + window.location = $(this).attr('network-selector-item-url') + }) + + let setNetworkTab = (currentTab) => { + if (currentTab.hasClass('active')) return + + networkSelectorTab.removeClass('active') + currentTab.addClass('active') + networkSelectorTabContent.removeClass('active') + $(`[network-selector-tab="${currentTab.attr('network-selector-tab-filter')}"]`).addClass('active') + } + + let openNetworkSelector = () => { + mainBody.addClass('network-selector-visible') + networkSelectorOverlay.fadeIn(FADE_IN_DELAY) + setNetworkSelectorVisiblePosition() + } + + let closeNetworkSelector = () => { + mainBody.removeClass('network-selector-visible') + networkSelectorOverlay.fadeOut(FADE_IN_DELAY) + setNetworkSelectorHiddenPosition() + } + + let getNetworkSelectorWidth = () => { + return parseInt(networkSelector.css('width')) || parseInt(networkSelector.css('max-width')) + } + + let setNetworkSelectorHiddenPosition = () => { + return networkSelector.css({ 'right': `-${getNetworkSelectorWidth()}px` }) + } + + let setNetworkSelectorVisiblePosition = () => { + return networkSelector.css({ 'right': '0' }) + } + + let init = () => { + setNetworkSelectorHiddenPosition() + } + + init() +}) diff --git a/apps/block_scout_web/assets/js/pages/favorites.js b/apps/block_scout_web/assets/js/pages/favorites.js new file mode 100644 index 0000000000..055cac8c0f --- /dev/null +++ b/apps/block_scout_web/assets/js/pages/favorites.js @@ -0,0 +1,58 @@ +import $ from 'jquery' + +var favoritesContainer = $('.js-favorites-tab') +var favoritesNetworksUrls = [] + +if (localStorage.getItem('favoritesNetworksUrls') === null) { + localStorage.setItem('favoritesNetworksUrls', JSON.stringify(favoritesNetworksUrls)) +} else { + favoritesNetworksUrls = JSON.parse(localStorage.getItem('favoritesNetworksUrls')) +} + +$(document).on('change', ".network-selector-item-favorite input[type='checkbox']", function () { + var networkUrl = $(this).attr('data-url') + var thisStatus = $(this).is(':checked') + var workWith = $(".network-selector-item[data-url='" + networkUrl + "'") + + // Add new checkbox status to same network in another tabs + $(".network-selector-item-favorite input[data-url='" + networkUrl + "']").prop('checked', thisStatus) + + // Clone + var parent = $(".network-selector-item[data-url='" + networkUrl + "'").clone() + + // Push or remove favorite networks to array + var found = $.inArray(networkUrl, favoritesNetworksUrls) + if (found < 0 && thisStatus === true) { + favoritesNetworksUrls.push(networkUrl) + } else { + var index = favoritesNetworksUrls.indexOf(networkUrl) + if (index !== -1) { + favoritesNetworksUrls.splice(index, 1) + } + } + + // Push to localstorage + var willBePushed = JSON.stringify(favoritesNetworksUrls) + localStorage.setItem('favoritesNetworksUrls', willBePushed) + + // Append or remove item from 'favorites' tab + if (thisStatus === true) { + favoritesContainer.append(parent[0]) + $('.js-favorites-tab .network-selector-tab-content-empty').hide() + } else { + var willRemoved = favoritesContainer.find(workWith) + willRemoved.remove() + if (favoritesNetworksUrls.length === 0) { + $('.js-favorites-tab .network-selector-tab-content-empty').show() + } + } +}) + +if (favoritesNetworksUrls.length > 0) { + $('.js-favorites-tab .network-selector-tab-content-empty').hide() + for (var i = 0; i < favoritesNetworksUrls.length + 1; i++) { + $(".network-selector-item[data-url='" + favoritesNetworksUrls[i] + "'").find('input[data-url]').prop('checked', true) + var parent = $(".network-selector-item[data-url='" + favoritesNetworksUrls[i] + "'").clone() + favoritesContainer.append(parent[0]) + } +} diff --git a/apps/block_scout_web/assets/js/pages/network-search.js b/apps/block_scout_web/assets/js/pages/network-search.js new file mode 100644 index 0000000000..36b7e02348 --- /dev/null +++ b/apps/block_scout_web/assets/js/pages/network-search.js @@ -0,0 +1,21 @@ +import $ from 'jquery' + +var networkSearchInput = $('.network-selector-search-input') +var networkSearchInputVal = '' + +$(networkSearchInput).on('input', function () { + networkSearchInputVal = $(this).val() + + $.expr[':'].Contains = $.expr.createPseudo(function (arg) { + return function (elem) { + return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0 + } + }) + + if (networkSearchInputVal === '') { + $('.network-selector-item').show() + } else { + $('.network-selector-item').hide() + $(".network-selector-item:Contains('" + networkSearchInputVal + "')").show() + } +}) diff --git a/apps/block_scout_web/assets/static/images/network-selector-icons/aerum-mainnet.png b/apps/block_scout_web/assets/static/images/network-selector-icons/aerum-mainnet.png new file mode 100644 index 0000000000..cdef9a2edb Binary files /dev/null and b/apps/block_scout_web/assets/static/images/network-selector-icons/aerum-mainnet.png differ diff --git a/apps/block_scout_web/assets/static/images/network-selector-icons/callisto-mainnet.png b/apps/block_scout_web/assets/static/images/network-selector-icons/callisto-mainnet.png new file mode 100644 index 0000000000..2e9f2b2730 Binary files /dev/null and b/apps/block_scout_web/assets/static/images/network-selector-icons/callisto-mainnet.png differ diff --git a/apps/block_scout_web/assets/static/images/network-selector-icons/callisto.svg b/apps/block_scout_web/assets/static/images/network-selector-icons/callisto.svg new file mode 100644 index 0000000000..7adabb6538 --- /dev/null +++ b/apps/block_scout_web/assets/static/images/network-selector-icons/callisto.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/apps/block_scout_web/assets/static/images/network-selector-icons/core.svg b/apps/block_scout_web/assets/static/images/network-selector-icons/core.svg new file mode 100644 index 0000000000..63c66a6baa --- /dev/null +++ b/apps/block_scout_web/assets/static/images/network-selector-icons/core.svg @@ -0,0 +1,4 @@ + + + + diff --git a/apps/block_scout_web/assets/static/images/network-selector-icons/dai.svg b/apps/block_scout_web/assets/static/images/network-selector-icons/dai.svg new file mode 100644 index 0000000000..c4f800733e --- /dev/null +++ b/apps/block_scout_web/assets/static/images/network-selector-icons/dai.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/block_scout_web/assets/static/images/network-selector-icons/ethereum-classic.png b/apps/block_scout_web/assets/static/images/network-selector-icons/ethereum-classic.png new file mode 100755 index 0000000000..5ca5d8fe7b Binary files /dev/null and b/apps/block_scout_web/assets/static/images/network-selector-icons/ethereum-classic.png differ diff --git a/apps/block_scout_web/assets/static/images/network-selector-icons/ethereum-mainnet.png b/apps/block_scout_web/assets/static/images/network-selector-icons/ethereum-mainnet.png new file mode 100755 index 0000000000..3752a92544 Binary files /dev/null and b/apps/block_scout_web/assets/static/images/network-selector-icons/ethereum-mainnet.png differ diff --git a/apps/block_scout_web/assets/static/images/network-selector-icons/goerli-testnet.png b/apps/block_scout_web/assets/static/images/network-selector-icons/goerli-testnet.png new file mode 100644 index 0000000000..7a3ac4ae48 Binary files /dev/null and b/apps/block_scout_web/assets/static/images/network-selector-icons/goerli-testnet.png differ diff --git a/apps/block_scout_web/assets/static/images/network-selector-icons/kovan-testnet.png b/apps/block_scout_web/assets/static/images/network-selector-icons/kovan-testnet.png new file mode 100755 index 0000000000..4fabf2fd71 Binary files /dev/null and b/apps/block_scout_web/assets/static/images/network-selector-icons/kovan-testnet.png differ diff --git a/apps/block_scout_web/assets/static/images/network-selector-icons/poa-core.png b/apps/block_scout_web/assets/static/images/network-selector-icons/poa-core.png new file mode 100644 index 0000000000..68bb5976f1 Binary files /dev/null and b/apps/block_scout_web/assets/static/images/network-selector-icons/poa-core.png differ diff --git a/apps/block_scout_web/assets/static/images/network-selector-icons/poa-sokol.png b/apps/block_scout_web/assets/static/images/network-selector-icons/poa-sokol.png new file mode 100644 index 0000000000..da38f9834b Binary files /dev/null and b/apps/block_scout_web/assets/static/images/network-selector-icons/poa-sokol.png differ diff --git a/apps/block_scout_web/assets/static/images/network-selector-icons/rinkeby-testnet.png b/apps/block_scout_web/assets/static/images/network-selector-icons/rinkeby-testnet.png new file mode 100644 index 0000000000..0e3993eb36 Binary files /dev/null and b/apps/block_scout_web/assets/static/images/network-selector-icons/rinkeby-testnet.png differ diff --git a/apps/block_scout_web/assets/static/images/network-selector-icons/rinkeby.svg b/apps/block_scout_web/assets/static/images/network-selector-icons/rinkeby.svg new file mode 100644 index 0000000000..1991096926 --- /dev/null +++ b/apps/block_scout_web/assets/static/images/network-selector-icons/rinkeby.svg @@ -0,0 +1,15 @@ + + + + + + + + diff --git a/apps/block_scout_web/assets/static/images/network-selector-icons/ropsten-testnet.png b/apps/block_scout_web/assets/static/images/network-selector-icons/ropsten-testnet.png new file mode 100644 index 0000000000..bc5afa1a2e Binary files /dev/null and b/apps/block_scout_web/assets/static/images/network-selector-icons/ropsten-testnet.png differ diff --git a/apps/block_scout_web/assets/static/images/network-selector-icons/ropsten.svg b/apps/block_scout_web/assets/static/images/network-selector-icons/ropsten.svg new file mode 100644 index 0000000000..87c98f79d2 --- /dev/null +++ b/apps/block_scout_web/assets/static/images/network-selector-icons/ropsten.svg @@ -0,0 +1,4 @@ + + + + diff --git a/apps/block_scout_web/assets/static/images/network-selector-icons/rsk-mainnet.png b/apps/block_scout_web/assets/static/images/network-selector-icons/rsk-mainnet.png new file mode 100755 index 0000000000..c7c0e067c8 Binary files /dev/null and b/apps/block_scout_web/assets/static/images/network-selector-icons/rsk-mainnet.png differ diff --git a/apps/block_scout_web/assets/static/images/network-selector-icons/sokol.svg b/apps/block_scout_web/assets/static/images/network-selector-icons/sokol.svg new file mode 100644 index 0000000000..b2ced66189 --- /dev/null +++ b/apps/block_scout_web/assets/static/images/network-selector-icons/sokol.svg @@ -0,0 +1,4 @@ + + + + diff --git a/apps/block_scout_web/assets/static/images/network-selector-icons/xdai-chain.png b/apps/block_scout_web/assets/static/images/network-selector-icons/xdai-chain.png new file mode 100644 index 0000000000..5fb54a4175 Binary files /dev/null and b/apps/block_scout_web/assets/static/images/network-selector-icons/xdai-chain.png differ diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex index 6742d01b60..51503fd7c1 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex @@ -10,6 +10,7 @@ defmodule BlockScoutWeb.AddressTransactionController do alias BlockScoutWeb.TransactionView alias Explorer.{Chain, Market} + alias Explorer.Chain.{AddressTokenTransferCsvExporter, AddressTransactionCsvExporter} alias Explorer.ExchangeRates.Token alias Indexer.Fetcher.CoinBalanceOnDemand alias Phoenix.View @@ -106,4 +107,44 @@ defmodule BlockScoutWeb.AddressTransactionController do not_found(conn) end end + + def token_transfers_csv(conn, %{"address_id" => address_hash_string}) do + with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), + {:ok, address} <- Chain.hash_to_address(address_hash) do + address + |> AddressTokenTransferCsvExporter.export() + |> Enum.into( + conn + |> put_resp_content_type("application/csv") + |> put_resp_header("content-disposition", "attachment; filename=token_transfers.csv") + |> send_chunked(200) + ) + else + :error -> + unprocessable_entity(conn) + + {:error, :not_found} -> + not_found(conn) + end + end + + def transactions_csv(conn, %{"address_id" => address_hash_string}) do + with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string), + {:ok, address} <- Chain.hash_to_address(address_hash) do + address + |> AddressTransactionCsvExporter.export() + |> Enum.into( + conn + |> put_resp_content_type("application/csv") + |> put_resp_header("content-disposition", "attachment; filename=transactions.csv") + |> send_chunked(200) + ) + else + :error -> + unprocessable_entity(conn) + + {:error, :not_found} -> + not_found(conn) + end + end end diff --git a/apps/block_scout_web/lib/block_scout_web/router.ex b/apps/block_scout_web/lib/block_scout_web/router.ex index 308114a402..3a0b76b8ae 100644 --- a/apps/block_scout_web/lib/block_scout_web/router.ex +++ b/apps/block_scout_web/lib/block_scout_web/router.ex @@ -242,8 +242,12 @@ defmodule BlockScoutWeb.Router do get("/search_logs", AddressLogsController, :search_logs) + get("/transactions_csv", AddressTransactionController, :transactions_csv) + get("/token_autocomplete", ChainController, :token_autocomplete) + get("/token_transfers_csv", AddressTransactionController, :token_transfers_csv) + get("/chain_blocks", ChainController, :chain_blocks, as: :chain_blocks) get("/api_docs", APIDocsController, :index) diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address/_responsive_hash.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address/_responsive_hash.html.eex index 22e0f76870..cad11f8ee6 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address/_responsive_hash.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address/_responsive_hash.html.eex @@ -5,8 +5,8 @@ <%= if assigns[:truncate] do %> <%= BlockScoutWeb.AddressView.trimmed_hash(@address.hash) %> <% else %> - <%= @address %> - <%= BlockScoutWeb.AddressView.trimmed_hash(@address.hash) %> + <%= @address %> + <%= BlockScoutWeb.AddressView.trimmed_hash(@address.hash) %> <% end %> <% end %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_internal_transaction/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_internal_transaction/index.html.eex index 3bc2e7fe9b..2b4fd18674 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_internal_transaction/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_internal_transaction/index.html.eex @@ -67,8 +67,17 @@
- - <%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %> + + + <%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %> + diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_token/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_token/index.html.eex index 43457d3bc1..840d9cc1da 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_token/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_token/index.html.eex @@ -21,7 +21,17 @@
- <%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %> +
+
+ Download to_string(@address.hash)}) %>><%= gettext("CSV") %> + + + + +
+ <%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %> +
+ diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex index 11b4de110c..5abd8285c6 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex @@ -51,6 +51,8 @@ + + <%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "top", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>