web/storagenode: added zksync wallet explorer button

WHAT: link to zkscan if zksync is opted in

WHY: to have ability to see wallet status redirected from dashboard

Change-Id: Ic2d084c1e551f461307fb5a1d5eb1741ed7cdf85
This commit is contained in:
NickolaiYurchenko 2021-03-24 17:43:12 +02:00 committed by Nikolay Yurchenko
parent 5dbc91622f
commit b91ba7057e
13 changed files with 317 additions and 157 deletions

View File

@ -1,146 +0,0 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="payout-container">
<WalletIcon
class="payout-container__image"
alt="wallet image"
/>
<div class="payout-container__wallet-address-section">
<p class="payout-container__wallet-address-section__label">{{label}}</p>
<p class="payout-container__wallet-address-section__bold-text">{{walletAddress}}</p>
</div>
<a
class="payout-container__button"
:href="'https://etherscan.io/address/' + walletAddress + '#tokentxns'"
target="_blank"
rel="noopener noreferrer"
>
<b class="payout-container-button-label">View on Etherscan</b>
</a>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import WalletIcon from '@/../static/images/wallet.svg';
@Component({
components: {
WalletIcon,
},
})
export default class PayoutArea extends Vue {
@Prop({default: ''})
private readonly label: string;
@Prop({default: ''})
private readonly walletAddress: string;
}
</script>
<style scoped lang="scss">
.payout-container {
background-color: var(--block-background-color);
padding: 40px;
display: flex;
justify-content: flex-start;
align-items: center;
border: 1px solid var(--block-border-color);
border-radius: 12px;
position: relative;
&__image {
margin-right: 40px;
}
&__wallet-address-section {
height: 50px;
display: flex;
flex-direction: column;
justify-content: space-between;
&__label {
font-size: 14px;
color: var(--regular-text-color);
}
&__bold-text {
font-family: 'font_bold', sans-serif;
font-size: 18px;
color: var(--regular-text-color);
word-break: break-all;
}
}
&__button {
font-size: 14px;
width: 168px;
height: 44px;
display: flex;
align-items: center;
justify-content: center;
background-color: var(--button-background-color);
border: 1px solid var(--block-border-color);
border-radius: 12px;
position: absolute;
top: 42px;
right: 40px;
color: var(--regular-text-color);
text-decoration: none;
&:hover {
background-color: #4d72b7;
cursor: pointer;
.payout-container-button-label {
color: #fff;
}
}
}
}
@media screen and (max-width: 1000px) {
.payout-container {
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
&__wallet-address-section {
&__label {
margin: 20px 0 6px 0;
}
}
&__button {
position: inherit;
left: 0;
margin: 20px 0 25px 0;
}
}
}
@media screen and (max-width: 500px) {
p {
margin: 0;
}
.payout-container {
&__wallet-address-section {
&__label {
margin: 20px 0 6px 0;
}
}
&__button {
margin: 10px 0 25px 0;
}
}
}
</style>

View File

