Merge branch 'master' into simon/add-4y
This commit is contained in:
@@ -24,7 +24,7 @@
|
||||
<td>
|
||||
‎{{ block.time | date:'yyyy-MM-dd HH:mm' }}
|
||||
<div class="lg-inline">
|
||||
<i class="symbol">(<app-time-since [time]="block.time / 1000" [fastRender]="true"></app-time-since>)</i>
|
||||
<i class="symbol">(<app-time kind="since" [time]="block.time / 1000" [fastRender]="true"></app-time>)</i>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<tbody *ngIf="blocks.value; else loadingTmpl">
|
||||
<tr *ngFor="let block of blocks.value[0]; trackBy: trackByFn">
|
||||
<td><a [routerLink]="['/block/' | relativeUrl, block.hash]" [state]="{ data: { block: block } }">{{ block.height }}</a></td>
|
||||
<td><app-time-since [time]="block.time / 1000" [fastRender]="true"></app-time-since></td>
|
||||
<td><app-time kind="since" [time]="block.time / 1000" [fastRender]="true"></app-time></td>
|
||||
<td>{{ calculateTotalOutput(block) / 100 | number: '1.2-2' }} <span class="symbol">BSQ</span></td>
|
||||
<td class="d-none d-md-block">{{ block.txs.length }}</td>
|
||||
</tr>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<td>
|
||||
‎{{ bisqTx.time | date:'yyyy-MM-dd HH:mm' }}
|
||||
<div class="lg-inline">
|
||||
<i class="symbol">(<app-time-since [time]="bisqTx.time / 1000" [fastRender]="true"></app-time-since>)</i>
|
||||
<i class="symbol">(<app-time kind="since" [time]="bisqTx.time / 1000" [fastRender]="true"></app-time>)</i>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
{{ calculateTotalOutput(tx.outputs) / 100 | number: '1.2-2' }} <span class="d-none d-md-inline symbol">BSQ</span>
|
||||
</ng-template>
|
||||
</td>
|
||||
<td><app-time-since [time]="tx.time / 1000" [fastRender]="true"></app-time-since></td>
|
||||
<td><app-time kind="since" [time]="tx.time / 1000" [fastRender]="true"></app-time></td>
|
||||
<td class="d-none d-md-block"><a [routerLink]="['/block/' | relativeUrl, tx.blockHash]" [state]="{ data: { blockHeight: tx.blockHeight } }">{{ tx.blockHeight }}</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
@@ -3,13 +3,15 @@
|
||||
{{ addPlus && satoshis >= 0 ? '+' : '' }}
|
||||
{{
|
||||
(
|
||||
(blockConversion.price[currency] >= 0 ? blockConversion.price[currency] : null) ??
|
||||
(blockConversion.price['USD'] * blockConversion.exchangeRates['USD' + currency]) ?? 0
|
||||
(blockConversion.price[currency] > -1 ? blockConversion.price[currency] : null) ??
|
||||
(blockConversion.price['USD'] > -1 ? blockConversion.price['USD'] * blockConversion.exchangeRates['USD' + currency] : null) ?? 0
|
||||
) * satoshis / 100000000 | fiatCurrency : digitsInfo : currency
|
||||
}}
|
||||
</span>
|
||||
<ng-template #noblockconversion>
|
||||
<span class="fiat">{{ addPlus && satoshis >= 0 ? '+' : '' }}{{ (conversions ? conversions[currency] : 0) * satoshis / 100000000 | fiatCurrency : digitsInfo : currency }}</span>
|
||||
<span class="fiat">{{ addPlus && satoshis >= 0 ? '+' : '' }}
|
||||
{{ (conversions[currency] > -1 ? conversions[currency] : 0) * satoshis / 100000000 | fiatCurrency : digitsInfo : currency }}
|
||||
</span>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
|
||||
|
||||
@@ -54,31 +54,6 @@
|
||||
max-height: 270px;
|
||||
}
|
||||
|
||||
.formRadioGroup {
|
||||
margin-top: 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@media (min-width: 991px) {
|
||||
position: relative;
|
||||
top: -100px;
|
||||
}
|
||||
@media (min-width: 830px) and (max-width: 991px) {
|
||||
position: relative;
|
||||
top: 0px;
|
||||
}
|
||||
@media (min-width: 830px) {
|
||||
flex-direction: row;
|
||||
float: right;
|
||||
margin-top: 0px;
|
||||
}
|
||||
.btn-sm {
|
||||
font-size: 9px;
|
||||
@media (min-width: 830px) {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.disabled {
|
||||
pointer-events: none;
|
||||
opacity: 0.5;
|
||||
|
||||
@@ -54,31 +54,6 @@
|
||||
max-height: 270px;
|
||||
}
|
||||
|
||||
.formRadioGroup {
|
||||
margin-top: 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@media (min-width: 991px) {
|
||||
position: relative;
|
||||
top: -100px;
|
||||
}
|
||||
@media (min-width: 830px) and (max-width: 991px) {
|
||||
position: relative;
|
||||
top: 0px;
|
||||
}
|
||||
@media (min-width: 830px) {
|
||||
flex-direction: row;
|
||||
float: right;
|
||||
margin-top: 0px;
|
||||
}
|
||||
.btn-sm {
|
||||
font-size: 9px;
|
||||
@media (min-width: 830px) {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.disabled {
|
||||
pointer-events: none;
|
||||
opacity: 0.5;
|
||||
|
||||
@@ -54,31 +54,6 @@
|
||||
max-height: 270px;
|
||||
}
|
||||
|
||||
.formRadioGroup {
|
||||
margin-top: 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@media (min-width: 991px) {
|
||||
position: relative;
|
||||
top: -100px;
|
||||
}
|
||||
@media (min-width: 830px) and (max-width: 991px) {
|
||||
position: relative;
|
||||
top: 0px;
|
||||
}
|
||||
@media (min-width: 830px) {
|
||||
flex-direction: row;
|
||||
float: right;
|
||||
margin-top: 0px;
|
||||
}
|
||||
.btn-sm {
|
||||
font-size: 9px;
|
||||
@media (min-width: 830px) {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.disabled {
|
||||
pointer-events: none;
|
||||
opacity: 0.5;
|
||||
|
||||
@@ -54,31 +54,6 @@
|
||||
max-height: 270px;
|
||||
}
|
||||
|
||||
.formRadioGroup {
|
||||
margin-top: 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@media (min-width: 1130px) {
|
||||
position: relative;
|
||||
top: -100px;
|
||||
}
|
||||
@media (min-width: 830px) and (max-width: 1130px) {
|
||||
position: relative;
|
||||
top: 0px;
|
||||
}
|
||||
@media (min-width: 830px) {
|
||||
flex-direction: row;
|
||||
float: right;
|
||||
margin-top: 0px;
|
||||
}
|
||||
.btn-sm {
|
||||
font-size: 9px;
|
||||
@media (min-width: 830px) {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.disabled {
|
||||
pointer-events: none;
|
||||
opacity: 0.5;
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
<ng-template #transactionsPlural let-i i18n="shared.transaction-count.plural">{{ i }} transactions</ng-template>
|
||||
</div>
|
||||
<div [attr.data-cy]="'bitcoin-block-' + offset + '-index-' + i + '-time'" class="time-difference">
|
||||
<app-time-since [time]="block.timestamp" [fastRender]="true"></app-time-since></div>
|
||||
<app-time kind="since" [time]="block.timestamp" [fastRender]="true"></app-time></div>
|
||||
</div>
|
||||
<div class="animated" [class]="showMiningInfo ? 'show' : 'hide'" *ngIf="block.extras?.pool != undefined">
|
||||
<a [attr.data-cy]="'bitcoin-block-' + offset + '-index-' + i + '-pool'" class="badge badge-primary"
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
‎{{ block.timestamp * 1000 | date:'yyyy-MM-dd HH:mm' }}
|
||||
</td>
|
||||
<td class="mined" *ngIf="!widget" [class]="indexingAvailable ? '' : 'legacy'">
|
||||
<app-time-since [time]="block.timestamp" [fastRender]="true"></app-time-since>
|
||||
<app-time kind="since" [time]="block.timestamp" [fastRender]="true"></app-time>
|
||||
</td>
|
||||
<td *ngIf="auditAvailable" class="health text-right" [ngClass]="{'widget': widget, 'legacy': !indexingAvailable}">
|
||||
<a
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<td class="d-none d-md-block"><a [routerLink]="['/block' | relativeUrl, diffChange.height]">{{ diffChange.height
|
||||
}}</a></td>
|
||||
<td class="text-left">
|
||||
<app-time-since [time]="diffChange.timestamp" [fastRender]="true"></app-time-since>
|
||||
<app-time kind="since" [time]="diffChange.timestamp" [fastRender]="true"></app-time>
|
||||
</td>
|
||||
<td class="text-right">{{ diffChange.difficultyShorten }}</td>
|
||||
<td class="text-right" [style]="diffChange.change >= 0 ? 'color: #42B747' : 'color: #B74242'">
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<ng-template #blocksPlural let-i i18n="shared.blocks">{{ i }} <span class="shared-block">blocks</span></ng-template>
|
||||
<ng-template #blocksSingular let-i i18n="shared.block">{{ i }} <span class="shared-block">block</span></ng-template>
|
||||
</div>
|
||||
<div class="symbol"><app-time-until [time]="epochData.estimatedRetargetDate" [fastRender]="true"></app-time-until></div>
|
||||
<div class="symbol"><app-time kind="until" [time]="epochData.estimatedRetargetDate" [fastRender]="true"></app-time></div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<h5 class="card-title" i18n="difficulty-box.estimate">Estimate</h5>
|
||||
@@ -53,7 +53,7 @@
|
||||
<ng-template #blocksPlural let-i i18n="shared.blocks">{{ i }} <span class="shared-block">blocks</span></ng-template>
|
||||
<ng-template #blocksSingular let-i i18n="shared.block">{{ i }} <span class="shared-block">block</span></ng-template>
|
||||
</div>
|
||||
<div class="symbol"><app-time-until [time]="epochData.timeUntilHalving" [fastRender]="true"></app-time-until></div>
|
||||
<div class="symbol"><app-time kind="until" [time]="epochData.timeUntilHalving" [fastRender]="true"></app-time></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
<div *ngIf="stateService.env.MINING_DASHBOARD || stateService.env.LIGHTNING" class="mb-3 d-flex menu"
|
||||
style="padding: 0px 35px;">
|
||||
<div *ngIf="stateService.env.MINING_DASHBOARD || stateService.env.LIGHTNING" class="mb-3 d-flex menu">
|
||||
|
||||
<a routerLinkActive="active" class="btn btn-primary mr-1" [class]="padding"
|
||||
<a routerLinkActive="active" class="btn btn-primary" [class]="padding"
|
||||
[routerLink]="['/graphs/mempool' | relativeUrl]">Mempool</a>
|
||||
|
||||
<div ngbDropdown class="mr-1" [class]="padding" *ngIf="stateService.env.MINING_DASHBOARD">
|
||||
<div ngbDropdown [class]="padding" *ngIf="stateService.env.MINING_DASHBOARD">
|
||||
<button class="btn btn-primary w-100" id="dropdownBasic1" ngbDropdownToggle i18n="mining">Mining</button>
|
||||
<div ngbDropdownMenu aria-labelledby="dropdownBasic1">
|
||||
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/mining/pools' | relativeUrl]"
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
.menu {
|
||||
flex-grow: 1;
|
||||
padding: 0 35px;
|
||||
@media (min-width: 576px) {
|
||||
max-width: 400px;
|
||||
}
|
||||
}
|
||||
|
||||
& > * {
|
||||
margin: 0;
|
||||
margin-inline-end: 0.25rem;
|
||||
&.last-child {
|
||||
margin-inline-end: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,31 +54,6 @@
|
||||
height: 240px;
|
||||
}
|
||||
|
||||
.formRadioGroup {
|
||||
margin-top: 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@media (min-width: 991px) {
|
||||
position: relative;
|
||||
top: -100px;
|
||||
}
|
||||
@media (min-width: 830px) and (max-width: 991px) {
|
||||
position: relative;
|
||||
top: 0px;
|
||||
}
|
||||
@media (min-width: 830px) {
|
||||
flex-direction: row;
|
||||
float: right;
|
||||
margin-top: 0px;
|
||||
}
|
||||
.btn-sm {
|
||||
font-size: 9px;
|
||||
@media (min-width: 830px) {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pool-distribution {
|
||||
min-height: 56px;
|
||||
display: block;
|
||||
|
||||
@@ -48,31 +48,6 @@
|
||||
max-height: 293px;
|
||||
}
|
||||
|
||||
.formRadioGroup {
|
||||
margin-top: 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@media (min-width: 991px) {
|
||||
position: relative;
|
||||
top: -100px;
|
||||
}
|
||||
@media (min-width: 830px) and (max-width: 991px) {
|
||||
position: relative;
|
||||
top: 0px;
|
||||
}
|
||||
@media (min-width: 830px) {
|
||||
flex-direction: row;
|
||||
float: right;
|
||||
margin-top: 0px;
|
||||
}
|
||||
.btn-sm {
|
||||
font-size: 9px;
|
||||
@media (min-width: 830px) {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.loadingGraphs {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
</div>
|
||||
<div [attr.data-cy]="'mempool-block-' + i + '-time'" class="time-difference" *ngIf="projectedBlock.blockVSize <= stateService.blockVSize; else mergedBlock">
|
||||
<ng-template [ngIf]="network === 'liquid' || network === 'liquidtestnet'" [ngIfElse]="timeDiffMainnet">
|
||||
<app-time-until [time]="(1 * i) + now + 61000" [fastRender]="false" [fixedRender]="true"></app-time-until>
|
||||
<app-time kind="until" [time]="(1 * i) + now + 61000" [fastRender]="false" [fixedRender]="true"></app-time>
|
||||
</ng-template>
|
||||
<ng-template #timeDiffMainnet>
|
||||
<app-time-until [time]="da.timeAvg * (i + 1) + now + da.timeOffset" [fastRender]="false" [fixedRender]="true" [forceFloorOnTimeIntervals]="['hour']"></app-time-until>
|
||||
<app-time kind="until" [time]="da.timeAvg * (i + 1) + now + da.timeOffset" [fastRender]="false" [fixedRender]="true" [forceFloorOnTimeIntervals]="['hour']"></app-time>
|
||||
</ng-template>
|
||||
</div>
|
||||
<ng-template #mergedBlock>
|
||||
|
||||
@@ -33,31 +33,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.formRadioGroup {
|
||||
margin-top: 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@media (min-width: 991px) {
|
||||
position: relative;
|
||||
top: -100px;
|
||||
}
|
||||
@media (min-width: 830px) and (max-width: 991px) {
|
||||
position: relative;
|
||||
top: 0px;
|
||||
}
|
||||
@media (min-width: 830px) {
|
||||
flex-direction: row;
|
||||
float: right;
|
||||
margin-top: 0px;
|
||||
}
|
||||
.btn-sm {
|
||||
font-size: 9px;
|
||||
@media (min-width: 830px) {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-padding {
|
||||
@media (max-width: 992px) {
|
||||
padding-bottom: 65px
|
||||
|
||||
@@ -227,7 +227,7 @@
|
||||
‎{{ block.timestamp * 1000 | date:'yyyy-MM-dd HH:mm' }}
|
||||
</td>
|
||||
<td class="mined">
|
||||
<app-time-since [time]="block.timestamp" [fastRender]="true"></app-time-since>
|
||||
<app-time kind="since" [time]="block.timestamp" [fastRender]="true"></app-time>
|
||||
</td>
|
||||
<td class="coinbase">
|
||||
<span class="badge badge-secondary scriptmessage longer">
|
||||
|
||||
@@ -25,6 +25,12 @@
|
||||
</defs>
|
||||
</svg>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="'warning'">
|
||||
<svg [class]="class" [style]="style" [attr.width]="width" [attr.height]="height" [attr.viewBox]="viewBox" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M135.3 34.474c-15.62 27.306-54.206 95.63-85.21 150.534L9.075 257.583C5.382 264.08 6.76 269.217 7.908 271.7c2.326 5.028 7.29 7.537 11.155 8.215l.78.133 264.698.006-.554-.02c4.152.255 9.664-1.24 12.677-6.194 1.926-3.18 3.31-8.589-1.073-16.278L213.637 114.37l-45.351-79.205c-5.681-9.932-12.272-12.022-16.8-12.022-4.42 0-10.818 1.964-16.181 11.331h-.006zm-69.072 159.94c30.997-54.885 69.563-123.184 85.16-150.446l.186-.297c.2.303.393.582.618.981l45.363 79.22s72.377 126.47 78.569 137.283l-247.618-.007 37.719-66.734" style="fill:#ffc107;fill-opacity:1"/>
|
||||
<path d="M152.597 247.445c8.02 0 14.518-6.728 14.518-15.025 0-8.29-6.499-15.018-14.518-15.018-8.031 0-14.529 6.728-14.529 15.018 0 8.297 6.498 15.025 14.53 15.025m-.001-147.18c11.586 0 22.23 10.958 20.977 21.7l-9.922 75.564c-.966 6.601-4.95 11.433-11.055 11.433s-10.102-4.832-11.056-11.433l-9.927-75.564c-1.26-10.742 9.39-21.7 20.983-21.7" style="fill:#ffc107;fill-opacity:1"/>
|
||||
</svg>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchCase="'mempoolSpace'">
|
||||
<svg [class]="class" [style]="style" [attr.width]="width" [attr.height]="height" [attr.viewBox]="viewBox" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M 219.548 86.198 L 219.548 63.833 C 219.548 60.359 218.746 57.686 217.163 55.919 C 215.601 54.151 213.237 53.267 210.195 53.267 C 206.762 53.267 203.946 54.377 202.013 56.453 C 200.081 58.55 199.053 61.633 199.053 65.395 L 199.053 86.219 L 191.447 86.219 L 191.447 63.833 C 191.447 56.823 188.282 53.267 182.032 53.267 C 178.6 53.267 175.783 54.377 173.851 56.453 C 171.919 58.55 170.891 61.633 170.891 65.395 L 170.891 86.219 L 163.285 86.219 L 163.285 46.422 L 170.685 46.422 L 170.685 50.759 C 173.687 47.799 178.003 46.175 182.999 46.175 C 188.96 46.175 193.667 48.498 196.36 52.753 C 199.608 48.559 204.85 46.175 210.955 46.175 C 215.93 46.175 219.877 47.614 222.693 50.43 C 225.632 53.39 227.174 57.871 227.154 63.36 L 227.154 86.198 L 219.548 86.198 Z" fill="white"/>
|
||||
@@ -104,4 +110,4 @@
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
|
||||
@@ -13,4 +13,5 @@ export class SvgImagesComponent {
|
||||
@Input() width: string;
|
||||
@Input() height: string;
|
||||
@Input() viewBox: string;
|
||||
@Input() fill: string;
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Input, ChangeDetectorRef, OnChanges } from '@angular/core';
|
||||
import { StateService } from '../../services/state.service';
|
||||
import { dates } from '../../shared/i18n/dates';
|
||||
|
||||
@Component({
|
||||
selector: 'app-time-since',
|
||||
template: `{{ text }}`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class TimeSinceComponent implements OnInit, OnChanges, OnDestroy {
|
||||
interval: number;
|
||||
text: string;
|
||||
intervals = {};
|
||||
|
||||
@Input() time: number;
|
||||
@Input() dateString: number;
|
||||
@Input() fastRender = false;
|
||||
|
||||
constructor(
|
||||
private ref: ChangeDetectorRef,
|
||||
private stateService: StateService,
|
||||
) {
|
||||
this.intervals = {
|
||||
year: 31536000,
|
||||
month: 2592000,
|
||||
week: 604800,
|
||||
day: 86400,
|
||||
hour: 3600,
|
||||
minute: 60,
|
||||
second: 1
|
||||
};
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (!this.stateService.isBrowser) {
|
||||
this.text = this.calculate();
|
||||
this.ref.markForCheck();
|
||||
return;
|
||||
}
|
||||
this.interval = window.setInterval(() => {
|
||||
this.text = this.calculate();
|
||||
this.ref.markForCheck();
|
||||
}, 1000 * (this.fastRender ? 1 : 60));
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
this.text = this.calculate();
|
||||
this.ref.markForCheck();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
clearInterval(this.interval);
|
||||
}
|
||||
|
||||
calculate() {
|
||||
let date: Date;
|
||||
if (this.dateString) {
|
||||
date = new Date(this.dateString)
|
||||
} else {
|
||||
date = new Date(this.time * 1000);
|
||||
}
|
||||
const seconds = Math.floor((+new Date() - +date) / 1000);
|
||||
if (seconds < 60) {
|
||||
return $localize`:@@date-base.just-now:Just now`;
|
||||
}
|
||||
let counter: number;
|
||||
for (const i in this.intervals) {
|
||||
if (this.intervals.hasOwnProperty(i)) {
|
||||
counter = Math.floor(seconds / this.intervals[i]);
|
||||
const dateStrings = dates(counter);
|
||||
if (counter > 0) {
|
||||
if (counter === 1) {
|
||||
switch (i) { // singular (1 day)
|
||||
case 'year': return $localize`:@@time-since:${dateStrings.i18nYear}:DATE: ago`; break;
|
||||
case 'month': return $localize`:@@time-since:${dateStrings.i18nMonth}:DATE: ago`; break;
|
||||
case 'week': return $localize`:@@time-since:${dateStrings.i18nWeek}:DATE: ago`; break;
|
||||
case 'day': return $localize`:@@time-since:${dateStrings.i18nDay}:DATE: ago`; break;
|
||||
case 'hour': return $localize`:@@time-since:${dateStrings.i18nHour}:DATE: ago`; break;
|
||||
case 'minute': return $localize`:@@time-since:${dateStrings.i18nMinute}:DATE: ago`; break;
|
||||
case 'second': return $localize`:@@time-since:${dateStrings.i18nSecond}:DATE: ago`; break;
|
||||
}
|
||||
} else {
|
||||
switch (i) { // plural (2 days)
|
||||
case 'year': return $localize`:@@time-since:${dateStrings.i18nYears}:DATE: ago`; break;
|
||||
case 'month': return $localize`:@@time-since:${dateStrings.i18nMonths}:DATE: ago`; break;
|
||||
case 'week': return $localize`:@@time-since:${dateStrings.i18nWeeks}:DATE: ago`; break;
|
||||
case 'day': return $localize`:@@time-since:${dateStrings.i18nDays}:DATE: ago`; break;
|
||||
case 'hour': return $localize`:@@time-since:${dateStrings.i18nHours}:DATE: ago`; break;
|
||||
case 'minute': return $localize`:@@time-since:${dateStrings.i18nMinutes}:DATE: ago`; break;
|
||||
case 'second': return $localize`:@@time-since:${dateStrings.i18nSeconds}:DATE: ago`; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Input, ChangeDetectorRef, OnChanges } from '@angular/core';
|
||||
import { StateService } from '../../services/state.service';
|
||||
import { dates } from '../../shared/i18n/dates';
|
||||
|
||||
@Component({
|
||||
selector: 'app-time-span',
|
||||
template: `{{ text }}`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class TimeSpanComponent implements OnInit, OnChanges, OnDestroy {
|
||||
interval: number;
|
||||
text: string;
|
||||
intervals = {};
|
||||
|
||||
@Input() time: number;
|
||||
@Input() fastRender = false;
|
||||
|
||||
constructor(
|
||||
private ref: ChangeDetectorRef,
|
||||
private stateService: StateService,
|
||||
) {
|
||||
this.intervals = {
|
||||
year: 31536000,
|
||||
month: 2592000,
|
||||
week: 604800,
|
||||
day: 86400,
|
||||
hour: 3600,
|
||||
minute: 60,
|
||||
second: 1
|
||||
};
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (!this.stateService.isBrowser) {
|
||||
this.text = this.calculate();
|
||||
this.ref.markForCheck();
|
||||
return;
|
||||
}
|
||||
this.interval = window.setInterval(() => {
|
||||
this.text = this.calculate();
|
||||
this.ref.markForCheck();
|
||||
}, 1000 * (this.fastRender ? 1 : 60));
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
this.text = this.calculate();
|
||||
this.ref.markForCheck();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
clearInterval(this.interval);
|
||||
}
|
||||
|
||||
calculate() {
|
||||
const seconds = Math.floor(this.time);
|
||||
if (seconds < 60) {
|
||||
return $localize`:@@date-base.just-now:Just now`;
|
||||
}
|
||||
let counter: number;
|
||||
for (const i in this.intervals) {
|
||||
if (this.intervals.hasOwnProperty(i)) {
|
||||
counter = Math.floor(seconds / this.intervals[i]);
|
||||
const dateStrings = dates(counter);
|
||||
if (counter > 0) {
|
||||
if (counter === 1) {
|
||||
switch (i) { // singular (1 day)
|
||||
case 'year': return $localize`:@@time-span:After ${dateStrings.i18nYear}:DATE:`; break;
|
||||
case 'month': return $localize`:@@time-span:After ${dateStrings.i18nMonth}:DATE:`; break;
|
||||
case 'week': return $localize`:@@time-span:After ${dateStrings.i18nWeek}:DATE:`; break;
|
||||
case 'day': return $localize`:@@time-span:After ${dateStrings.i18nDay}:DATE:`; break;
|
||||
case 'hour': return $localize`:@@time-span:After ${dateStrings.i18nHour}:DATE:`; break;
|
||||
case 'minute': return $localize`:@@time-span:After ${dateStrings.i18nMinute}:DATE:`; break;
|
||||
case 'second': return $localize`:@@time-span:After ${dateStrings.i18nSecond}:DATE:`; break;
|
||||
}
|
||||
} else {
|
||||
switch (i) { // plural (2 days)
|
||||
case 'year': return $localize`:@@time-span:After ${dateStrings.i18nYears}:DATE:`; break;
|
||||
case 'month': return $localize`:@@time-span:After ${dateStrings.i18nMonths}:DATE:`; break;
|
||||
case 'week': return $localize`:@@time-span:After ${dateStrings.i18nWeeks}:DATE:`; break;
|
||||
case 'day': return $localize`:@@time-span:After ${dateStrings.i18nDays}:DATE:`; break;
|
||||
case 'hour': return $localize`:@@time-span:After ${dateStrings.i18nHours}:DATE:`; break;
|
||||
case 'minute': return $localize`:@@time-span:After ${dateStrings.i18nMinutes}:DATE:`; break;
|
||||
case 'second': return $localize`:@@time-span:After ${dateStrings.i18nSeconds}:DATE:`; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Input, ChangeDetectorRef, OnChanges } from '@angular/core';
|
||||
import { StateService } from '../../services/state.service';
|
||||
import { dates } from '../../shared/i18n/dates';
|
||||
|
||||
@Component({
|
||||
selector: 'app-time-until',
|
||||
template: `{{ text }}`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class TimeUntilComponent implements OnInit, OnChanges, OnDestroy {
|
||||
interval: number;
|
||||
text: string;
|
||||
intervals = {};
|
||||
|
||||
@Input() time: number;
|
||||
@Input() fastRender = false;
|
||||
@Input() fixedRender = false;
|
||||
@Input() forceFloorOnTimeIntervals: string[];
|
||||
|
||||
constructor(
|
||||
private ref: ChangeDetectorRef,
|
||||
private stateService: StateService,
|
||||
) {
|
||||
this.intervals = {
|
||||
year: 31536000,
|
||||
month: 2592000,
|
||||
week: 604800,
|
||||
day: 86400,
|
||||
hour: 3600,
|
||||
minute: 60,
|
||||
second: 1
|
||||
};
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if(this.fixedRender){
|
||||
this.text = this.calculate();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.stateService.isBrowser) {
|
||||
this.text = this.calculate();
|
||||
this.ref.markForCheck();
|
||||
return;
|
||||
}
|
||||
this.interval = window.setInterval(() => {
|
||||
this.text = this.calculate();
|
||||
this.ref.markForCheck();
|
||||
}, 1000 * (this.fastRender ? 1 : 60));
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
this.text = this.calculate();
|
||||
this.ref.markForCheck();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
clearInterval(this.interval);
|
||||
}
|
||||
|
||||
calculate() {
|
||||
const seconds = (+new Date(this.time) - +new Date()) / 1000;
|
||||
|
||||
if (seconds < 60) {
|
||||
const dateStrings = dates(1);
|
||||
return $localize`:@@time-until:In ~${dateStrings.i18nMinute}:DATE:`;
|
||||
}
|
||||
let counter: number;
|
||||
for (const i in this.intervals) {
|
||||
if (this.intervals.hasOwnProperty(i)) {
|
||||
if (this.forceFloorOnTimeIntervals && this.forceFloorOnTimeIntervals.indexOf(i) > -1) {
|
||||
counter = Math.floor(seconds / this.intervals[i]);
|
||||
} else {
|
||||
counter = Math.round(seconds / this.intervals[i]);
|
||||
}
|
||||
const dateStrings = dates(counter);
|
||||
if (counter > 0) {
|
||||
if (counter === 1) {
|
||||
switch (i) { // singular (In ~1 day)
|
||||
case 'year': return $localize`:@@time-until:In ~${dateStrings.i18nYear}:DATE:`; break;
|
||||
case 'month': return $localize`:@@time-until:In ~${dateStrings.i18nMonth}:DATE:`; break;
|
||||
case 'week': return $localize`:@@time-until:In ~${dateStrings.i18nWeek}:DATE:`; break;
|
||||
case 'day': return $localize`:@@time-until:In ~${dateStrings.i18nDay}:DATE:`; break;
|
||||
case 'hour': return $localize`:@@time-until:In ~${dateStrings.i18nHour}:DATE:`; break;
|
||||
case 'minute': return $localize`:@@time-until:In ~${dateStrings.i18nMinute}:DATE:`;
|
||||
case 'second': return $localize`:@@time-until:In ~${dateStrings.i18nSecond}:DATE:`;
|
||||
}
|
||||
} else {
|
||||
switch (i) { // plural (In ~2 days)
|
||||
case 'year': return $localize`:@@time-until:In ~${dateStrings.i18nYears}:DATE:`; break;
|
||||
case 'month': return $localize`:@@time-until:In ~${dateStrings.i18nMonths}:DATE:`; break;
|
||||
case 'week': return $localize`:@@time-until:In ~${dateStrings.i18nWeeks}:DATE:`; break;
|
||||
case 'day': return $localize`:@@time-until:In ~${dateStrings.i18nDays}:DATE:`; break;
|
||||
case 'hour': return $localize`:@@time-until:In ~${dateStrings.i18nHours}:DATE:`; break;
|
||||
case 'minute': return $localize`:@@time-until:In ~${dateStrings.i18nMinutes}:DATE:`; break;
|
||||
case 'second': return $localize`:@@time-until:In ~${dateStrings.i18nSeconds}:DATE:`; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
190
frontend/src/app/components/time/time.component.ts
Normal file
190
frontend/src/app/components/time/time.component.ts
Normal file
@@ -0,0 +1,190 @@
|
||||
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Input, ChangeDetectorRef, OnChanges } from '@angular/core';
|
||||
import { StateService } from '../../services/state.service';
|
||||
import { dates } from '../../shared/i18n/dates';
|
||||
|
||||
@Component({
|
||||
selector: 'app-time',
|
||||
template: `{{ text }}`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class TimeComponent implements OnInit, OnChanges, OnDestroy {
|
||||
interval: number;
|
||||
text: string;
|
||||
intervals = {};
|
||||
|
||||
@Input() time: number;
|
||||
@Input() dateString: number;
|
||||
@Input() kind: 'plain' | 'since' | 'until' | 'span' = 'plain';
|
||||
@Input() fastRender = false;
|
||||
@Input() fixedRender = false;
|
||||
@Input() relative = false;
|
||||
@Input() forceFloorOnTimeIntervals: string[];
|
||||
|
||||
constructor(
|
||||
private ref: ChangeDetectorRef,
|
||||
private stateService: StateService,
|
||||
) {
|
||||
this.intervals = {
|
||||
year: 31536000,
|
||||
month: 2592000,
|
||||
week: 604800,
|
||||
day: 86400,
|
||||
hour: 3600,
|
||||
minute: 60,
|
||||
second: 1
|
||||
};
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if(this.fixedRender){
|
||||
this.text = this.calculate();
|
||||
return;
|
||||
}
|
||||
if (!this.stateService.isBrowser) {
|
||||
this.text = this.calculate();
|
||||
this.ref.markForCheck();
|
||||
return;
|
||||
}
|
||||
this.interval = window.setInterval(() => {
|
||||
this.text = this.calculate();
|
||||
this.ref.markForCheck();
|
||||
}, 1000 * (this.fastRender ? 1 : 60));
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
this.text = this.calculate();
|
||||
this.ref.markForCheck();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
clearInterval(this.interval);
|
||||
}
|
||||
|
||||
calculate() {
|
||||
let seconds: number;
|
||||
switch (this.kind) {
|
||||
case 'since':
|
||||
seconds = Math.floor((+new Date() - +new Date(this.dateString || this.time * 1000)) / 1000);
|
||||
break;
|
||||
case 'until':
|
||||
seconds = (+new Date(this.time) - +new Date()) / 1000;
|
||||
break;
|
||||
default:
|
||||
seconds = Math.floor(this.time);
|
||||
}
|
||||
|
||||
if (seconds < 60) {
|
||||
if (this.relative || this.kind === 'since') {
|
||||
return $localize`:@@date-base.just-now:Just now`;
|
||||
} else if (this.kind === 'until') {
|
||||
seconds = 60;
|
||||
}
|
||||
}
|
||||
|
||||
let counter: number;
|
||||
for (const i in this.intervals) {
|
||||
if (this.kind !== 'until' || this.forceFloorOnTimeIntervals && this.forceFloorOnTimeIntervals.indexOf(i) > -1) {
|
||||
counter = Math.floor(seconds / this.intervals[i]);
|
||||
} else {
|
||||
counter = Math.round(seconds / this.intervals[i]);
|
||||
}
|
||||
const dateStrings = dates(counter);
|
||||
if (counter > 0) {
|
||||
switch (this.kind) {
|
||||
case 'since':
|
||||
if (counter === 1) {
|
||||
switch (i) { // singular (1 day)
|
||||
case 'year': return $localize`:@@time-since:${dateStrings.i18nYear}:DATE: ago`; break;
|
||||
case 'month': return $localize`:@@time-since:${dateStrings.i18nMonth}:DATE: ago`; break;
|
||||
case 'week': return $localize`:@@time-since:${dateStrings.i18nWeek}:DATE: ago`; break;
|
||||
case 'day': return $localize`:@@time-since:${dateStrings.i18nDay}:DATE: ago`; break;
|
||||
case 'hour': return $localize`:@@time-since:${dateStrings.i18nHour}:DATE: ago`; break;
|
||||
case 'minute': return $localize`:@@time-since:${dateStrings.i18nMinute}:DATE: ago`; break;
|
||||
case 'second': return $localize`:@@time-since:${dateStrings.i18nSecond}:DATE: ago`; break;
|
||||
}
|
||||
} else {
|
||||
switch (i) { // plural (2 days)
|
||||
case 'year': return $localize`:@@time-since:${dateStrings.i18nYears}:DATE: ago`; break;
|
||||
case 'month': return $localize`:@@time-since:${dateStrings.i18nMonths}:DATE: ago`; break;
|
||||
case 'week': return $localize`:@@time-since:${dateStrings.i18nWeeks}:DATE: ago`; break;
|
||||
case 'day': return $localize`:@@time-since:${dateStrings.i18nDays}:DATE: ago`; break;
|
||||
case 'hour': return $localize`:@@time-since:${dateStrings.i18nHours}:DATE: ago`; break;
|
||||
case 'minute': return $localize`:@@time-since:${dateStrings.i18nMinutes}:DATE: ago`; break;
|
||||
case 'second': return $localize`:@@time-since:${dateStrings.i18nSeconds}:DATE: ago`; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'until':
|
||||
if (counter === 1) {
|
||||
switch (i) { // singular (In ~1 day)
|
||||
case 'year': return $localize`:@@time-until:In ~${dateStrings.i18nYear}:DATE:`; break;
|
||||
case 'month': return $localize`:@@time-until:In ~${dateStrings.i18nMonth}:DATE:`; break;
|
||||
case 'week': return $localize`:@@time-until:In ~${dateStrings.i18nWeek}:DATE:`; break;
|
||||
case 'day': return $localize`:@@time-until:In ~${dateStrings.i18nDay}:DATE:`; break;
|
||||
case 'hour': return $localize`:@@time-until:In ~${dateStrings.i18nHour}:DATE:`; break;
|
||||
case 'minute': return $localize`:@@time-until:In ~${dateStrings.i18nMinute}:DATE:`;
|
||||
case 'second': return $localize`:@@time-until:In ~${dateStrings.i18nSecond}:DATE:`;
|
||||
}
|
||||
} else {
|
||||
switch (i) { // plural (In ~2 days)
|
||||
case 'year': return $localize`:@@time-until:In ~${dateStrings.i18nYears}:DATE:`; break;
|
||||
case 'month': return $localize`:@@time-until:In ~${dateStrings.i18nMonths}:DATE:`; break;
|
||||
case 'week': return $localize`:@@time-until:In ~${dateStrings.i18nWeeks}:DATE:`; break;
|
||||
case 'day': return $localize`:@@time-until:In ~${dateStrings.i18nDays}:DATE:`; break;
|
||||
case 'hour': return $localize`:@@time-until:In ~${dateStrings.i18nHours}:DATE:`; break;
|
||||
case 'minute': return $localize`:@@time-until:In ~${dateStrings.i18nMinutes}:DATE:`; break;
|
||||
case 'second': return $localize`:@@time-until:In ~${dateStrings.i18nSeconds}:DATE:`; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'span':
|
||||
if (counter === 1) {
|
||||
switch (i) { // singular (1 day)
|
||||
case 'year': return $localize`:@@time-span:After ${dateStrings.i18nYear}:DATE:`; break;
|
||||
case 'month': return $localize`:@@time-span:After ${dateStrings.i18nMonth}:DATE:`; break;
|
||||
case 'week': return $localize`:@@time-span:After ${dateStrings.i18nWeek}:DATE:`; break;
|
||||
case 'day': return $localize`:@@time-span:After ${dateStrings.i18nDay}:DATE:`; break;
|
||||
case 'hour': return $localize`:@@time-span:After ${dateStrings.i18nHour}:DATE:`; break;
|
||||
case 'minute': return $localize`:@@time-span:After ${dateStrings.i18nMinute}:DATE:`; break;
|
||||
case 'second': return $localize`:@@time-span:After ${dateStrings.i18nSecond}:DATE:`; break;
|
||||
}
|
||||
} else {
|
||||
switch (i) { // plural (2 days)
|
||||
case 'year': return $localize`:@@time-span:After ${dateStrings.i18nYears}:DATE:`; break;
|
||||
case 'month': return $localize`:@@time-span:After ${dateStrings.i18nMonths}:DATE:`; break;
|
||||
case 'week': return $localize`:@@time-span:After ${dateStrings.i18nWeeks}:DATE:`; break;
|
||||
case 'day': return $localize`:@@time-span:After ${dateStrings.i18nDays}:DATE:`; break;
|
||||
case 'hour': return $localize`:@@time-span:After ${dateStrings.i18nHours}:DATE:`; break;
|
||||
case 'minute': return $localize`:@@time-span:After ${dateStrings.i18nMinutes}:DATE:`; break;
|
||||
case 'second': return $localize`:@@time-span:After ${dateStrings.i18nSeconds}:DATE:`; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (counter === 1) {
|
||||
switch (i) { // singular (1 day)
|
||||
case 'year': return dateStrings.i18nYear; break;
|
||||
case 'month': return dateStrings.i18nMonth; break;
|
||||
case 'week': return dateStrings.i18nWeek; break;
|
||||
case 'day': return dateStrings.i18nDay; break;
|
||||
case 'hour': return dateStrings.i18nHour; break;
|
||||
case 'minute': return dateStrings.i18nMinute; break;
|
||||
case 'second': return dateStrings.i18nSecond; break;
|
||||
}
|
||||
} else {
|
||||
switch (i) { // plural (2 days)
|
||||
case 'year': return dateStrings.i18nYears; break;
|
||||
case 'month': return dateStrings.i18nMonths; break;
|
||||
case 'week': return dateStrings.i18nWeeks; break;
|
||||
case 'day': return dateStrings.i18nDays; break;
|
||||
case 'hour': return dateStrings.i18nHours; break;
|
||||
case 'minute': return dateStrings.i18nMinutes; break;
|
||||
case 'second': return dateStrings.i18nSeconds; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -57,14 +57,14 @@
|
||||
<td>
|
||||
‎{{ tx.status.block_time * 1000 | date:'yyyy-MM-dd HH:mm' }}
|
||||
<div class="lg-inline">
|
||||
<i class="symbol">(<app-time-since [time]="tx.status.block_time" [fastRender]="true"></app-time-since>)</i>
|
||||
<i class="symbol">(<app-time kind="since" [time]="tx.status.block_time" [fastRender]="true"></app-time>)</i>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<ng-template [ngIf]="transactionTime > 0">
|
||||
<tr>
|
||||
<td i18n="transaction.confirmed|Transaction Confirmed state">Confirmed</td>
|
||||
<td><app-time-span [time]="tx.status.block_time - transactionTime" [fastRender]="true"></app-time-span></td>
|
||||
<td><app-time kind="span" [time]="tx.status.block_time - transactionTime" [fastRender]="true" [relative]="true"></app-time></td>
|
||||
</tr>
|
||||
</ng-template>
|
||||
<tr *ngIf="network !== 'liquid' && network !== 'liquidtestnet'">
|
||||
@@ -100,7 +100,7 @@
|
||||
<ng-template #firstSeenTmpl>
|
||||
<tr>
|
||||
<td i18n="transaction.first-seen|Transaction first seen">First seen</td>
|
||||
<td><i><app-time-since [time]="transactionTime" [fastRender]="true"></app-time-since></i></td>
|
||||
<td><i><app-time kind="since" [time]="transactionTime" [fastRender]="true"></app-time></i></td>
|
||||
</tr>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
@@ -116,10 +116,10 @@
|
||||
</ng-template>
|
||||
<ng-template #belowBlockLimit>
|
||||
<ng-template [ngIf]="network === 'liquid' || network === 'liquidtestnet'" [ngIfElse]="timeEstimateDefault">
|
||||
<app-time-until [time]="(60 * 1000 * txInBlockIndex) + now" [fastRender]="false" [fixedRender]="true"></app-time-until>
|
||||
<app-time kind="until" [time]="(60 * 1000 * txInBlockIndex) + now" [fastRender]="false" [fixedRender]="true"></app-time>
|
||||
</ng-template>
|
||||
<ng-template #timeEstimateDefault>
|
||||
<app-time-until *ngIf="(timeAvg$ | async) as timeAvg;" [time]="(timeAvg * txInBlockIndex) + now + timeAvg" [fastRender]="false" [fixedRender]="true" [forceFloorOnTimeIntervals]="['hour']"></app-time-until>
|
||||
<app-time kind="until" *ngIf="(timeAvg$ | async) as timeAvg;" [time]="(timeAvg * txInBlockIndex) + now + timeAvg" [fastRender]="false" [fixedRender]="true" [forceFloorOnTimeIntervals]="['hour']"></app-time>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
@@ -210,6 +210,7 @@
|
||||
<div class="graph-container" #graphContainer>
|
||||
<tx-bowtie-graph
|
||||
[tx]="tx"
|
||||
[cached]="isCached"
|
||||
[width]="graphWidth"
|
||||
[height]="graphHeight"
|
||||
[lineLimit]="inOutLimit"
|
||||
@@ -250,7 +251,7 @@
|
||||
</div>
|
||||
|
||||
|
||||
<app-transactions-list #txList [transactions]="[tx]" [errorUnblinded]="errorUnblinded" [inputIndex]="inputIndex" [outputIndex]="outputIndex" [transactionPage]="true"></app-transactions-list>
|
||||
<app-transactions-list #txList [transactions]="[tx]" [cached]="isCached" [errorUnblinded]="errorUnblinded" [inputIndex]="inputIndex" [outputIndex]="outputIndex" [transactionPage]="true"></app-transactions-list>
|
||||
|
||||
<div class="title text-left">
|
||||
<h2 i18n="transaction.details">Details</h2>
|
||||
|
||||
@@ -57,6 +57,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
fetchCpfp$ = new Subject<string>();
|
||||
fetchRbfHistory$ = new Subject<string>();
|
||||
fetchCachedTx$ = new Subject<string>();
|
||||
isCached: boolean = false;
|
||||
now = new Date().getTime();
|
||||
timeAvg$: Observable<number>;
|
||||
liquidUnblinding = new LiquidUnblinding();
|
||||
@@ -196,6 +197,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
|
||||
this.tx = tx;
|
||||
this.isCached = true;
|
||||
if (tx.fee === undefined) {
|
||||
this.tx.fee = 0;
|
||||
}
|
||||
@@ -289,6 +291,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
|
||||
this.tx = tx;
|
||||
this.isCached = false;
|
||||
if (tx.fee === undefined) {
|
||||
this.tx.fee = 0;
|
||||
}
|
||||
@@ -362,7 +365,6 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.waitingForTransaction = false;
|
||||
}
|
||||
this.rbfTransaction = rbfTransaction;
|
||||
this.cacheService.setTxCache([this.rbfTransaction]);
|
||||
this.replaced = true;
|
||||
if (rbfTransaction && !this.tx) {
|
||||
this.fetchCachedTx$.next(this.txId);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div>
|
||||
<ng-template [ngIf]="tx.status.confirmed">‎{{ tx.status.block_time * 1000 | date:'yyyy-MM-dd HH:mm' }}</ng-template>
|
||||
<ng-template [ngIf]="!tx.status.confirmed && tx.firstSeen">
|
||||
<i><app-time-since [time]="tx.firstSeen" [fastRender]="true"></app-time-since></i>
|
||||
<i><app-time kind="since" [time]="tx.firstSeen" [fastRender]="true"></app-time></i>
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component, OnInit, Input, ChangeDetectionStrategy, OnChanges, Output, EventEmitter, ChangeDetectorRef } from '@angular/core';
|
||||
import { StateService } from '../../services/state.service';
|
||||
import { CacheService } from '../../services/cache.service';
|
||||
import { Observable, ReplaySubject, BehaviorSubject, merge, Subscription } from 'rxjs';
|
||||
import { Observable, ReplaySubject, BehaviorSubject, merge, Subscription, of } from 'rxjs';
|
||||
import { Outspend, Transaction, Vin, Vout } from '../../interfaces/electrs.interface';
|
||||
import { ElectrsApiService } from '../../services/electrs-api.service';
|
||||
import { environment } from '../../../environments/environment';
|
||||
@@ -23,6 +23,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
|
||||
showMoreIncrement = 1000;
|
||||
|
||||
@Input() transactions: Transaction[];
|
||||
@Input() cached: boolean = false;
|
||||
@Input() showConfirmations = false;
|
||||
@Input() transactionPage = false;
|
||||
@Input() errorUnblinded = false;
|
||||
@@ -67,7 +68,13 @@ export class TransactionsListComponent implements OnInit, OnChanges {
|
||||
this.outspendsSubscription = merge(
|
||||
this.refreshOutspends$
|
||||
.pipe(
|
||||
switchMap((txIds) => this.apiService.getOutspendsBatched$(txIds)),
|
||||
switchMap((txIds) => {
|
||||
if (!this.cached) {
|
||||
return this.apiService.getOutspendsBatched$(txIds);
|
||||
} else {
|
||||
return of([]);
|
||||
}
|
||||
}),
|
||||
tap((outspends: Outspend[][]) => {
|
||||
if (!this.transactions) {
|
||||
return;
|
||||
@@ -155,7 +162,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
|
||||
).subscribe();
|
||||
});
|
||||
const txIds = this.transactions.filter((tx) => !tx._outspends).map((tx) => tx.txid);
|
||||
if (txIds.length) {
|
||||
if (txIds.length && !this.cached) {
|
||||
this.refreshOutspends$.next(txIds);
|
||||
}
|
||||
if (this.stateService.env.LIGHTNING) {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Component, OnInit, Input, OnChanges, HostListener, Inject, LOCALE_ID }
|
||||
import { StateService } from '../../services/state.service';
|
||||
import { Outspend, Transaction } from '../../interfaces/electrs.interface';
|
||||
import { Router } from '@angular/router';
|
||||
import { ReplaySubject, merge, Subscription } from 'rxjs';
|
||||
import { ReplaySubject, merge, Subscription, of } from 'rxjs';
|
||||
import { tap, switchMap } from 'rxjs/operators';
|
||||
import { ApiService } from '../../services/api.service';
|
||||
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
|
||||
@@ -40,6 +40,7 @@ interface Xput {
|
||||
export class TxBowtieGraphComponent implements OnInit, OnChanges {
|
||||
@Input() tx: Transaction;
|
||||
@Input() network: string;
|
||||
@Input() cached: boolean = false;
|
||||
@Input() width = 1200;
|
||||
@Input() height = 600;
|
||||
@Input() lineLimit = 250;
|
||||
@@ -107,7 +108,13 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
|
||||
this.outspendsSubscription = merge(
|
||||
this.refreshOutspends$
|
||||
.pipe(
|
||||
switchMap((txid) => this.apiService.getOutspendsBatched$([txid])),
|
||||
switchMap((txid) => {
|
||||
if (!this.cached) {
|
||||
return this.apiService.getOutspendsBatched$([txid]);
|
||||
} else {
|
||||
return of(null);
|
||||
}
|
||||
}),
|
||||
tap((outspends: Outspend[][]) => {
|
||||
if (!this.tx || !outspends || !outspends.length) {
|
||||
return;
|
||||
@@ -132,7 +139,9 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
|
||||
|
||||
ngOnChanges(): void {
|
||||
this.initGraph();
|
||||
this.refreshOutspends$.next(this.tx.txid);
|
||||
if (!this.cached) {
|
||||
this.refreshOutspends$.next(this.tx.txid);
|
||||
}
|
||||
}
|
||||
|
||||
initGraph(): void {
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
<tbody>
|
||||
<tr *ngFor="let block of blocks$ | async; let i = index; trackBy: trackByBlock">
|
||||
<td class="table-cell-height" ><a [routerLink]="['/block' | relativeUrl, block.id]" [state]="{ data: { block: block } }">{{ block.height }}</a></td>
|
||||
<td *ngIf="!stateService.env.MINING_DASHBOARD" class="table-cell-mined" ><app-time-since [time]="block.timestamp" [fastRender]="true"></app-time-since></td>
|
||||
<td *ngIf="!stateService.env.MINING_DASHBOARD" class="table-cell-mined" ><app-time kind="since" [time]="block.timestamp" [fastRender]="true"></app-time></td>
|
||||
<td *ngIf="stateService.env.MINING_DASHBOARD" class="table-cell-mined pl-lg-4">
|
||||
<a class="clear-link" [routerLink]="[('/mining/pool/' + block.extras.pool.slug) | relativeUrl]">
|
||||
<img width="22" height="22" src="{{ block.extras.pool['logo'] }}"
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
<div class="doc-content">
|
||||
|
||||
<div id="disclaimer">
|
||||
<table><tr><td><svg viewBox="0 0 304 304" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd" style="fill:#ffc107;fill-opacity:1"><path d="M135.3 34.474c-15.62 27.306-54.206 95.63-85.21 150.534L9.075 257.583C5.382 264.08 6.76 269.217 7.908 271.7c2.326 5.028 7.29 7.537 11.155 8.215l.78.133 264.698.006-.554-.02c4.152.255 9.664-1.24 12.677-6.194 1.926-3.18 3.31-8.589-1.073-16.278L213.637 114.37l-45.351-79.205c-5.681-9.932-12.272-12.022-16.8-12.022-4.42 0-10.818 1.964-16.181 11.331h-.006zm-69.072 159.94c30.997-54.885 69.563-123.184 85.16-150.446l.186-.297c.2.303.393.582.618.981l45.363 79.22s72.377 126.47 78.569 137.283l-247.618-.007 37.719-66.734" style="fill:#ffc107;fill-opacity:1"/><path d="M152.597 247.445c8.02 0 14.518-6.728 14.518-15.025 0-8.29-6.499-15.018-14.518-15.018-8.031 0-14.529 6.728-14.529 15.018 0 8.297 6.498 15.025 14.53 15.025m-.001-147.18c11.586 0 22.23 10.958 20.977 21.7l-9.922 75.564c-.966 6.601-4.95 11.433-11.055 11.433s-10.102-4.832-11.056-11.433l-9.927-75.564c-1.26-10.742 9.39-21.7 20.983-21.7" style="fill:#ffc107;fill-opacity:1"/></g></svg></td><td><p i18n="faq.big-disclaimer"><b>mempool.space merely provides data about the Bitcoin network.</b> It cannot help you with retrieving funds, confirming your transaction quicker, etc.</p><p>For any such requests, you need to get in touch with the entity that helped make the transaction (wallet software, exchange company, etc).</p></td></tr></table>
|
||||
<table *ngIf="!mobileViewport"><tr><td><app-svg-images name="warning" class="disclaimer-warning" viewBox="0 0 304 304" fill="#ffc107" width="50" height="50"></app-svg-images></td><td><p i18n="faq.big-disclaimer"><b>mempool.space merely provides data about the Bitcoin network.</b> It cannot help you with retrieving funds, confirming your transaction quicker, etc.</p><p>For any such requests, you need to get in touch with the entity that helped make the transaction (wallet software, exchange company, etc).</p></td></tr></table>
|
||||
<div *ngIf="mobileViewport"><app-svg-images name="warning" class="disclaimer-warning" viewBox="0 0 304 304" fill="#ffc107" width="50" height="50"></app-svg-images><p i18n="faq.big-disclaimer"><b>mempool.space merely provides data about the Bitcoin network.</b> It cannot help you with retrieving funds, confirming your transaction quicker, etc.</p><p>For any such requests, you need to get in touch with the entity that helped make the transaction (wallet software, exchange company, etc).</p></div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -274,10 +274,8 @@ h3 {
|
||||
margin: 24px 0;
|
||||
}
|
||||
|
||||
#disclaimer svg {
|
||||
width: 50px;
|
||||
height: auto;
|
||||
margin-right: 32px;
|
||||
.disclaimer-warning {
|
||||
margin-right: 50px;
|
||||
}
|
||||
|
||||
#disclaimer p:last-child {
|
||||
@@ -294,6 +292,12 @@ h3 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.disclaimer-warning {
|
||||
display: block;
|
||||
margin: 2px auto 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.doc-content {
|
||||
width: 100%;
|
||||
float: unset;
|
||||
@@ -332,6 +336,10 @@ h3 {
|
||||
.doc-welcome-note {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
#disclaimer table {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
|
||||
@@ -29,6 +29,7 @@ export class ApiDocsComponent implements OnInit, AfterViewInit {
|
||||
screenWidth: number;
|
||||
officialMempoolInstance: boolean;
|
||||
auditEnabled: boolean;
|
||||
mobileViewport: boolean = false;
|
||||
|
||||
@ViewChildren(FaqTemplateDirective) faqTemplates: QueryList<FaqTemplateDirective>;
|
||||
dict = {};
|
||||
@@ -43,6 +44,7 @@ export class ApiDocsComponent implements OnInit, AfterViewInit {
|
||||
this.faqTemplates.forEach((x) => this.dict[x.type] = x.template);
|
||||
}
|
||||
this.desktopDocsNavPosition = ( window.pageYOffset > 182 ) ? "fixed" : "relative";
|
||||
this.mobileViewport = window.innerWidth <= 992;
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<span class="green-color" *ngIf="blockConversion; else noblockconversion">
|
||||
{{
|
||||
(
|
||||
(blockConversion.price[currency] >= 0 ? blockConversion.price[currency] : null) ??
|
||||
(blockConversion.price['USD'] * blockConversion.exchangeRates['USD' + currency]) ?? 0
|
||||
(blockConversion.price[currency] > -1 ? blockConversion.price[currency] : null) ??
|
||||
(blockConversion.price['USD'] > -1 ? blockConversion.price['USD'] * blockConversion.exchangeRates['USD' + currency] : null) ?? 0
|
||||
) * value / 100000000 | fiatCurrency : digitsInfo : currency
|
||||
}}
|
||||
</span>
|
||||
|
||||
<ng-template #noblockconversion>
|
||||
<span class="green-color" *ngIf="(conversions$ | async) as conversions">
|
||||
{{ (conversions[currency] ?? conversions['USD'] ?? 0) * value / 100000000 | fiatCurrency : digitsInfo : currency }}
|
||||
{{ (conversions[currency] > -1 ? conversions[currency] : 0) * value / 100000000 | fiatCurrency : digitsInfo : currency }}
|
||||
</span>
|
||||
</ng-template>
|
||||
@@ -20,7 +20,7 @@
|
||||
<div class="clearfix"></div>
|
||||
|
||||
<div *ngIf="error" class="d-flex flex-column justify-content-around align-items-center mt-5 w-100" style="min-height: 100px">
|
||||
<span class="text-center" i18n="lightning.channel-not-found">No channel found for short id "{{ channel.short_id }}"</span>
|
||||
<span class="text-center">No channel found for ID "{{ channel.short_id }}"</span>
|
||||
</div>
|
||||
|
||||
<app-nodes-channels-map *ngIf="!error && (channelGeo$ | async) as channelGeo" [style]="'channelpage'"
|
||||
|
||||
@@ -78,5 +78,5 @@ h3 {
|
||||
|
||||
.details-button {
|
||||
align-self: center;
|
||||
margin-left: auto;
|
||||
margin-inline-start: auto;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
:host-context(.rtl-layout) .formRadioGroup {
|
||||
direction: ltr;
|
||||
@media (min-width: 435px) {
|
||||
right: unset;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
@media (max-width: 435px) {
|
||||
flex-grow: 1;
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
</ng-template>
|
||||
<input type="text" class="form-control" aria-label="Text input with dropdown button"
|
||||
[value]="node.socketsObject[selectedSocketIndex].socket">
|
||||
<button class="btn btn-secondary ml-1" type="button" id="inputGroupFileAddon04" (mouseover)="qrCodeVisible[i] = 1"
|
||||
<button class="btn btn-secondary" type="button" id="inputGroupFileAddon04" (mouseover)="qrCodeVisible[i] = 1"
|
||||
(mouseout)="qrCodeVisible[i] = 0">
|
||||
<fa-icon [icon]="['fas', 'qrcode']" [fixedWidth]="true"></fa-icon>
|
||||
<div class="qr-wrapper" [hidden]="!qrCodeVisible[i]">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-left: 15px;
|
||||
margin-inline-start: 15px;
|
||||
}
|
||||
|
||||
.qr-wrapper {
|
||||
@@ -57,3 +57,17 @@ h1 {
|
||||
.description-text {
|
||||
white-space: break-spaces;
|
||||
}
|
||||
|
||||
.timestamp-first .input-group {
|
||||
input {
|
||||
margin-inline-end: .25rem;
|
||||
}
|
||||
}
|
||||
|
||||
:host-context(.rtl-layout) {
|
||||
.timestamp-first .input-group {
|
||||
button {
|
||||
margin-inline-end: .25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
<div class="clearfix"></div>
|
||||
|
||||
<div *ngIf="error" class="d-flex flex-column justify-content-around align-items-center mt-5 w-100" style="min-height: 100px">
|
||||
<span class="text-center" i18n="lightning.node-not-found">No node found for public key "{{ node.public_key | shortenString : 12}}"</span>
|
||||
<span class="text-center">No node found for public key "{{ node.public_key | shortenString : 12}}"</span>
|
||||
</div>
|
||||
|
||||
<div class="box" *ngIf="!error">
|
||||
@@ -57,7 +57,7 @@
|
||||
</tr>
|
||||
<tr *ngIf="(avgChannelDistance$ | async) as avgDistance;">
|
||||
<td i18n="lightning.avg-distance" class="text-truncate">Avg channel distance</td>
|
||||
<td>{{ avgDistance | number : '1.0-0' }} <span class="symbol">km</span> <span class="separator">/</span> {{ kmToMiles(avgDistance) | number : '1.0-0' }} <span class="symbol">mi</span></td>
|
||||
<td class="direction-ltr">{{ avgDistance | number : '1.0-0' }} <span class="symbol">km</span> <span class="separator">/</span> {{ kmToMiles(avgDistance) | number : '1.0-0' }} <span class="symbol">mi</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -4,10 +4,6 @@
|
||||
&.widget {
|
||||
height: 250px;
|
||||
}
|
||||
|
||||
&.graph {
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.card-header {
|
||||
|
||||
@@ -229,6 +229,7 @@ export class NodesChannelsMap implements OnInit {
|
||||
title: title ?? undefined,
|
||||
tooltip: {},
|
||||
geo: {
|
||||
top: 75,
|
||||
animation: false,
|
||||
silent: true,
|
||||
center: this.center,
|
||||
|
||||
@@ -53,31 +53,6 @@
|
||||
height: 145px;
|
||||
}
|
||||
|
||||
.formRadioGroup {
|
||||
margin-top: 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@media (min-width: 991px) {
|
||||
position: relative;
|
||||
top: -100px;
|
||||
}
|
||||
@media (min-width: 830px) and (max-width: 991px) {
|
||||
position: relative;
|
||||
top: 0px;
|
||||
}
|
||||
@media (min-width: 830px) {
|
||||
flex-direction: row;
|
||||
float: right;
|
||||
margin-top: 0px;
|
||||
}
|
||||
.btn-sm {
|
||||
font-size: 9px;
|
||||
@media (min-width: 830px) {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pool-distribution {
|
||||
min-height: 56px;
|
||||
display: block;
|
||||
|
||||
@@ -182,7 +182,7 @@ export class NodesNetworksChartComponent implements OnInit {
|
||||
{
|
||||
zlevel: 1,
|
||||
yAxisIndex: 0,
|
||||
name: $localize`Clearnet (IPv4, IPv6)`,
|
||||
name: $localize`Clearnet Only (IPv4, IPv6)`,
|
||||
showSymbol: false,
|
||||
symbol: 'none',
|
||||
data: data.clearnet_nodes,
|
||||
@@ -292,7 +292,7 @@ export class NodesNetworksChartComponent implements OnInit {
|
||||
icon: 'roundRect',
|
||||
},
|
||||
{
|
||||
name: $localize`Clearnet (IPv4, IPv6)`,
|
||||
name: $localize`Clearnet Only (IPv4, IPv6)`,
|
||||
inactiveColor: 'rgb(110, 112, 121)',
|
||||
textStyle: {
|
||||
color: 'white',
|
||||
@@ -318,7 +318,7 @@ export class NodesNetworksChartComponent implements OnInit {
|
||||
],
|
||||
selected: this.widget ? undefined : JSON.parse(this.storageService.getValue('nodes_networks_legend')) ?? {
|
||||
'$localize`Darknet Only (Tor, I2P, cjdns)`': true,
|
||||
'$localize`Clearnet (IPv4, IPv6)`': true,
|
||||
'$localize`Clearnet Only (IPv4, IPv6)`': true,
|
||||
'$localize`Clearnet and Darknet`': true,
|
||||
'$localize`:@@e5d8bb389c702588877f039d72178f219453a72d:Unknown`': true,
|
||||
}
|
||||
|
||||
@@ -34,31 +34,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.formRadioGroup {
|
||||
margin-top: 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@media (min-width: 991px) {
|
||||
position: relative;
|
||||
top: -100px;
|
||||
}
|
||||
@media (min-width: 830px) and (max-width: 991px) {
|
||||
position: relative;
|
||||
top: 0px;
|
||||
}
|
||||
@media (min-width: 830px) {
|
||||
flex-direction: row;
|
||||
float: right;
|
||||
margin-top: 0px;
|
||||
}
|
||||
.btn-sm {
|
||||
font-size: 9px;
|
||||
@media (min-width: 830px) {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-padding {
|
||||
@media (max-width: 992px) {
|
||||
padding-bottom: 65px
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<th class="pool text-left" i18n="nodes.alias" [ngClass]="{'widget': widget}">Alias</th>
|
||||
<th class="liquidity text-right" i18n="node.channels">Channels</th>
|
||||
<th *ngIf="!widget" class="d-none d-md-table-cell channels text-right" i18n="lightning.channels">Capacity</th>
|
||||
<th *ngIf="!widget" class="d-none d-md-table-cell text-right" i18n="node.liquidity">{{ currency$ | async }}</th>
|
||||
<th *ngIf="!widget" class="d-none d-md-table-cell text-right">{{ currency$ | async }}</th>
|
||||
<th *ngIf="!widget" class="d-none d-md-table-cell timestamp text-right" i18n="transaction.first-seen|Transaction first seen">First seen</th>
|
||||
<th *ngIf="!widget" class="d-none d-md-table-cell timestamp text-right" i18n="lightning.last_update">Last update</th>
|
||||
<th class="geolocation d-table-cell text-right" i18n="lightning.location">Location</th>
|
||||
|
||||
@@ -53,31 +53,6 @@
|
||||
height: 145px;
|
||||
}
|
||||
|
||||
.formRadioGroup {
|
||||
margin-top: 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@media (min-width: 991px) {
|
||||
position: relative;
|
||||
top: -100px;
|
||||
}
|
||||
@media (min-width: 830px) and (max-width: 991px) {
|
||||
position: relative;
|
||||
top: 0px;
|
||||
}
|
||||
@media (min-width: 830px) {
|
||||
flex-direction: row;
|
||||
float: right;
|
||||
margin-top: 0px;
|
||||
}
|
||||
.btn-sm {
|
||||
font-size: 9px;
|
||||
@media (min-width: 830px) {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pool-distribution {
|
||||
min-height: 56px;
|
||||
display: block;
|
||||
|
||||
@@ -89,7 +89,7 @@ export class PriceService {
|
||||
return this.singlePriceObservable$.pipe(
|
||||
map((conversion) => {
|
||||
if (conversion.prices.length <= 0) {
|
||||
return this.getEmptyPrice();
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
price: {
|
||||
@@ -113,7 +113,7 @@ export class PriceService {
|
||||
|
||||
return this.priceObservable$.pipe(
|
||||
map((conversion) => {
|
||||
if (!blockTimestamp) {
|
||||
if (!blockTimestamp || !conversion) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
<span *ngIf="seconds !== undefined">
|
||||
‎{{ seconds * 1000 | date: customFormat ?? 'yyyy-MM-dd HH:mm' }}
|
||||
<div class="lg-inline" *ngIf="!hideTimeSince">
|
||||
<i class="symbol">(<app-time-since [time]="seconds" [fastRender]="true"></app-time-since>)</i>
|
||||
<i class="symbol">(<app-time kind="since" [time]="seconds" [fastRender]="true"></app-time>)</i>
|
||||
</div>
|
||||
</span>
|
||||
|
||||
@@ -25,8 +25,7 @@ import { BytesPipe } from './pipes/bytes-pipe/bytes.pipe';
|
||||
import { WuBytesPipe } from './pipes/bytes-pipe/wubytes.pipe';
|
||||
import { FiatCurrencyPipe } from './pipes/fiat-currency.pipe';
|
||||
import { BlockchainComponent } from '../components/blockchain/blockchain.component';
|
||||
import { TimeSinceComponent } from '../components/time-since/time-since.component';
|
||||
import { TimeUntilComponent } from '../components/time-until/time-until.component';
|
||||
import { TimeComponent } from '../components/time/time.component';
|
||||
import { ClipboardComponent } from '../components/clipboard/clipboard.component';
|
||||
import { QrcodeComponent } from '../components/qrcode/qrcode.component';
|
||||
import { FiatComponent } from '../fiat/fiat.component';
|
||||
@@ -53,7 +52,6 @@ import { AddressComponent } from '../components/address/address.component';
|
||||
import { SearchFormComponent } from '../components/search-form/search-form.component';
|
||||
import { AddressLabelsComponent } from '../components/address-labels/address-labels.component';
|
||||
import { FooterComponent } from '../components/footer/footer.component';
|
||||
import { TimeSpanComponent } from '../components/time-span/time-span.component';
|
||||
import { AssetComponent } from '../components/asset/asset.component';
|
||||
import { AssetsComponent } from '../components/assets/assets.component';
|
||||
import { AssetsNavComponent } from '../components/assets/assets-nav/assets-nav.component';
|
||||
@@ -88,8 +86,7 @@ import { GeolocationComponent } from '../shared/components/geolocation/geolocati
|
||||
@NgModule({
|
||||
declarations: [
|
||||
ClipboardComponent,
|
||||
TimeSinceComponent,
|
||||
TimeUntilComponent,
|
||||
TimeComponent,
|
||||
QrcodeComponent,
|
||||
FiatComponent,
|
||||
TxFeaturesComponent,
|
||||
@@ -129,7 +126,6 @@ import { GeolocationComponent } from '../shared/components/geolocation/geolocati
|
||||
TransactionsListComponent,
|
||||
AddressComponent,
|
||||
SearchFormComponent,
|
||||
TimeSpanComponent,
|
||||
AddressLabelsComponent,
|
||||
FooterComponent,
|
||||
AssetComponent,
|
||||
@@ -195,8 +191,7 @@ import { GeolocationComponent } from '../shared/components/geolocation/geolocati
|
||||
NgbCollapseModule,
|
||||
InfiniteScrollModule,
|
||||
FontAwesomeModule,
|
||||
TimeSinceComponent,
|
||||
TimeUntilComponent,
|
||||
TimeComponent,
|
||||
ClipboardComponent,
|
||||
QrcodeComponent,
|
||||
FiatComponent,
|
||||
@@ -232,7 +227,6 @@ import { GeolocationComponent } from '../shared/components/geolocation/geolocati
|
||||
TransactionsListComponent,
|
||||
AddressComponent,
|
||||
SearchFormComponent,
|
||||
TimeSpanComponent,
|
||||
AddressLabelsComponent,
|
||||
FooterComponent,
|
||||
AssetComponent,
|
||||
|
||||
Reference in New Issue
Block a user