Merge pull request #5149 from mempool/mononaut/accurate-timestamps-hover
Accurate timestamps on hover
This commit is contained in:
		
						commit
						8382a27a7c
					
				| @ -27,6 +27,7 @@ import { ShortenStringPipe } from './shared/pipes/shorten-string-pipe/shorten-st | |||||||
| import { CapAddressPipe } from './shared/pipes/cap-address-pipe/cap-address-pipe'; | import { CapAddressPipe } from './shared/pipes/cap-address-pipe/cap-address-pipe'; | ||||||
| import { AppPreloadingStrategy } from './app.preloading-strategy'; | import { AppPreloadingStrategy } from './app.preloading-strategy'; | ||||||
| import { ServicesApiServices } from './services/services-api.service'; | import { ServicesApiServices } from './services/services-api.service'; | ||||||
|  | import { DatePipe } from '@angular/common'; | ||||||
| 
 | 
 | ||||||
| const providers = [ | const providers = [ | ||||||
|   ElectrsApiService, |   ElectrsApiService, | ||||||
| @ -45,6 +46,7 @@ const providers = [ | |||||||
|   FiatShortenerPipe, |   FiatShortenerPipe, | ||||||
|   FiatCurrencyPipe, |   FiatCurrencyPipe, | ||||||
|   CapAddressPipe, |   CapAddressPipe, | ||||||
|  |   DatePipe, | ||||||
|   AppPreloadingStrategy, |   AppPreloadingStrategy, | ||||||
|   ServicesApiServices, |   ServicesApiServices, | ||||||
|   PreloadService, |   PreloadService, | ||||||
|  | |||||||
| @ -35,7 +35,7 @@ | |||||||
|               {{ (acceleration.feeDelta) | number }} <span class="symbol" i18n="shared.sat|sat">sat</span> |               {{ (acceleration.feeDelta) | number }} <span class="symbol" i18n="shared.sat|sat">sat</span> | ||||||
|             </td> |             </td> | ||||||
|             <td class="time text-right"> |             <td class="time text-right"> | ||||||
|               <app-time kind="since" [time]="acceleration.added" [fastRender]="true"></app-time> |               <app-time kind="since" [time]="acceleration.added" [fastRender]="true" [showTooltip]="true"></app-time> | ||||||
|             </td> |             </td> | ||||||
|           </ng-container> |           </ng-container> | ||||||
|           <ng-container *ngIf="!pending"> |           <ng-container *ngIf="!pending"> | ||||||
| @ -55,7 +55,7 @@ | |||||||
|               <span *ngIf="acceleration.status.includes('failed')" class="badge badge-danger" i18n="accelerator.canceled">Failed <span *ngIf="acceleration.status === 'failed_provisional'">🔄</span></span> |               <span *ngIf="acceleration.status.includes('failed')" class="badge badge-danger" i18n="accelerator.canceled">Failed <span *ngIf="acceleration.status === 'failed_provisional'">🔄</span></span> | ||||||
|             </td> |             </td> | ||||||
|             <td class="date text-right" *ngIf="!this.widget"> |             <td class="date text-right" *ngIf="!this.widget"> | ||||||
|               <app-time kind="since" [time]="acceleration.added" [fastRender]="true"></app-time> |               <app-time kind="since" [time]="acceleration.added" [fastRender]="true" [showTooltip]="true"></app-time> | ||||||
|             </td> |             </td> | ||||||
|           </ng-container> |           </ng-container> | ||||||
|         </tr> |         </tr> | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ | |||||||
|       </td> |       </td> | ||||||
|       <td class="table-cell-satoshis"><app-amount [satoshis]="transaction.value" digitsInfo="1.2-4" [noFiat]="true"></app-amount></td> |       <td class="table-cell-satoshis"><app-amount [satoshis]="transaction.value" digitsInfo="1.2-4" [noFiat]="true"></app-amount></td> | ||||||
|       <td class="table-cell-fiat" ><app-fiat [value]="transaction.value" [blockConversion]="transaction.price" digitsInfo="1.0-0"></app-fiat></td> |       <td class="table-cell-fiat" ><app-fiat [value]="transaction.value" [blockConversion]="transaction.price" digitsInfo="1.0-0"></app-fiat></td> | ||||||
|       <td class="table-cell-date"><app-time kind="since" [time]="transaction.time" [fastRender]="true"></app-time></td> |       <td class="table-cell-date"><app-time kind="since" [time]="transaction.time" [fastRender]="true" [showTooltip]="true"></app-time></td> | ||||||
|     </tr> |     </tr> | ||||||
|   </tbody> |   </tbody> | ||||||
|   <div class=""> </div> |   <div class=""> </div> | ||||||
|  | |||||||
| @ -158,7 +158,7 @@ | |||||||
|                   <tbody *ngIf="blocks$ | async as blocks; else blocksSkeleton"> |                   <tbody *ngIf="blocks$ | async as blocks; else blocksSkeleton"> | ||||||
|                     <tr *ngFor="let block of blocks; let i = index; trackBy: trackByBlock"> |                     <tr *ngFor="let block of blocks; 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 class="table-cell-height" ><a [routerLink]="['/block' | relativeUrl, block.id]" [state]="{ data: { block: block } }">{{ block.height }}</a></td> | ||||||
|                       <td class="table-cell-mined" ><app-time kind="since" [time]="block.timestamp" [fastRender]="true"></app-time></td> |                       <td class="table-cell-mined" ><app-time kind="since" [time]="block.timestamp" [fastRender]="true" [showTooltip]="true"></app-time></td> | ||||||
|                       <td class="table-cell-transaction-count">{{ block.tx_count | number }}</td> |                       <td class="table-cell-transaction-count">{{ block.tx_count | number }}</td> | ||||||
|                       <td class="table-cell-size"> |                       <td class="table-cell-size"> | ||||||
|                         <div class="progress"> |                         <div class="progress"> | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ | |||||||
|           <a [routerLink]="['/block' | relativeUrl, diffChange.height]">{{ diffChange.height }}</a> |           <a [routerLink]="['/block' | relativeUrl, diffChange.height]">{{ diffChange.height }}</a> | ||||||
|         </td> |         </td> | ||||||
|         <td class="date text-left"> |         <td class="date text-left"> | ||||||
|           <app-time kind="since" [time]="diffChange.timestamp" [fastRender]="true" [precision]="1"></app-time> |           <app-time kind="since" [time]="diffChange.timestamp" [fastRender]="true" [precision]="1" [showTooltip]="true"></app-time> | ||||||
|         </td> |         </td> | ||||||
|         <td class="text-right">{{ diffChange.difficultyShorten }}</td> |         <td class="text-right">{{ diffChange.difficultyShorten }}</td> | ||||||
|         <td class="text-right" [style]="diffChange.change >= 0 ? 'color: #42B747' : 'color: #B74242'"> |         <td class="text-right" [style]="diffChange.change >= 0 ? 'color: #42B747' : 'color: #B74242'"> | ||||||
|  | |||||||
| @ -26,7 +26,7 @@ | |||||||
|               <app-amount [satoshis]="utxo.amount" [noFiat]="true" [forceBtc]="true"></app-amount> |               <app-amount [satoshis]="utxo.amount" [noFiat]="true" [forceBtc]="true"></app-amount> | ||||||
|             </td> |             </td> | ||||||
|             <td class="timestamp text-left widget"> |             <td class="timestamp text-left widget"> | ||||||
|               <app-time kind="since" [time]="utxo.blocktime"></app-time> |               <app-time kind="since" [time]="utxo.blocktime" [showTooltip]="true"></app-time> | ||||||
|             </td> |             </td> | ||||||
|           </tr> |           </tr> | ||||||
|         </ng-container> |         </ng-container> | ||||||
|  | |||||||
| @ -31,7 +31,7 @@ | |||||||
|               </ng-container> |               </ng-container> | ||||||
|             </td> |             </td> | ||||||
|             <td class="timestamp text-left widget"> |             <td class="timestamp text-left widget"> | ||||||
|               <app-time kind="since" [time]="peg.blocktime"></app-time> |               <app-time kind="since" [time]="peg.blocktime" [showTooltip]="true"></app-time> | ||||||
|             </td> |             </td> | ||||||
|             <td class="amount text-right widget" [ngClass]="{'credit': peg.amount > 0, 'debit': peg.amount < 0, 'glow-effect': peg.amount < 0 && peg.bitcoinaddress && !peg.bitcointxid}"> |             <td class="amount text-right widget" [ngClass]="{'credit': peg.amount > 0, 'debit': peg.amount < 0, 'glow-effect': peg.amount < 0 && peg.bitcoinaddress && !peg.bitcointxid}"> | ||||||
|               <app-amount [satoshis]="peg.amount" [noFiat]="true" [forceBtc]="true" [addPlus]="true"></app-amount> |               <app-amount [satoshis]="peg.amount" [noFiat]="true" [forceBtc]="true" [addPlus]="true"></app-amount> | ||||||
|  | |||||||
| @ -197,7 +197,7 @@ | |||||||
|             ‎{{ block.timestamp * 1000 | date:'yyyy-MM-dd HH:mm:ss' }} |             ‎{{ block.timestamp * 1000 | date:'yyyy-MM-dd HH:mm:ss' }} | ||||||
|           </td> |           </td> | ||||||
|           <td class="mined"> |           <td class="mined"> | ||||||
|             <app-time kind="since" [time]="block.timestamp" [fastRender]="true"></app-time> |             <app-time kind="since" [time]="block.timestamp" [fastRender]="true" [showTooltip]="true"></app-time> | ||||||
|           </td> |           </td> | ||||||
|           <td class="coinbase"> |           <td class="coinbase"> | ||||||
|             <span class="badge badge-secondary scriptmessage longer"> |             <span class="badge badge-secondary scriptmessage longer"> | ||||||
|  | |||||||
| @ -23,7 +23,7 @@ | |||||||
|             <span *ngIf="tree.mined" class="badge badge-success" i18n="transaction.rbf.mined">Mined</span> |             <span *ngIf="tree.mined" class="badge badge-success" i18n="transaction.rbf.mined">Mined</span> | ||||||
|             <span *ngIf="tree.fullRbf" class="badge badge-info" i18n="transaction.full-rbf">Full RBF</span> |             <span *ngIf="tree.fullRbf" class="badge badge-info" i18n="transaction.full-rbf">Full RBF</span> | ||||||
|           </span> |           </span> | ||||||
|           <app-time kind="since" [time]="tree.time"></app-time> |           <app-time kind="since" [time]="tree.time" [showTooltip]="true"></app-time> | ||||||
|         </p> |         </p> | ||||||
|         <div class="timeline-wrapper" [class.mined]="tree.mined"> |         <div class="timeline-wrapper" [class.mined]="tree.mined"> | ||||||
|           <app-rbf-timeline [replacements]="tree"></app-rbf-timeline> |           <app-rbf-timeline [replacements]="tree"></app-rbf-timeline> | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								frontend/src/app/components/time/time.component.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								frontend/src/app/components/time/time.component.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | <span [ngbTooltip]="tooltip">{{ text }}</span> | ||||||
| @ -1,15 +1,17 @@ | |||||||
| import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Input, ChangeDetectorRef, OnChanges } from '@angular/core'; | import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Input, ChangeDetectorRef, OnChanges } from '@angular/core'; | ||||||
| import { StateService } from '../../services/state.service'; | import { StateService } from '../../services/state.service'; | ||||||
| import { dates } from '../../shared/i18n/dates'; | import { dates } from '../../shared/i18n/dates'; | ||||||
|  | import { DatePipe } from '@angular/common'; | ||||||
| 
 | 
 | ||||||
| @Component({ | @Component({ | ||||||
|   selector: 'app-time', |   selector: 'app-time', | ||||||
|   template: `{{ text }}`, |   templateUrl: './time.component.html', | ||||||
|   changeDetection: ChangeDetectionStrategy.OnPush |   changeDetection: ChangeDetectionStrategy.OnPush | ||||||
| }) | }) | ||||||
| export class TimeComponent implements OnInit, OnChanges, OnDestroy { | export class TimeComponent implements OnInit, OnChanges, OnDestroy { | ||||||
|   interval: number; |   interval: number; | ||||||
|   text: string; |   text: string; | ||||||
|  |   tooltip: string; | ||||||
|   precisionThresholds = { |   precisionThresholds = { | ||||||
|     year: 100, |     year: 100, | ||||||
|     month: 18, |     month: 18, | ||||||
| @ -26,6 +28,7 @@ export class TimeComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|   @Input() kind: 'plain' | 'since' | 'until' | 'span' | 'before' | 'within' = 'plain'; |   @Input() kind: 'plain' | 'since' | 'until' | 'span' | 'before' | 'within' = 'plain'; | ||||||
|   @Input() fastRender = false; |   @Input() fastRender = false; | ||||||
|   @Input() fixedRender = false; |   @Input() fixedRender = false; | ||||||
|  |   @Input() showTooltip = false; | ||||||
|   @Input() relative = false; |   @Input() relative = false; | ||||||
|   @Input() precision: number = 0; |   @Input() precision: number = 0; | ||||||
|   @Input() numUnits: number = 1; |   @Input() numUnits: number = 1; | ||||||
| @ -36,6 +39,7 @@ export class TimeComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|   constructor( |   constructor( | ||||||
|     private ref: ChangeDetectorRef, |     private ref: ChangeDetectorRef, | ||||||
|     private stateService: StateService, |     private stateService: StateService, | ||||||
|  |     private datePipe: DatePipe, | ||||||
|   ) { |   ) { | ||||||
|       this.intervals = { |       this.intervals = { | ||||||
|         year: 31536000, |         year: 31536000, | ||||||
| @ -78,13 +82,20 @@ export class TimeComponent implements OnInit, OnChanges, OnDestroy { | |||||||
|     switch (this.kind) { |     switch (this.kind) { | ||||||
|       case 'since': |       case 'since': | ||||||
|         seconds = Math.floor((+new Date() - +new Date(this.dateString || this.time * 1000)) / 1000); |         seconds = Math.floor((+new Date() - +new Date(this.dateString || this.time * 1000)) / 1000); | ||||||
|  |         this.tooltip = this.datePipe.transform(new Date(this.dateString || this.time * 1000), 'yyyy-MM-dd HH:mm'); | ||||||
|         break; |         break; | ||||||
|       case 'until': |       case 'until': | ||||||
|       case 'within': |       case 'within': | ||||||
|         seconds = (+new Date(this.time) - +new Date()) / 1000; |         seconds = (+new Date(this.time) - +new Date()) / 1000; | ||||||
|  |         this.tooltip = this.datePipe.transform(new Date(this.time), 'yyyy-MM-dd HH:mm'); | ||||||
|         break; |         break; | ||||||
|       default: |       default: | ||||||
|         seconds = Math.floor(this.time); |         seconds = Math.floor(this.time); | ||||||
|  |         this.tooltip = ''; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (!this.showTooltip || this.relative) { | ||||||
|  |       this.tooltip = ''; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (seconds < 1 && this.kind === 'span') { |     if (seconds < 1 && this.kind === 'span') { | ||||||
|  | |||||||
| @ -59,7 +59,7 @@ | |||||||
|             <div class="label" i18n="transaction.first-seen|Transaction first seen">First seen</div> |             <div class="label" i18n="transaction.first-seen|Transaction first seen">First seen</div> | ||||||
|             <div class="value"> |             <div class="value"> | ||||||
|               @if (transactionTime > 0) { |               @if (transactionTime > 0) { | ||||||
|                 <i><app-time kind="since" [time]="transactionTime" [fastRender]="true"></app-time></i> |                 <i><app-time kind="since" [time]="transactionTime" [fastRender]="true" [showTooltip]="true"></app-time></i> | ||||||
|               } @else { |               } @else { | ||||||
|                 <span class="skeleton-loader" style="max-width: 50%;"></span> |                 <span class="skeleton-loader" style="max-width: 50%;"></span> | ||||||
|               } |               } | ||||||
| @ -86,7 +86,7 @@ | |||||||
|             <div class="value"> |             <div class="value"> | ||||||
|               ‎{{ tx.status.block_time * 1000 | date:'yyyy-MM-dd HH:mm' }} |               ‎{{ tx.status.block_time * 1000 | date:'yyyy-MM-dd HH:mm' }} | ||||||
|               <div class="lg-inline"> |               <div class="lg-inline"> | ||||||
|                 <i class="symbol">(<app-time kind="since" [time]="tx.status.block_time" [fastRender]="true"></app-time>)</i> |                 <i class="symbol">(<app-time kind="since" [time]="tx.status.block_time" [fastRender]="true" [showTooltip]="true"></app-time>)</i> | ||||||
|               </div> |               </div> | ||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|  | |||||||
| @ -450,7 +450,7 @@ | |||||||
|     @if (transactionTime > 0) { |     @if (transactionTime > 0) { | ||||||
|       <tr> |       <tr> | ||||||
|         <td i18n="transaction.confirmed|Transaction Confirmed state">Confirmed</td> |         <td i18n="transaction.confirmed|Transaction Confirmed state">Confirmed</td> | ||||||
|         <td><app-time kind="span" [time]="tx.status.block_time - transactionTime" [fastRender]="true" [relative]="true"></app-time></td> |         <td><app-time kind="span" [time]="tx.status.block_time" [fastRender]="true" [showTooltip]="true"></app-time></td> | ||||||
|       </tr> |       </tr> | ||||||
|     } |     } | ||||||
|   } @else { |   } @else { | ||||||
| @ -464,7 +464,7 @@ | |||||||
|   } @else if (transactionTime > 0) { |   } @else if (transactionTime > 0) { | ||||||
|     <tr> |     <tr> | ||||||
|       <td i18n="transaction.first-seen|Transaction first seen">First seen</td> |       <td i18n="transaction.first-seen|Transaction first seen">First seen</td> | ||||||
|       <td><i><app-time kind="since" [time]="transactionTime" [fastRender]="true"></app-time></i></td> |       <td><i><app-time kind="since" [time]="transactionTime" [fastRender]="true" [showTooltip]="true"></app-time></i></td> | ||||||
|     </tr> |     </tr> | ||||||
|   } @else { |   } @else { | ||||||
|     <tr> |     <tr> | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ | |||||||
|     <div> |     <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.status.block_time * 1000 | date:'yyyy-MM-dd HH:mm' }}</ng-template> | ||||||
|       <ng-template [ngIf]="!tx.status.confirmed && tx.firstSeen"> |       <ng-template [ngIf]="!tx.status.confirmed && tx.firstSeen"> | ||||||
|         <i><app-time kind="since" [time]="tx.firstSeen" [fastRender]="true"></app-time></i> |         <i><app-time kind="since" [time]="tx.firstSeen" [fastRender]="true" [showTooltip]="true"></app-time></i> | ||||||
|       </ng-template> |       </ng-template> | ||||||
|     </div> |     </div> | ||||||
|   </div> |   </div> | ||||||
|  | |||||||
| @ -110,7 +110,7 @@ | |||||||
|               <tbody *ngIf="blocks$ | async as blocks; else blocksSkeleton"> |               <tbody *ngIf="blocks$ | async as blocks; else blocksSkeleton"> | ||||||
|                 <tr *ngFor="let block of blocks; let i = index; trackBy: trackByBlock"> |                 <tr *ngFor="let block of blocks; 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 class="table-cell-height" ><a [routerLink]="['/block' | relativeUrl, block.id]" [state]="{ data: { block: block } }">{{ block.height }}</a></td> | ||||||
|                   <td class="table-cell-mined" ><app-time kind="since" [time]="block.timestamp" [fastRender]="true"></app-time></td> |                   <td class="table-cell-mined" ><app-time kind="since" [time]="block.timestamp" [fastRender]="true" [showTooltip]="true"></app-time></td> | ||||||
|                   <td class="table-cell-transaction-count">{{ block.tx_count | number }}</td> |                   <td class="table-cell-transaction-count">{{ block.tx_count | number }}</td> | ||||||
|                   <td class="table-cell-size"> |                   <td class="table-cell-size"> | ||||||
|                     <div class="progress"> |                     <div class="progress"> | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user