@ -144,9 +144,10 @@
<BlueArrowRight />
</router-link>
</div>
<PayoutArea
label="STORJ Wallet Address"
:wallet-address="wallet"
<WalletArea
label="Wallet Address"
:wallet-address="nodeInfo.wallet"
:wallet-features="nodeInfo.walletFeatures"
/>
<TotalPayoutArea class="info-area__total-area" />
</div>
@ -164,9 +165,9 @@ import DiskStatChart from '@/app/components/DiskStatChart.vue';
import EgressChart from '@/app/components/EgressChart.vue';
import IngressChart from '@/app/components/IngressChart.vue';
import EstimationArea from '@/app/components/payments/EstimationArea.vue';
import PayoutArea from '@/app/components/PayoutArea.vue';
import SatelliteSelection from '@/app/components/SatelliteSelection.vue';
import TotalPayoutArea from '@/app/components/TotalPayoutArea.vue';
import WalletArea from '@/app/components/WalletArea.vue';
import BlueArrowRight from '@/../static/images/BlueArrowRight.svg';
import LargeDisqualificationIcon from '@/../static/images/largeDisqualify.svg';
@ -175,7 +176,7 @@ import LargeSuspensionIcon from '@/../static/images/largeSuspend.svg';
import { RouteConfig } from '@/app/router';
import { APPSTATE_ACTIONS } from '@/app/store/modules/appState';
import { Size } from '@/private/memory/size';
import { SatelliteInfo, SatelliteScores } from '@/storagenode/sno/sno';
import { Dashboard, SatelliteInfo, SatelliteScores } from '@/storagenode/sno/sno';
@Component ({
components: {
@ -190,7 +191,7 @@ import { SatelliteInfo, SatelliteScores } from '@/storagenode/sno/sno';
DiskSpaceChart,
BarInfo,
ChecksArea,
PayoutArea,
WalletArea,
LargeDisqualificationIcon,
LargeSuspensionIcon,
BlueArrowRight,
@ -290,11 +291,11 @@ export default class SNOContentFilling extends Vue {
}
/**
* wallet - wallet address as string from store.
* @return string - wallet address
* nodeInfo - contains common sno dashboard information.
* @return Dashboard
*/
public get wallet(): string {
return this.$store.state.node.info.wallet;
public get nodeInfo(): Dashboard {
return this.$store.state.node.info;
}
/**

View File

@ -0,0 +1,226 @@
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
<template>
<div class="wallet-area" :class="{'with-wallet-features': isZkSyncEnabled}">
<WalletIcon
class="wallet-area__image"
alt="wallet image"
/>
<div class="wallet-area__wallet-address-section">
<p class="wallet-area__wallet-address-section__label">{{label}}</p>
<p class="wallet-area__wallet-address-section__bold-text">{{walletAddress}}</p>
</div>
<a
class="wallet-area__button"
:href="`https://etherscan.io/address/${walletAddress}#tokentxns`"
target="_blank"
rel="noopener noreferrer"
v-if="!isZkSyncEnabled"
>
<b class="wallet-area-button-label">View on Etherscan</b>
</a>
<div class="wallet-area__buttons-area" v-else>
<a
class="wallet-area__button"
:href="`https://zkscan.io/explorer/accounts/${walletAddress}`"
target="_blank"
rel="noopener noreferrer"
>
<b class="wallet-area-button-label">View on zkScan</b>
</a>
<a
class="wallet-area__button"
:href="`https://etherscan.io/address/${walletAddress}#tokentxns`"
target="_blank"
rel="noopener noreferrer"
>
<b class="wallet-area-button-label">View on Etherscan</b>
</a>
<div class="wallet-area__buttons-area__active-wallet-area">
<CheckIcon class="wallet-area__buttons-area__active-wallet-area__icon" />
<p class="wallet-area__buttons-area__active-wallet-area__label">zkSync is opted-in</p>
</div>
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import CheckIcon from '@/../static/images/common/greenCheck.svg';
import WalletIcon from '@/../static/images/wallet.svg';
@Component({
components: {
CheckIcon,
WalletIcon,
},
})
export default class WalletArea extends Vue {
@Prop({default: ''})
private readonly label: string;
@Prop({default: ''})
private readonly walletAddress: string;
@Prop({default: () => []})
private readonly walletFeatures: string[];
public get isZkSyncEnabled(): boolean {
return this.walletFeatures.includes('zksync');
}
}
</script>
<style scoped lang="scss">
.wallet-area {
background-color: var(--block-background-color);
padding: 40px 30px;
display: flex;
justify-content: space-between;
align-items: center;
border: 1px solid var(--block-border-color);
border-radius: 12px;
position: relative;
&__image {
margin-right: 40px;
}
&__wallet-address-section {
height: auto;
display: flex;
flex-direction: column;
justify-content: space-between;
margin-right: 20px;
&__label {
font-size: 14px;
color: var(--regular-text-color);
}
&__bold-text {
font-family: 'font_bold', sans-serif;
font-size: 18px;
color: var(--regular-text-color);
word-break: break-all;
}
}
&__button {
font-size: 14px;
width: 168px;
height: 44px;
display: flex;
align-items: center;
justify-content: center;
background-color: var(--button-background-color);
border: 1px solid var(--block-border-color);
border-radius: 12px;
color: var(--regular-text-color);
text-decoration: none;
&:hover {
background-color: #4d72b7;
cursor: pointer;
.wallet-area-button-label {
color: #fff;
}
}
}
&__buttons-area {
display: flex;
align-items: center;
justify-content: flex-start;
margin-top: 10px;
& .wallet-area__button {
margin-right: 12px;
}
&__active-wallet-area {
display: flex;
align-items: center;
justify-content: flex-start;
&__icon {
background: white;
border-radius: 50%;
path {
fill: var(--wallet-feature-opted-in);
}
}
&__label {
font-family: 'font_semiBold', sans-serif;
font-size: 14px;
line-height: 17px;
margin-left: 7.5px;
color: var(--wallet-feature-opted-in);
}
}
}
}
.with-wallet-features {
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
& .wallet-area__wallet-address-section {
margin: 15px 0;
}
}
@media screen and (max-width: 1000px) {
.wallet-area {
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
padding-bottom: 25px;
&__wallet-address-section {
margin-bottom: 20px;
&__label {
margin: 20px 0 6px 0;
}
}
}
}
@media screen and (max-width: 500px) {
p {
margin: 0;
}
.wallet-area {
&__wallet-address-section {
margin-bottom: 10px;
&__label {
margin: 20px 0 6px 0;
}
}
&__buttons-area {
flex-direction: column;
width: 100%;
& .wallet-area__button {
margin: 0 0 15px 0;
width: 100%;
}
&__active-wallet-area {
margin-top: 10px;
}
}
}
}
</style>

View File

@ -54,6 +54,7 @@ export function newNodeModule(service: StorageNodeService): StoreModule<StorageN
nodeInfo.version,
nodeInfo.allowedVersion,
nodeInfo.wallet,
nodeInfo.walletFeatures,
nodeInfo.isUpToDate,
);

View File

@ -45,7 +45,7 @@ export class StorageNodeApi {
const diskSpace: Traffic = new Traffic(data.diskSpace.used, data.diskSpace.available, data.diskSpace.trash, data.diskSpace.overused);
const bandwidth: Traffic = new Traffic(data.bandwidth.used);
return new Dashboard(data.nodeID, data.wallet, satellites, diskSpace, bandwidth,
return new Dashboard(data.nodeID, data.wallet, data.walletFeatures || [], satellites, diskSpace, bandwidth,
new Date(data.lastPinged), new Date(data.startedAt), data.version, data.allowedVersion, data.upToDate);
}

View File

@ -15,6 +15,7 @@ export class Node {
public version: string = '',
public allowedVersion: string = '',
public wallet: string = '',
public walletFeatures: string[] = [],
public isLastVersion: boolean = false,
) {}
}
@ -63,6 +64,7 @@ export class Dashboard {
public constructor(
public nodeID: string,
public wallet: string,
public walletFeatures: string[],
public satellites: SatelliteInfo[],
public diskSpace: Traffic,
public bandwidth: Traffic,

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.5 8C15.5 9.98912 14.7098 11.8968 13.3033 13.3033C11.8968 14.7098 9.98912 15.5 8 15.5C6.01088 15.5 4.10322 14.7098 2.6967 13.3033C1.29018 11.8968 0.5 9.98912 0.5 8C0.5 6.01088 1.29018 4.10322 2.6967 2.6967C4.10322 1.29018 6.01088 0.5 8 0.5C9.98912 0.5 11.8968 1.29018 13.3033 2.6967C14.7098 4.10322 15.5 6.01088 15.5 8ZM11.7781 5.15937C11.7112 5.09264 11.6314 5.0401 11.5437 5.00489C11.4559 4.96968 11.362 4.95252 11.2675 4.95445C11.173 4.95637 11.0798 4.97734 10.9936 5.0161C10.9073 5.05485 10.8298 5.1106 10.7656 5.18L7.50969 9.32844L5.5475 7.36531C5.41421 7.24111 5.23792 7.1735 5.05576 7.17671C4.8736 7.17992 4.6998 7.25372 4.57098 7.38254C4.44215 7.51137 4.36836 7.68517 4.36515 7.86732C4.36193 8.04948 4.42955 8.22577 4.55375 8.35906L7.03437 10.8406C7.1012 10.9073 7.18078 10.9599 7.26836 10.9952C7.35594 11.0305 7.44973 11.0477 7.54414 11.046C7.63854 11.0442 7.73163 11.0235 7.81784 10.985C7.90405 10.9465 7.98163 10.891 8.04594 10.8219L11.7884 6.14375C11.916 6.01109 11.9865 5.8337 11.9848 5.64965C11.983 5.4656 11.9092 5.28958 11.7791 5.15937H11.7781Z" fill="#00CE7D"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -58,6 +58,7 @@
--error-page-background-color: #f2f2f3;
--error-page-text-color: #000;
--error-page-button-background: #133e9c;
--wallet-feature-opted-in: #00ce7d;
--error-page-image-path: url('../../static/images/errors/404.png');
--tooltip-background-path: url('../../static/images/tooltipBack.png');
--tooltip-arrow-path: url('../../static/images/tooltipArrow.png');
@ -123,6 +124,7 @@
--error-page-background-color: #1f2026;
--error-page-text-color: #fff;
--error-page-button-background: #565b6b;
--wallet-feature-opted-in: #00ce7d;
--error-page-image-path: url('../../static/images/errors/404Dark.png');
--tooltip-background-path: url('../../static/images/tooltipBackDark.png');
--tooltip-arrow-path: url('../../static/images/tooltipArrowDark.png');

View File

@ -46,6 +46,7 @@ describe('DiskStatChart', (): void => {
new Dashboard(
'1',
'2',
[],
[
new SatelliteInfo('3', 'url1', null, null),
new SatelliteInfo('4', 'url2', new Date(2020, 1, 1), new Date(2020, 0, 1)),

View File

@ -0,0 +1,39 @@
// Copyright (C) 2021 Storj Labs, Inc.
// See LICENSE for copying information.
import WalletArea from '@/app/components/WalletArea.vue';
import { createLocalVue, shallowMount } from '@vue/test-utils';
const localVue = createLocalVue();
describe('WalletArea', (): void => {
it('renders correctly with no wallet features', (): void => {
const wrapper = shallowMount(WalletArea, {
localVue,
propsData: {
walletAddress: '0x0123456789012345678901234567890123456789',
walletFeatures: [],
label: 'Wallet address',
},
});
expect(wrapper).toMatchSnapshot();
});
it('renders correctly with no wallet features', (): void => {
const wrapper = shallowMount(WalletArea, {
localVue,
propsData: {
walletAddress: '0x0123456789012345678901234567890123456789',
walletFeatures: [ 'zksync' ],
label: 'Wallet address',
},
});
expect(wrapper).toMatchSnapshot();
});
});

View File

@ -0,0 +1,27 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`WalletArea renders correctly with no wallet features 1`] = `
<div class="wallet-area">
<walleticon-stub alt="wallet image" class="wallet-area__image"></walleticon-stub>
<div class="wallet-area__wallet-address-section">
<p class="wallet-area__wallet-address-section__label">Wallet address</p>
<p class="wallet-area__wallet-address-section__bold-text">0x0123456789012345678901234567890123456789</p>
</div> <a href="https://etherscan.io/address/0x0123456789012345678901234567890123456789#tokentxns" target="_blank" rel="noopener noreferrer" class="wallet-area__button"><b class="wallet-area-button-label">View on Etherscan</b></a>
</div>
`;
exports[`WalletArea renders correctly with no wallet features 2`] = `
<div class="wallet-area with-wallet-features">
<walleticon-stub alt="wallet image" class="wallet-area__image"></walleticon-stub>
<div class="wallet-area__wallet-address-section">
<p class="wallet-area__wallet-address-section__label">Wallet address</p>
<p class="wallet-area__wallet-address-section__bold-text">0x0123456789012345678901234567890123456789</p>
</div>
<div class="wallet-area__buttons-area"><a href="https://zkscan.io/explorer/accounts/0x0123456789012345678901234567890123456789" target="_blank" rel="noopener noreferrer" class="wallet-area__button"><b class="wallet-area-button-label">View on zkScan</b></a> <a href="https://etherscan.io/address/0x0123456789012345678901234567890123456789#tokentxns" target="_blank" rel="noopener noreferrer" class="wallet-area__button"><b class="wallet-area-button-label">View on Etherscan</b></a>
<div class="wallet-area__buttons-area__active-wallet-area">
<checkicon-stub class="wallet-area__buttons-area__active-wallet-area__icon"></checkicon-stub>
<p class="wallet-area__buttons-area__active-wallet-area__label">zkSync is opted-in</p>
</div>
</div>
</div>
`;

View File

@ -62,6 +62,7 @@ describe('EstimationPeriodDropdown', (): void => {
const dashboardInfo = new Dashboard(
'1',
'2',
[],
[
new SatelliteInfo('3', 'url1', null, null),
new SatelliteInfo('4', 'url2', new Date(), new Date(2020, 0, 1)),

View File

@ -42,6 +42,7 @@ describe('mutations', () => {
const dashboardInfo = new Dashboard(
'1',
'2',
[],
[
new SatelliteInfo('3', 'url1', null, null),
new SatelliteInfo('4', 'url2', new Date(2020, 1, 1), new Date(2020, 0, 1)),
@ -179,6 +180,7 @@ describe('actions', () => {
new Dashboard(
'1',
'2',
[],
[
new SatelliteInfo('3', 'url1', null, null),
new SatelliteInfo('4', 'url2', new Date(2020, 1, 1), new Date(2020, 0, 1)),
@ -322,6 +324,7 @@ describe('getters', () => {
const dashboardInfo = new Dashboard(
'1',
'2',
[],
[
new SatelliteInfo('3', 'url1', null, null),
new SatelliteInfo('4', 'url2', firstTestDate, new Date(2020, 0, 1)),