web/multinode: by node payouts page markup
Change-Id: I4d760a9965d28afc37f4cfa971d95254bfcb1d7e
This commit is contained in:
parent
c9d4674859
commit
f2842a27e2
93
web/multinode/src/app/components/common/BaseTable.vue
Normal file
93
web/multinode/src/app/components/common/BaseTable.vue
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
// Copyright (C) 2021 Storj Labs, Inc.
|
||||||
|
// See LICENSE for copying information.
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<table class="base-table" border="0" cellpadding="0" cellspacing="0">
|
||||||
|
<slot name="head"></slot>
|
||||||
|
<slot name="body"></slot>
|
||||||
|
</table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Vue } from 'vue-property-decorator';
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class BaseTable extends Vue {}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.base-table {
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid var(--c-gray--light);
|
||||||
|
border-radius: var(--br-table);
|
||||||
|
font-family: 'font_semiBold', sans-serif;
|
||||||
|
z-index: 999;
|
||||||
|
|
||||||
|
th {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0 20px;
|
||||||
|
max-width: 250px;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead {
|
||||||
|
background: var(--c-block-gray);
|
||||||
|
|
||||||
|
tr {
|
||||||
|
height: 40px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--c-gray);
|
||||||
|
border-radius: var(--br-table);
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-item {
|
||||||
|
height: 56px;
|
||||||
|
text-align: right;
|
||||||
|
font-size: 16px;
|
||||||
|
color: var(--c-line);
|
||||||
|
|
||||||
|
th {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0 20px;
|
||||||
|
max-width: 250px;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:nth-of-type(even) {
|
||||||
|
background: var(--c-block-gray);
|
||||||
|
}
|
||||||
|
|
||||||
|
th:not(:first-of-type) {
|
||||||
|
font-family: 'font_medium', sans-serif;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.align-left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.online {
|
||||||
|
color: var(--c-success);
|
||||||
|
}
|
||||||
|
|
||||||
|
.offline {
|
||||||
|
color: var(--c-error);
|
||||||
|
}
|
||||||
|
|
||||||
|
.overflow-visible {
|
||||||
|
overflow: visible !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.options {
|
||||||
|
width: 60px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
40
web/multinode/src/app/components/common/VLink.vue
Normal file
40
web/multinode/src/app/components/common/VLink.vue
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Copyright (C) 2021 Storj Labs, Inc.
|
||||||
|
// See LICENSE for copying information.
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a class="link" :href="uri">
|
||||||
|
{{ label }}
|
||||||
|
<svg class="link__icon" width="13" height="12" viewBox="0 0 13 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M11.3333 5.33333C11.1565 5.33333 10.987 5.40357 10.8619 5.5286C10.7369 5.65362 10.6667 5.82319 10.6667 6V10C10.6667 10.1768 10.5964 10.3464 10.4714 10.4714C10.3464 10.5964 10.1768 10.6667 10 10.6667H2C1.82319 10.6667 1.65362 10.5964 1.5286 10.4714C1.40357 10.3464 1.33333 10.1768 1.33333 10V2C1.33333 1.82319 1.40357 1.65362 1.5286 1.5286C1.65362 1.40357 1.82319 1.33333 2 1.33333H6C6.17681 1.33333 6.34638 1.2631 6.4714 1.13807C6.59643 1.01305 6.66667 0.843478 6.66667 0.666667C6.66667 0.489856 6.59643 0.320286 6.4714 0.195262C6.34638 0.0702379 6.17681 0 6 0H2C1.46957 0 0.960859 0.210714 0.585787 0.585787C0.210714 0.960859 0 1.46957 0 2V10C0 10.5304 0.210714 11.0391 0.585787 11.4142C0.960859 11.7893 1.46957 12 2 12H10C10.5304 12 11.0391 11.7893 11.4142 11.4142C11.7893 11.0391 12 10.5304 12 10V6C12 5.82319 11.9298 5.65362 11.8047 5.5286C11.6797 5.40357 11.5101 5.33333 11.3333 5.33333Z" fill="#0059D0"/>
|
||||||
|
<path d="M8.66923 1.33333H9.72256L5.52923 5.52C5.46674 5.58198 5.41715 5.65571 5.3833 5.73695C5.34946 5.81819 5.33203 5.90533 5.33203 5.99333C5.33203 6.08134 5.34946 6.16848 5.3833 6.24972C5.41715 6.33096 5.46674 6.40469 5.52923 6.46667C5.59121 6.52915 5.66494 6.57875 5.74618 6.61259C5.82742 6.64644 5.91456 6.66387 6.00256 6.66387C6.09057 6.66387 6.17771 6.64644 6.25895 6.61259C6.34019 6.57875 6.41392 6.52915 6.4759 6.46667L10.6692 2.28V3.33333C10.6692 3.51014 10.7395 3.67971 10.8645 3.80474C10.9895 3.92976 11.1591 4 11.3359 4C11.5127 4 11.6823 3.92976 11.8073 3.80474C11.9323 3.67971 12.0026 3.51014 12.0026 3.33333V0.666667C12.0026 0.489856 11.9323 0.320286 11.8073 0.195262C11.6823 0.0702379 11.5127 0 11.3359 0H8.66923C8.49242 0 8.32285 0.0702379 8.19783 0.195262C8.0728 0.320286 8.00256 0.489856 8.00256 0.666667C8.00256 0.843478 8.0728 1.01305 8.19783 1.13807C8.32285 1.2631 8.49242 1.33333 8.66923 1.33333Z" fill="#0059D0"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class VLink extends Vue {
|
||||||
|
@Prop({default: ''})
|
||||||
|
public readonly uri: string;
|
||||||
|
@Prop({default: ''})
|
||||||
|
public readonly label: string;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
font-family: 'font_semiBold', sans-serif;
|
||||||
|
color: var(--c-primary);
|
||||||
|
font-size: 16px;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
margin-left: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -2,7 +2,7 @@
|
|||||||
// See LICENSE for copying information.
|
// See LICENSE for copying information.
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<tr class="node-item">
|
<tr class="table-item">
|
||||||
<th class="align-left">{{ node.displayedName }}</th>
|
<th class="align-left">{{ node.displayedName }}</th>
|
||||||
<template v-if="isSatelliteSelected">
|
<template v-if="isSatelliteSelected">
|
||||||
<th>{{ node.suspensionScore | floatToPercentage }}</th>
|
<th>{{ node.suspensionScore | floatToPercentage }}</th>
|
||||||
@ -31,7 +31,9 @@ import NodeOptions from '@/app/components/common/NodeOptions.vue';
|
|||||||
import { Node } from '@/nodes';
|
import { Node } from '@/nodes';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: { NodeOptions },
|
components: {
|
||||||
|
NodeOptions,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
export default class NodeItem extends Vue {
|
export default class NodeItem extends Vue {
|
||||||
@Prop({default: () => new Node()})
|
@Prop({default: () => new Node()})
|
||||||
@ -42,46 +44,3 @@ export default class NodeItem extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.node-item {
|
|
||||||
height: 56px;
|
|
||||||
text-align: right;
|
|
||||||
font-size: 16px;
|
|
||||||
color: var(--c-line);
|
|
||||||
|
|
||||||
th {
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 0 20px;
|
|
||||||
max-width: 250px;
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:nth-of-type(even) {
|
|
||||||
background: var(--c-block-gray);
|
|
||||||
}
|
|
||||||
|
|
||||||
th:not(:first-of-type) {
|
|
||||||
font-family: 'font_medium', sans-serif;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.online {
|
|
||||||
color: var(--c-success);
|
|
||||||
}
|
|
||||||
|
|
||||||
.offline {
|
|
||||||
color: var(--c-error);
|
|
||||||
}
|
|
||||||
|
|
||||||
.align-left {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.overflow-visible {
|
|
||||||
overflow: visible !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
// See LICENSE for copying information.
|
// See LICENSE for copying information.
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<table class="nodes-table" v-if="nodes.length" border="0" cellpadding="0" cellspacing="0">
|
<base-table v-if="nodes.length">
|
||||||
<thead>
|
<thead slot="head">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="align-left">NODE</th>
|
<th class="align-left">NODE</th>
|
||||||
<template v-if="isSatelliteSelected">
|
<template v-if="isSatelliteSelected">
|
||||||
@ -22,21 +22,23 @@
|
|||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody slot="body">
|
||||||
<node-item v-for="node in nodes" :key="node.id" :node="node" />
|
<node-item v-for="node in nodes" :key="node.id" :node="node" />
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</base-table>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Vue } from 'vue-property-decorator';
|
import { Component, Vue } from 'vue-property-decorator';
|
||||||
|
|
||||||
|
import BaseTable from '@/app/components/common/BaseTable.vue';
|
||||||
import NodeItem from '@/app/components/myNodes/tables/NodeItem.vue';
|
import NodeItem from '@/app/components/myNodes/tables/NodeItem.vue';
|
||||||
|
|
||||||
import { Node } from '@/nodes';
|
import { Node } from '@/nodes';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
|
BaseTable,
|
||||||
NodeItem,
|
NodeItem,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -50,37 +52,3 @@ export default class NodesTable extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.nodes-table {
|
|
||||||
width: 100%;
|
|
||||||
border: 1px solid var(--c-gray--light);
|
|
||||||
border-radius: var(--br-table);
|
|
||||||
font-family: 'font_semiBold', sans-serif;
|
|
||||||
|
|
||||||
th {
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 0 20px;
|
|
||||||
max-width: 250px;
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
thead {
|
|
||||||
background: var(--c-block-gray);
|
|
||||||
|
|
||||||
tr {
|
|
||||||
height: 40px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: var(--c-gray);
|
|
||||||
border-radius: var(--br-table);
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.align-left {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -29,6 +29,8 @@ import ReputationIcon from '@/../static/images/icons/navigation/reputation.svg';
|
|||||||
import TrafficIcon from '@/../static/images/icons/navigation/traffic.svg';
|
import TrafficIcon from '@/../static/images/icons/navigation/traffic.svg';
|
||||||
import StorjLogo from '@/../static/images/Logo.svg';
|
import StorjLogo from '@/../static/images/Logo.svg';
|
||||||
|
|
||||||
|
import { Config as RouterConfig } from '@/app/router';
|
||||||
|
|
||||||
export class NavigationLink {
|
export class NavigationLink {
|
||||||
constructor(
|
constructor(
|
||||||
public name: string = '',
|
public name: string = '',
|
||||||
@ -51,10 +53,9 @@ export default class NavigationArea extends Vue {
|
|||||||
/**
|
/**
|
||||||
* Array of navigation links with icons.
|
* Array of navigation links with icons.
|
||||||
*/
|
*/
|
||||||
// TODO: add actual routes
|
|
||||||
public readonly navigation: NavigationLink[] = [
|
public readonly navigation: NavigationLink[] = [
|
||||||
new NavigationLink('My Nodes', '/my-nodes', MyNodesIcon),
|
new NavigationLink('My Nodes', RouterConfig.MyNodes.path, MyNodesIcon),
|
||||||
new NavigationLink('Payouts', '/payouts', PayoutsIcon),
|
new NavigationLink('Payouts', RouterConfig.Payouts.with(RouterConfig.PayoutsSummary).path, PayoutsIcon),
|
||||||
new NavigationLink('Bandwidth & Disk', '/traffic', TrafficIcon),
|
new NavigationLink('Bandwidth & Disk', '/traffic', TrafficIcon),
|
||||||
new NavigationLink('Reputation', '/reputation', ReputationIcon),
|
new NavigationLink('Reputation', '/reputation', ReputationIcon),
|
||||||
new NavigationLink('Notifications', '/notifications', NotificationIcon),
|
new NavigationLink('Notifications', '/notifications', NotificationIcon),
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="calendar-button"
|
class="calendar-button"
|
||||||
@click.stop="openCalendar"
|
@click.stop="toggleCalendar"
|
||||||
>
|
>
|
||||||
<span class="label">{{ period }}</span>
|
<span class="label">{{ period }}</span>
|
||||||
<svg width="8" height="4" viewBox="0 0 8 4" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="8" height="4" viewBox="0 0 8 4" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M3.33657 3.73107C3.70296 4.09114 4.29941 4.08814 4.66237 3.73107L7.79796 0.650836C8.16435 0.291517 8.01864 0 7.47247 0L0.526407 0C-0.0197628 0 -0.16292 0.294525 0.200917 0.650836L3.33657 3.73107Z" fill="#131D3A"/>
|
<path d="M3.33657 3.73107C3.70296 4.09114 4.29941 4.08814 4.66237 3.73107L7.79796 0.650836C8.16435 0.291517 8.01864 0 7.47247 0L0.526407 0C-0.0197628 0 -0.16292 0.294525 0.200917 0.650836L3.33657 3.73107Z" fill="#131D3A"/>
|
||||||
</svg>
|
</svg>
|
||||||
<payout-period-calendar class="calendar-button__calendar" v-if="isCalendarShown" @onClose="closeCalendar" v-click-outside="close" />
|
<payout-period-calendar class="calendar-button__calendar" v-if="isCalendarShown" @onClose="closeCalendar" v-click-outside="closeCalendar" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -28,8 +28,8 @@ export default class Payout extends Vue {
|
|||||||
|
|
||||||
public isCalendarShown: boolean = false;
|
public isCalendarShown: boolean = false;
|
||||||
|
|
||||||
public openCalendar(): void {
|
public toggleCalendar(): void {
|
||||||
this.isCalendarShown = true;
|
this.isCalendarShown = !this.isCalendarShown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public closeCalendar(): void {
|
public closeCalendar(): void {
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
// Copyright (C) 2021 Storj Labs, Inc.
|
|
||||||
// See LICENSE for copying information.
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<table class="payouts-summary-table" v-if="nodePayoutsSummary.length" border="0" cellpadding="0" cellspacing="0">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="align-left">NODE</th>
|
|
||||||
<th>HELD</th>
|
|
||||||
<th>PAID</th>
|
|
||||||
<th class="options"></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<payouts-summary-item v-for="payoutSummary in nodePayoutsSummary" :key="payoutSummary.nodeId" :payouts-summary="payoutSummary"/>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
|
||||||
|
|
||||||
import NodeItem from '@/app/components/myNodes/tables/NodeItem.vue';
|
|
||||||
import PayoutsSummaryItem from '@/app/components/payouts/tables/PayoutsSummaryItem.vue';
|
|
||||||
|
|
||||||
import { NodePayoutsSummary } from '@/payouts';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
components: {
|
|
||||||
PayoutsSummaryItem,
|
|
||||||
NodeItem,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
export default class PayoutsSummaryTable extends Vue {
|
|
||||||
@Prop({default: () => []})
|
|
||||||
public nodePayoutsSummary: NodePayoutsSummary[];
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.payouts-summary-table {
|
|
||||||
width: 100%;
|
|
||||||
border: 1px solid var(--c-gray--light);
|
|
||||||
border-radius: var(--br-table);
|
|
||||||
font-family: 'font_semiBold', sans-serif;
|
|
||||||
z-index: 999;
|
|
||||||
|
|
||||||
th {
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 0 20px;
|
|
||||||
max-width: 250px;
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
thead {
|
|
||||||
background: var(--c-block-gray);
|
|
||||||
|
|
||||||
tr {
|
|
||||||
height: 40px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: var(--c-gray);
|
|
||||||
border-radius: var(--br-table);
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.align-left {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.options {
|
|
||||||
width: 60px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -0,0 +1,59 @@
|
|||||||
|
// Copyright (C) 2021 Storj Labs, Inc.
|
||||||
|
// See LICENSE for copying information.
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<base-table >
|
||||||
|
<thead slot="head">
|
||||||
|
<tr>
|
||||||
|
<th class="align-left">SATELLITE</th>
|
||||||
|
<th>MONTH 1-3</th>
|
||||||
|
<th>MONTH 4-6</th>
|
||||||
|
<th>MONTH 7-9</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody slot="body">
|
||||||
|
<tr class="table-item">
|
||||||
|
<th class="align-left">
|
||||||
|
<p class="table-item__name">US-Central-1</p>
|
||||||
|
<p class="table-item__months">7 month</p>
|
||||||
|
</th>
|
||||||
|
<th>$0.0005</th>
|
||||||
|
<th>$0.0053</th>
|
||||||
|
<th>$0.0005</th>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</base-table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Vue } from 'vue-property-decorator';
|
||||||
|
|
||||||
|
import BaseTable from '@/app/components/common/BaseTable.vue';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components: {
|
||||||
|
BaseTable,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
export default class HeldHistory extends Vue {}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.table-item {
|
||||||
|
|
||||||
|
&__name {
|
||||||
|
font-family: 'font_regular', sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--regular-text-color);
|
||||||
|
max-width: calc(100% - 40px);
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__months {
|
||||||
|
font-family: 'font_regular', sans-serif;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #9b9db1;
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,8 +1,8 @@
|
|||||||
// Copyright (C) 2020 Storj Labs, Inc.
|
// Copyright (C) 2021 Storj Labs, Inc.
|
||||||
// See LICENSE for copying information.
|
// See LICENSE for copying information.
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<tr class="payouts-summary-item">
|
<tr class="table-item payouts-summary-item" @click.prevent="redirectToByNodePayoutsPage">
|
||||||
<th class="align-left node-name">{{ payoutsSummary.nodeName || payoutsSummary.nodeId }}</th>
|
<th class="align-left node-name">{{ payoutsSummary.nodeName || payoutsSummary.nodeId }}</th>
|
||||||
<th>{{ payoutsSummary.held | centsToDollars }}</th>
|
<th>{{ payoutsSummary.held | centsToDollars }}</th>
|
||||||
<th>{{ payoutsSummary.paid | centsToDollars }}</th>
|
<th>{{ payoutsSummary.paid | centsToDollars }}</th>
|
||||||
@ -17,58 +17,33 @@ import { Component, Prop, Vue } from 'vue-property-decorator';
|
|||||||
|
|
||||||
import NodeOptions from '@/app/components/common/NodeOptions.vue';
|
import NodeOptions from '@/app/components/common/NodeOptions.vue';
|
||||||
|
|
||||||
|
import { Config as RouterConfig } from '@/app/router';
|
||||||
import { NodePayoutsSummary } from '@/payouts';
|
import { NodePayoutsSummary } from '@/payouts';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: { NodeOptions },
|
components: {
|
||||||
|
NodeOptions,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
export default class PayoutsSummaryItem extends Vue {
|
export default class PayoutsSummaryItem extends Vue {
|
||||||
@Prop({default: () => new NodePayoutsSummary()})
|
@Prop({default: () => new NodePayoutsSummary()})
|
||||||
public payoutsSummary: NodePayoutsSummary;
|
public payoutsSummary: NodePayoutsSummary;
|
||||||
|
|
||||||
|
public redirectToByNodePayoutsPage(): void {
|
||||||
|
this.$router.push({
|
||||||
|
name: RouterConfig.Payouts.with(RouterConfig.PayoutsByNode).name,
|
||||||
|
params: { id: this.payoutsSummary.nodeId },
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.payouts-summary-item {
|
.payouts-summary-item {
|
||||||
height: 56px;
|
|
||||||
text-align: right;
|
|
||||||
font-size: 16px;
|
|
||||||
color: var(--c-line);
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
th {
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 0 20px;
|
|
||||||
max-width: 250px;
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:nth-of-type(even) {
|
|
||||||
background: var(--c-block-gray);
|
|
||||||
}
|
|
||||||
|
|
||||||
th:not(:first-of-type) {
|
|
||||||
font-family: 'font_medium', sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.node-name {
|
.node-name {
|
||||||
color: var(--c-primary);
|
color: var(--c-primary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.align-left {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.overflow-visible {
|
|
||||||
overflow: visible !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.options {
|
|
||||||
width: 60px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (C) 2021 Storj Labs, Inc.
|
||||||
|
// See LICENSE for copying information.
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<base-table v-if="nodePayoutsSummary.length">
|
||||||
|
<thead slot="head">
|
||||||
|
<tr>
|
||||||
|
<th class="align-left">NODE</th>
|
||||||
|
<th>HELD</th>
|
||||||
|
<th>PAID</th>
|
||||||
|
<th class="options"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody slot="body">
|
||||||
|
<payouts-summary-item v-for="payoutSummary in nodePayoutsSummary" :key="payoutSummary.nodeId" :payouts-summary="payoutSummary"/>
|
||||||
|
</tbody>
|
||||||
|
</base-table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||||
|
|
||||||
|
import BaseTable from '@/app/components/common/BaseTable.vue';
|
||||||
|
import PayoutsSummaryItem from '@/app/components/payouts/tables/payoutSummary/PayoutsSummaryItem.vue';
|
||||||
|
|
||||||
|
import { NodePayoutsSummary } from '@/payouts';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components: {
|
||||||
|
BaseTable,
|
||||||
|
PayoutsSummaryItem,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
export default class PayoutsSummaryTable extends Vue {
|
||||||
|
@Prop({default: () => []})
|
||||||
|
public nodePayoutsSummary: NodePayoutsSummary[];
|
||||||
|
}
|
||||||
|
</script>
|
@ -0,0 +1,73 @@
|
|||||||
|
// Copyright (C) 2021 Storj Labs, Inc.
|
||||||
|
// See LICENSE for copying information.
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<base-table >
|
||||||
|
<thead slot="head">
|
||||||
|
<tr>
|
||||||
|
<th class="align-left">NAME</th>
|
||||||
|
<th>DISK</th>
|
||||||
|
<th>BANDWIDTH</th>
|
||||||
|
<th>PAYOUT</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody slot="body">
|
||||||
|
<tr class="table-item">
|
||||||
|
<th class="align-left">Download</th>
|
||||||
|
<th>--</th>
|
||||||
|
<th>98.24 GB</th>
|
||||||
|
<th>204.25$</th>
|
||||||
|
</tr>
|
||||||
|
<tr class="table-item">
|
||||||
|
<th class="align-left">Download Repair</th>
|
||||||
|
<th>--</th>
|
||||||
|
<th>98.24 GB</th>
|
||||||
|
<th>1 420.68$</th>
|
||||||
|
</tr>
|
||||||
|
<tr class="table-item">
|
||||||
|
<th class="align-left">Disk Space</th>
|
||||||
|
<th>25.45 GBm</th>
|
||||||
|
<th>--</th>
|
||||||
|
<th>30.77$</th>
|
||||||
|
</tr>
|
||||||
|
<tr class="table-item">
|
||||||
|
<th class="align-left">Gross Total</th>
|
||||||
|
<th></th><th></th>
|
||||||
|
<th>163.18$</th>
|
||||||
|
</tr>
|
||||||
|
<tr class="table-item">
|
||||||
|
<th class="align-left">Held amount</th>
|
||||||
|
<th></th><th></th>
|
||||||
|
<th>11 204.25$</th>
|
||||||
|
</tr>
|
||||||
|
<tr class="table-item">
|
||||||
|
<th class="align-left">NET TOTAL</th>
|
||||||
|
<th></th><th></th>
|
||||||
|
<th>$14.5</th>
|
||||||
|
</tr>
|
||||||
|
<tr class="table-item">
|
||||||
|
<th class="align-left">Minimal Threshold</th>
|
||||||
|
<th></th><th></th>
|
||||||
|
<th>$35</th>
|
||||||
|
</tr>
|
||||||
|
<tr class="table-item">
|
||||||
|
<th class="align-left">Distributed</th>
|
||||||
|
<th></th><th></th>
|
||||||
|
<th>$0</th>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</base-table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Vue } from 'vue-property-decorator';
|
||||||
|
|
||||||
|
import BaseTable from '@/app/components/common/BaseTable.vue';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components: {
|
||||||
|
BaseTable,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
export default class PayoutsByNodeTable extends Vue {}
|
||||||
|
</script>
|
@ -7,7 +7,9 @@ import { Component } from 'vue-router/types/router';
|
|||||||
import AddFirstNode from '@/app/views/AddFirstNode.vue';
|
import AddFirstNode from '@/app/views/AddFirstNode.vue';
|
||||||
import Dashboard from '@/app/views/Dashboard.vue';
|
import Dashboard from '@/app/views/Dashboard.vue';
|
||||||
import MyNodes from '@/app/views/MyNodes.vue';
|
import MyNodes from '@/app/views/MyNodes.vue';
|
||||||
|
import PayoutsByNode from '@/app/views/PayoutsByNode.vue';
|
||||||
import PayoutsPage from '@/app/views/PayoutsPage.vue';
|
import PayoutsPage from '@/app/views/PayoutsPage.vue';
|
||||||
|
import PayoutsRoot from '@/app/views/PayoutsRoot.vue';
|
||||||
import WelcomeScreen from '@/app/views/WelcomeScreen.vue';
|
import WelcomeScreen from '@/app/views/WelcomeScreen.vue';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,6 +52,18 @@ export class Route {
|
|||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public isChild(): boolean {
|
||||||
|
return this.path[0] !== '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
public with(child: Route): Route {
|
||||||
|
if (!child.isChild()) {
|
||||||
|
throw new Error('provided child root is not defined');
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Route(`${this.path}/${child.path}`, child.name, child.component, child.meta);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,13 +74,18 @@ export class Config {
|
|||||||
public static Welcome: Route = new Route('/welcome', 'Welcome', WelcomeScreen);
|
public static Welcome: Route = new Route('/welcome', 'Welcome', WelcomeScreen);
|
||||||
public static AddFirstNode: Route = new Route('/add-first-node', 'AddFirstNode', AddFirstNode);
|
public static AddFirstNode: Route = new Route('/add-first-node', 'AddFirstNode', AddFirstNode);
|
||||||
public static MyNodes: Route = new Route('/my-nodes', 'MyNodes', MyNodes);
|
public static MyNodes: Route = new Route('/my-nodes', 'MyNodes', MyNodes);
|
||||||
public static Payouts: Route = new Route('/payouts', 'Payouts', PayoutsPage);
|
public static Payouts: Route = new Route('/payouts', 'Payouts', PayoutsRoot);
|
||||||
|
public static PayoutsSummary: Route = new Route('summary', 'PayoutsSummary', PayoutsPage);
|
||||||
|
public static PayoutsByNode: Route = new Route('by-node/:id', 'PayoutsByNode', PayoutsByNode);
|
||||||
|
|
||||||
public static mode: RouterMode = 'history';
|
public static mode: RouterMode = 'history';
|
||||||
public static routes: Route[] = [
|
public static routes: Route[] = [
|
||||||
Config.Root.addChildren([
|
Config.Root.addChildren([
|
||||||
Config.MyNodes,
|
Config.MyNodes,
|
||||||
Config.Payouts,
|
Config.Payouts.addChildren([
|
||||||
|
Config.PayoutsByNode,
|
||||||
|
Config.PayoutsSummary,
|
||||||
|
]),
|
||||||
]),
|
]),
|
||||||
Config.Welcome,
|
Config.Welcome,
|
||||||
Config.AddFirstNode,
|
Config.AddFirstNode,
|
||||||
|
353
web/multinode/src/app/views/PayoutsByNode.vue
Normal file
353
web/multinode/src/app/views/PayoutsByNode.vue
Normal file
@ -0,0 +1,353 @@
|
|||||||
|
// Copyright (C) 2021 Storj Labs, Inc.
|
||||||
|
// See LICENSE for copying information.
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="payouts-by-node">
|
||||||
|
<div class="payouts-by-node__top-area">
|
||||||
|
<div class="payouts-by-node__top-area__left-area">
|
||||||
|
<div class="payouts-by-node__top-area__left-area__title-area">
|
||||||
|
<div class="payouts-by-node__top-area__left-area__title-area__arrow" @click="redirectToPayoutSummary">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.3398 0.554956C14.0797 1.2949 14.0797 2.49458 13.3398 3.23452L6.46904 10.1053H22.1053C23.1517 10.1053 24 10.9536 24 12C24 13.0464 23.1517 13.8947 22.1053 13.8947H6.46904L13.3398 20.7655C14.0797 21.5054 14.0797 22.7051 13.3398 23.445C12.5998 24.185 11.4002 24.185 10.6602 23.445L0.554956 13.3398C-0.184985 12.5998 -0.184985 11.4002 0.554956 10.6602L10.6602 0.554956C11.4002 -0.184985 12.5998 -0.184985 13.3398 0.554956Z" fill="#252A32"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h1 class="payouts-by-node__top-area__left-area__title-area__title">{{ nodeTitle }}</h1>
|
||||||
|
</div>
|
||||||
|
<p class="payouts-by-node__top-area__left-area__wallet">0xb64ef51c888972c908cfacf59b47c1afbc0ab8ac</p>
|
||||||
|
<div class="payouts-by-node__top-area__left-area__links">
|
||||||
|
<v-link uri="#" label="View on Etherscan (L1 payouts)" />
|
||||||
|
<v-link uri="#" label="View on zkScan (L2 payouts)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<info-block>
|
||||||
|
<div class="payouts-by-node__top-area__balance" slot="body">
|
||||||
|
<div class="payouts-by-node__top-area__balance__item">
|
||||||
|
<h3 class="payouts-by-node__top-area__balance__item__label">Undistributed Balance</h3>
|
||||||
|
<h2 class="payouts-by-node__top-area__balance__item__value">$1,992.93</h2>
|
||||||
|
</div>
|
||||||
|
<div class="payouts-by-node__top-area__balance__divider"></div>
|
||||||
|
<div class="payouts-by-node__top-area__balance__item">
|
||||||
|
<h3 class="payouts-by-node__top-area__balance__item__label">Estimated Earnings (Apr)</h3>
|
||||||
|
<h2 class="payouts-by-node__top-area__balance__item__value">$1,992.93</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</info-block>
|
||||||
|
</div>
|
||||||
|
<div class="payouts-by-node__content-area">
|
||||||
|
<div class="payouts-by-node__content-area__dropdowns">
|
||||||
|
<satellite-selection-dropdown />
|
||||||
|
<payout-period-calendar-button :period="period" />
|
||||||
|
</div>
|
||||||
|
<section class="payouts-by-node__content-area__main-info">
|
||||||
|
<payouts-by-node-table class="payouts-by-node__content-area__main-info__table"/>
|
||||||
|
<div class="payouts-by-node__content-area__main-info__totals-area">
|
||||||
|
<info-block>
|
||||||
|
<div class="payouts-by-node__content-area__main-info__totals-area__item" slot="body">
|
||||||
|
<p class="payouts-by-node__content-area__main-info__totals-area__item__label">TOTAL PAID</p>
|
||||||
|
<p class="payouts-by-node__content-area__main-info__totals-area__item__value">$700.52</p>
|
||||||
|
</div>
|
||||||
|
</info-block>
|
||||||
|
<info-block>
|
||||||
|
<div class="payouts-by-node__content-area__main-info__totals-area__item" slot="body">
|
||||||
|
<p class="payouts-by-node__content-area__main-info__totals-area__item__label">TOTAL HELD</p>
|
||||||
|
<p class="payouts-by-node__content-area__main-info__totals-area__item__value">$130.52</p>
|
||||||
|
</div>
|
||||||
|
</info-block>
|
||||||
|
<info-block>
|
||||||
|
<div class="payouts-by-node__content-area__main-info__totals-area__item" slot="body">
|
||||||
|
<p class="payouts-by-node__content-area__main-info__totals-area__item__label">TOTAL EARNED</p>
|
||||||
|
<p class="payouts-by-node__content-area__main-info__totals-area__item__value">$830.52</p>
|
||||||
|
</div>
|
||||||
|
</info-block>
|
||||||
|
<info-block class="information">
|
||||||
|
<div class="payouts-by-node__content-area__main-info__totals-area__information" slot="body">
|
||||||
|
<h3 class="payouts-by-node__content-area__main-info__totals-area__information__title">Minimal threshold & distributed payout system</h3>
|
||||||
|
<p class="payouts-by-node__content-area__main-info__totals-area__information__description">Short description how minimal threshold system works.</p>
|
||||||
|
<a href="#"
|
||||||
|
class="payouts-by-node__content-area__main-info__totals-area__information__link"
|
||||||
|
>
|
||||||
|
Learn more
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</info-block>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<section class="payouts-by-node__held-history">
|
||||||
|
<h2 class="payouts-by-node__held-history__title">Held Amount History</h2>
|
||||||
|
<held-history />
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Vue } from 'vue-property-decorator';
|
||||||
|
|
||||||
|
import InfoBlock from '@/app/components/common/InfoBlock.vue';
|
||||||
|
import SatelliteSelectionDropdown from '@/app/components/common/SatelliteSelectionDropdown.vue';
|
||||||
|
import VLink from '@/app/components/common/VLink.vue';
|
||||||
|
import PayoutPeriodCalendarButton from '@/app/components/payouts/PayoutPeriodCalendarButton.vue';
|
||||||
|
import HeldHistory from '@/app/components/payouts/tables/heldHistory/HeldHistory.vue';
|
||||||
|
import PayoutsByNodeTable from '@/app/components/payouts/tables/payoutsByNode/PayoutsByNodeTable.vue';
|
||||||
|
|
||||||
|
import { UnauthorizedError } from '@/api';
|
||||||
|
import { Config as RouterConfig } from '@/app/router';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components: {
|
||||||
|
HeldHistory,
|
||||||
|
PayoutsByNodeTable,
|
||||||
|
InfoBlock,
|
||||||
|
VLink,
|
||||||
|
PayoutPeriodCalendarButton,
|
||||||
|
SatelliteSelectionDropdown,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
export default class PayoutsPage extends Vue {
|
||||||
|
/**
|
||||||
|
* Checks id path parameters and redirects if no provided.
|
||||||
|
*/
|
||||||
|
public beforeMount(): void {
|
||||||
|
if (!this.$route.params.id) {
|
||||||
|
this.redirectToPayoutSummary();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* payoutsSummary contains payouts summary from store.
|
||||||
|
*/
|
||||||
|
public get nodeTitle(): string {
|
||||||
|
const selectedNodeSummary = this.$store.state.payouts.summary.nodeSummary.find(summary => {
|
||||||
|
return summary.nodeId === this.$route.params.id;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!selectedNodeSummary) return '';
|
||||||
|
|
||||||
|
return selectedNodeSummary.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* period selected payout period from store.
|
||||||
|
*/
|
||||||
|
public get period(): string {
|
||||||
|
return this.$store.getters['payouts/periodString'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async mounted(): Promise<void> {
|
||||||
|
try {
|
||||||
|
await this.$store.dispatch('payouts/summary');
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof UnauthorizedError) {
|
||||||
|
// TODO: redirect to login screen.
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: notify error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public redirectToPayoutSummary(): void {
|
||||||
|
this.$router.push(RouterConfig.PayoutsSummary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.payouts-by-node {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 60px;
|
||||||
|
overflow-y: auto;
|
||||||
|
height: calc(100vh - 60px);
|
||||||
|
|
||||||
|
&__top-area {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
&__left-area {
|
||||||
|
width: 53%;
|
||||||
|
margin-right: 36px;
|
||||||
|
|
||||||
|
&__title-area {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
margin-bottom: 36px;
|
||||||
|
|
||||||
|
&__arrow {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
max-width: 32px;
|
||||||
|
max-height: 32px;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-family: 'font_bold', sans-serif;
|
||||||
|
font-size: 32px;
|
||||||
|
color: var(--c-title);
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__wallet {
|
||||||
|
font-family: 'font_medium', sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
color: var(--c-title);
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__links {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
& *:not(:first-of-type) {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__balance {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
max-width: 200px;
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
font-size: 16px;
|
||||||
|
color: var(--c-gray);
|
||||||
|
font-family: 'font_medium', sans-serif;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__value {
|
||||||
|
font-size: 22px;
|
||||||
|
font-family: 'font_bold', sans-serif;
|
||||||
|
color: var(--c-title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__divider {
|
||||||
|
height: 60px;
|
||||||
|
width: 1px;
|
||||||
|
background: var(--c-gray--light);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content-area {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 48px;
|
||||||
|
|
||||||
|
&__dropdowns {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
& > *:first-of-type {
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-button,
|
||||||
|
.dropdown {
|
||||||
|
max-width: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__main-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 20px;
|
||||||
|
|
||||||
|
&__table {
|
||||||
|
width: 75%;
|
||||||
|
min-width: 750px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__totals-area {
|
||||||
|
width: 23%;
|
||||||
|
|
||||||
|
&__item,
|
||||||
|
&__information {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
font-family: 'font_semiBold', sans-serif;
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--c-gray);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__value {
|
||||||
|
font-size: 18px;
|
||||||
|
color: var(--c-title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__information {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--c-title);
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-family: 'font_bold', sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__description {
|
||||||
|
font-family: 'font_regular', sans-serif;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__link {
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--c-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__held-history {
|
||||||
|
width: 75%;
|
||||||
|
margin-top: 40px;
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-family: 'font_bold', sans-serif;
|
||||||
|
font-size: 24px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
color: var(--c-title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-block {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding: 20px;
|
||||||
|
|
||||||
|
&.information {
|
||||||
|
background: #f8f8f9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -37,7 +37,7 @@ import NodesTable from '@/app/components/myNodes/tables/NodesTable.vue';
|
|||||||
import DetailsArea from '@/app/components/payouts/DetailsArea.vue';
|
import DetailsArea from '@/app/components/payouts/DetailsArea.vue';
|
||||||
import PayoutHistoryBlock from '@/app/components/payouts/PayoutHistoryBlock.vue';
|
import PayoutHistoryBlock from '@/app/components/payouts/PayoutHistoryBlock.vue';
|
||||||
import PayoutPeriodCalendarButton from '@/app/components/payouts/PayoutPeriodCalendarButton.vue';
|
import PayoutPeriodCalendarButton from '@/app/components/payouts/PayoutPeriodCalendarButton.vue';
|
||||||
import PayoutsSummaryTable from '@/app/components/payouts/tables/PayoutsSummaryTable.vue';
|
import PayoutsSummaryTable from '@/app/components/payouts/tables/payoutSummary/PayoutsSummaryTable.vue';
|
||||||
|
|
||||||
import { UnauthorizedError } from '@/api';
|
import { UnauthorizedError } from '@/api';
|
||||||
import { PayoutsSummary } from '@/payouts';
|
import { PayoutsSummary } from '@/payouts';
|
||||||
@ -85,8 +85,8 @@ export default class PayoutsPage extends Vue {
|
|||||||
.payouts {
|
.payouts {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 60px;
|
padding: 60px;
|
||||||
height: 100%;
|
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
height: calc(100vh - 60px);
|
||||||
|
|
||||||
&__title {
|
&__title {
|
||||||
font-family: 'font_bold', sans-serif;
|
font-family: 'font_bold', sans-serif;
|
||||||
|
15
web/multinode/src/app/views/PayoutsRoot.vue
Normal file
15
web/multinode/src/app/views/PayoutsRoot.vue
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Copyright (C) 2021 Storj Labs, Inc.
|
||||||
|
// See LICENSE for copying information.
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div id="payouts-root">
|
||||||
|
<router-view/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Vue } from 'vue-property-decorator';
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class PayoutsRoot extends Vue {}
|
||||||
|
</script>
|
@ -17,6 +17,14 @@ export class NodePayoutsSummary {
|
|||||||
public held: number = 0,
|
public held: number = 0,
|
||||||
public paid: number = 0,
|
public paid: number = 0,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns node name for displaying.
|
||||||
|
* If no provided returns id.
|
||||||
|
*/
|
||||||
|
public get title(): string {
|
||||||
|
return this.nodeName || this.nodeId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import Vuex from 'vuex';
|
import Vuex from 'vuex';
|
||||||
|
|
||||||
import PayoutsSummaryItem from '@/app/components/payouts/tables/PayoutsSummaryItem.vue';
|
import PayoutsSummaryItem from '@/app/components/payouts/tables/payoutSummary/PayoutsSummaryItem.vue';
|
||||||
|
|
||||||
import { Currency } from '@/app/utils/currency';
|
import { Currency } from '@/app/utils/currency';
|
||||||
import { NodePayoutsSummary } from '@/payouts';
|
import { NodePayoutsSummary } from '@/payouts';
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import Vuex from 'vuex';
|
import Vuex from 'vuex';
|
||||||
|
|
||||||
import PayoutsSummaryTable from '@/app/components/payouts/tables/PayoutsSummaryTable.vue';
|
import PayoutsSummaryTable from '@/app/components/payouts/tables/payoutSummary/PayoutsSummaryTable.vue';
|
||||||
|
|
||||||
import { NodePayoutsSummary } from '@/payouts';
|
import { NodePayoutsSummary } from '@/payouts';
|
||||||
import { createLocalVue, shallowMount } from '@vue/test-utils';
|
import { createLocalVue, shallowMount } from '@vue/test-utils';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`PayoutsSummaryItem renders correctly 1`] = `
|
exports[`PayoutsSummaryItem renders correctly 1`] = `
|
||||||
<tr class="payouts-summary-item">
|
<tr class="table-item payouts-summary-item">
|
||||||
<th class="align-left node-name">name1</th>
|
<th class="align-left node-name">name1</th>
|
||||||
<th>$50.00</th>
|
<th>$50.00</th>
|
||||||
<th>$40.00</th>
|
<th>$40.00</th>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`PayoutsSummaryTable renders correctly 1`] = `
|
exports[`PayoutsSummaryTable renders correctly 1`] = `
|
||||||
<table border="0" cellpadding="0" cellspacing="0" class="payouts-summary-table">
|
<base-table-stub>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="align-left">NODE</th>
|
<th class="align-left">NODE</th>
|
||||||
@ -14,5 +14,5 @@ exports[`PayoutsSummaryTable renders correctly 1`] = `
|
|||||||
<payouts-summary-item-stub payoutssummary="[object Object]"></payouts-summary-item-stub>
|
<payouts-summary-item-stub payoutssummary="[object Object]"></payouts-summary-item-stub>
|
||||||
<payouts-summary-item-stub payoutssummary="[object Object]"></payouts-summary-item-stub>
|
<payouts-summary-item-stub payoutssummary="[object Object]"></payouts-summary-item-stub>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</base-table-stub>
|
||||||
`;
|
`;
|
||||||
|
Loading…
Reference in New Issue
Block a user