Merge pull request #2342 from mempool/simon/display-opening-closing-transactions
This commit is contained in:
		
						commit
						13bac763a1
					
				| @ -20,7 +20,7 @@ | |||||||
|       <div class="col"> |       <div class="col"> | ||||||
|         <table class="table table-borderless smaller-text table-sm table-tx-vin"> |         <table class="table table-borderless smaller-text table-sm table-tx-vin"> | ||||||
|           <tbody> |           <tbody> | ||||||
|             <ng-template ngFor let-vin [ngForOf]="tx['@vinLimit'] ? ((tx.vin.length>12)?tx.vin.slice(0, 10): tx.vin.slice(0, 12)) : tx.vin" [ngForTrackBy]="trackByIndexFn"> |             <ng-template ngFor let-vin [ngForOf]="tx['@vinLimit'] ? ((tx.vin.length > rowLimit) ? tx.vin.slice(0, rowLimit - 2) : tx.vin.slice(0, rowLimit)) : tx.vin" [ngForTrackBy]="trackByIndexFn"> | ||||||
|               <tr [ngClass]="{ |               <tr [ngClass]="{ | ||||||
|                 'assetBox': assetsMinimal && vin.prevout && assetsMinimal[vin.prevout.asset] && !vin.is_coinbase && vin.prevout.scriptpubkey_address && tx._unblinded, |                 'assetBox': assetsMinimal && vin.prevout && assetsMinimal[vin.prevout.asset] && !vin.is_coinbase && vin.prevout.scriptpubkey_address && tx._unblinded, | ||||||
|                 'highlight': vin.prevout?.scriptpubkey_address === this.address && this.address !== '' |                 'highlight': vin.prevout?.scriptpubkey_address === this.address && this.address !== '' | ||||||
| @ -146,9 +146,9 @@ | |||||||
|                 </td> |                 </td> | ||||||
|               </tr> |               </tr> | ||||||
|             </ng-template> |             </ng-template> | ||||||
|             <tr *ngIf="tx.vin.length > 12 && tx['@vinLimit']"> |             <tr *ngIf="tx.vin.length > rowLimit && tx['@vinLimit']"> | ||||||
|               <td colspan="3" class="text-center"> |               <td colspan="3" class="text-center"> | ||||||
|                 <button class="btn btn-sm btn-primary mt-2" (click)="loadMoreInputs(tx);"><span i18n="show-all">Show all</span> ({{ tx.vin.length - 10 }})</button> |                 <button class="btn btn-sm btn-primary mt-2" (click)="loadMoreInputs(tx);"><span i18n="show-all">Show all</span> ({{ tx.vin.length }})</button> | ||||||
|               </td> |               </td> | ||||||
|             </tr> |             </tr> | ||||||
|           </tbody> |           </tbody> | ||||||
| @ -158,7 +158,7 @@ | |||||||
|       <div class="col mobile-bottomcol"> |       <div class="col mobile-bottomcol"> | ||||||
|         <table class="table table-borderless smaller-text table-sm table-tx-vout"> |         <table class="table table-borderless smaller-text table-sm table-tx-vout"> | ||||||
|           <tbody> |           <tbody> | ||||||
|             <ng-template ngFor let-vout let-vindex="index" [ngForOf]="tx['@voutLimit'] && !outputIndex ? ((tx.vout.length > 12) ? tx.vout.slice(0, 10) : tx.vout.slice(0, 12)) : tx.vout" [ngForTrackBy]="trackByIndexFn"> |             <ng-template ngFor let-vout let-vindex="index" [ngForOf]="tx['@voutLimit'] && !outputIndex ? ((tx.vout.length > rowLimit) ? tx.vout.slice(0, rowLimit - 2) : tx.vout.slice(0, rowLimit)) : tx.vout" [ngForTrackBy]="trackByIndexFn"> | ||||||
|               <tr [ngClass]="{ |               <tr [ngClass]="{ | ||||||
|                 'assetBox': assetsMinimal && assetsMinimal[vout.asset] && vout.scriptpubkey_address && tx.vin && !tx.vin[0].is_coinbase && tx._unblinded || outputIndex === vindex, |                 'assetBox': assetsMinimal && assetsMinimal[vout.asset] && vout.scriptpubkey_address && tx.vin && !tx.vin[0].is_coinbase && tx._unblinded || outputIndex === vindex, | ||||||
|                 'highlight': vout.scriptpubkey_address === this.address && this.address !== '' |                 'highlight': vout.scriptpubkey_address === this.address && this.address !== '' | ||||||
| @ -257,9 +257,9 @@ | |||||||
|                 </td> |                 </td> | ||||||
|               </tr> |               </tr> | ||||||
|             </ng-template> |             </ng-template> | ||||||
|             <tr *ngIf="tx.vout.length > 12 && tx['@voutLimit'] && !outputIndex"> |             <tr *ngIf="tx.vout.length > rowLimit && tx['@voutLimit'] && !outputIndex"> | ||||||
|               <td colspan="3" class="text-center"> |               <td colspan="3" class="text-center"> | ||||||
|                 <button class="btn btn-sm btn-primary mt-2" (click)="tx['@voutLimit'] = false;"><span i18n="show-all">Show all</span> ({{ tx.vout.length - 10 }})</button> |                 <button class="btn btn-sm btn-primary mt-2" (click)="tx['@voutLimit'] = false;"><span i18n="show-all">Show all</span> ({{ tx.vout.length }})</button> | ||||||
|               </td> |               </td> | ||||||
|             </tr> |             </tr> | ||||||
|           </tbody> |           </tbody> | ||||||
|  | |||||||
| @ -26,6 +26,8 @@ export class TransactionsListComponent implements OnInit, OnChanges { | |||||||
|   @Input() paginated = false; |   @Input() paginated = false; | ||||||
|   @Input() outputIndex: number; |   @Input() outputIndex: number; | ||||||
|   @Input() address: string = ''; |   @Input() address: string = ''; | ||||||
|  |   @Input() rowLimit = 12; | ||||||
|  |   @Input() channels: { inputs: any[], outputs: any[] }; | ||||||
| 
 | 
 | ||||||
|   @Output() loadMore = new EventEmitter(); |   @Output() loadMore = new EventEmitter(); | ||||||
| 
 | 
 | ||||||
| @ -36,7 +38,6 @@ export class TransactionsListComponent implements OnInit, OnChanges { | |||||||
|   showDetails$ = new BehaviorSubject<boolean>(false); |   showDetails$ = new BehaviorSubject<boolean>(false); | ||||||
|   outspends: Outspend[][] = []; |   outspends: Outspend[][] = []; | ||||||
|   assetsMinimal: any; |   assetsMinimal: any; | ||||||
|   channels: { inputs: any[], outputs: any[] }; |  | ||||||
| 
 | 
 | ||||||
|   constructor( |   constructor( | ||||||
|     public stateService: StateService, |     public stateService: StateService, | ||||||
| @ -127,7 +128,9 @@ export class TransactionsListComponent implements OnInit, OnChanges { | |||||||
|     }); |     }); | ||||||
|     const txIds = this.transactions.map((tx) => tx.txid); |     const txIds = this.transactions.map((tx) => tx.txid); | ||||||
|     this.refreshOutspends$.next(txIds); |     this.refreshOutspends$.next(txIds); | ||||||
|     this.refreshChannels$.next(txIds); |     if (!this.channels) { | ||||||
|  |       this.refreshChannels$.next(txIds); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   onScroll() { |   onScroll() { | ||||||
|  | |||||||
| @ -16,3 +16,9 @@ | |||||||
|   color: #ffffff66; |   color: #ffffff66; | ||||||
|   font-size: 12px; |   font-size: 12px; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | @media (max-width: 768px) { | ||||||
|  |   .box { | ||||||
|  |     margin-bottom: 20px; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -14,7 +14,7 @@ | |||||||
| 
 | 
 | ||||||
|   <div class="clearfix"></div> |   <div class="clearfix"></div> | ||||||
| 
 | 
 | ||||||
|   <app-nodes-channels-map *ngIf="!error" [style]="'channelpage'" [channel]="channelGeo"></app-nodes-channels-map> |   <app-nodes-channels-map *ngIf="!error && (channelGeo$ | async) as channelGeo" [style]="'channelpage'" [channel]="channelGeo"></app-nodes-channels-map> | ||||||
| 
 | 
 | ||||||
|   <div class="box"> |   <div class="box"> | ||||||
| 
 | 
 | ||||||
| @ -30,32 +30,6 @@ | |||||||
|                 <td i18n="address.total-sent">Last update</td> |                 <td i18n="address.total-sent">Last update</td> | ||||||
|                 <td><app-timestamp [dateString]="channel.updated_at"></app-timestamp></td> |                 <td><app-timestamp [dateString]="channel.updated_at"></app-timestamp></td> | ||||||
|               </tr> |               </tr> | ||||||
|               <tr> |  | ||||||
|                 <td i18n="address.total-sent">Opening transaction</td> |  | ||||||
|                 <td> |  | ||||||
|                   <a [routerLink]="['/tx' | relativeUrl, channel.transaction_id + ':' + channel.transaction_vout]" > |  | ||||||
|                     <span>{{ channel.transaction_id | shortenString : 10 }}</span> |  | ||||||
|                   </a> |  | ||||||
|                   <app-clipboard [text]="channel.transaction_id"></app-clipboard> |  | ||||||
|                 </td> |  | ||||||
|               </tr> |  | ||||||
|               <ng-template [ngIf]="channel.closing_transaction_id"> |  | ||||||
|                 <tr *ngIf="channel.closing_transaction_id"> |  | ||||||
|                   <td i18n="address.total-sent">Closing transaction</td> |  | ||||||
|                   <td> |  | ||||||
|                     <a [routerLink]="['/tx' | relativeUrl, channel.closing_transaction_id]" > |  | ||||||
|                       <span>{{ channel.closing_transaction_id | shortenString : 10 }}</span> |  | ||||||
|                     </a> |  | ||||||
|                     <app-clipboard [text]="channel.closing_transaction_id"></app-clipboard> |  | ||||||
|                   </td> |  | ||||||
|                 </tr> |  | ||||||
|                 <tr> |  | ||||||
|                   <td i18n="address.total-sent">Closing type</td> |  | ||||||
|                   <td> |  | ||||||
|                     <app-closing-type [type]="channel.closing_reason"></app-closing-type> |  | ||||||
|                   </td> |  | ||||||
|                 </tr> |  | ||||||
|               </ng-template> |  | ||||||
|             </tbody> |             </tbody> | ||||||
|           </table> |           </table> | ||||||
|         </div> |         </div> | ||||||
| @ -82,8 +56,23 @@ | |||||||
|       </div> |       </div> | ||||||
|       <div class="col"> |       <div class="col"> | ||||||
|         <app-channel-box [channel]="channel.node_right"></app-channel-box> |         <app-channel-box [channel]="channel.node_right"></app-channel-box> | ||||||
|  |       </div> | ||||||
|     </div> |     </div> | ||||||
|   </div> |      | ||||||
|  |     <br> | ||||||
|  | 
 | ||||||
|  |     <ng-container *ngIf="transactions$ | async as transactions"> | ||||||
|  |       <ng-template [ngIf]="transactions[0]"> | ||||||
|  |         <h3>Opening transaction</h3> | ||||||
|  |         <app-transactions-list [transactions]="[transactions[0]]" [showConfirmations]="true" [rowLimit]="5" [channels]="{ inputs: [], outputs: [channel] }"></app-transactions-list> | ||||||
|  |       </ng-template> | ||||||
|  |       <ng-template [ngIf]="transactions[1]"> | ||||||
|  |         <div class="closing-header"> | ||||||
|  |           <h3 style="margin: 0;">Closing transaction</h3>  <app-closing-type [type]="channel.closing_reason"></app-closing-type> | ||||||
|  |         </div> | ||||||
|  |         <app-transactions-list [transactions]="[transactions[1]]" [showConfirmations]="true" [rowLimit]="5" [channels]="{ inputs: [channel], outputs: [] }"></app-transactions-list> | ||||||
|  |       </ng-template> | ||||||
|  |     </ng-container> | ||||||
| 
 | 
 | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -39,3 +39,16 @@ app-fiat { | |||||||
|     margin-left: 10px; |     margin-left: 10px; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | .closing-header { | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: row; | ||||||
|  |   margin-bottom: 1rem; | ||||||
|  |   align-items: center; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @media (max-width: 768px) { | ||||||
|  |   h3 { | ||||||
|  |     font-size: 1.4rem; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | |||||||
| @ -1,7 +1,9 @@ | |||||||
| import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; | import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; | ||||||
| import { ActivatedRoute, ParamMap } from '@angular/router'; | import { ActivatedRoute, ParamMap } from '@angular/router'; | ||||||
| import { Observable, of } from 'rxjs'; | import { forkJoin, Observable, of, share, zip } from 'rxjs'; | ||||||
| import { catchError, switchMap, tap } from 'rxjs/operators'; | import { catchError, map, shareReplay, switchMap, tap } from 'rxjs/operators'; | ||||||
|  | import { ApiService } from 'src/app/services/api.service'; | ||||||
|  | import { ElectrsApiService } from 'src/app/services/electrs-api.service'; | ||||||
| import { SeoService } from 'src/app/services/seo.service'; | import { SeoService } from 'src/app/services/seo.service'; | ||||||
| import { LightningApiService } from '../lightning-api.service'; | import { LightningApiService } from '../lightning-api.service'; | ||||||
| 
 | 
 | ||||||
| @ -13,13 +15,15 @@ import { LightningApiService } from '../lightning-api.service'; | |||||||
| }) | }) | ||||||
| export class ChannelComponent implements OnInit { | export class ChannelComponent implements OnInit { | ||||||
|   channel$: Observable<any>; |   channel$: Observable<any>; | ||||||
|  |   channelGeo$: Observable<number[]>; | ||||||
|  |   transactions$: Observable<any>; | ||||||
|   error: any = null; |   error: any = null; | ||||||
|   channelGeo: number[] = []; |  | ||||||
| 
 | 
 | ||||||
|   constructor( |   constructor( | ||||||
|     private lightningApiService: LightningApiService, |     private lightningApiService: LightningApiService, | ||||||
|     private activatedRoute: ActivatedRoute, |     private activatedRoute: ActivatedRoute, | ||||||
|     private seoService: SeoService, |     private seoService: SeoService, | ||||||
|  |     private electrsApiService: ElectrsApiService, | ||||||
|   ) { } |   ) { } | ||||||
| 
 | 
 | ||||||
|   ngOnInit(): void { |   ngOnInit(): void { | ||||||
| @ -30,28 +34,41 @@ export class ChannelComponent implements OnInit { | |||||||
|           this.seoService.setTitle(`Channel: ${params.get('short_id')}`); |           this.seoService.setTitle(`Channel: ${params.get('short_id')}`); | ||||||
|           return this.lightningApiService.getChannel$(params.get('short_id')) |           return this.lightningApiService.getChannel$(params.get('short_id')) | ||||||
|             .pipe( |             .pipe( | ||||||
|               tap((data) => { |  | ||||||
|                 if (!data.node_left.longitude || !data.node_left.latitude || |  | ||||||
|                   !data.node_right.longitude || !data.node_right.latitude) { |  | ||||||
|                   this.channelGeo = []; |  | ||||||
|                 } else { |  | ||||||
|                   this.channelGeo = [ |  | ||||||
|                     data.node_left.public_key, |  | ||||||
|                     data.node_left.alias, |  | ||||||
|                     data.node_left.longitude, data.node_left.latitude, |  | ||||||
|                     data.node_right.public_key, |  | ||||||
|                     data.node_right.alias, |  | ||||||
|                     data.node_right.longitude, data.node_right.latitude, |  | ||||||
|                   ]; |  | ||||||
|                 } |  | ||||||
|               }), |  | ||||||
|               catchError((err) => { |               catchError((err) => { | ||||||
|                 this.error = err; |                 this.error = err; | ||||||
|                 return of(null); |                 return of(null); | ||||||
|               }) |               }) | ||||||
|             ); |             ); | ||||||
|         }) |         }), | ||||||
|  |         shareReplay(), | ||||||
|       ); |       ); | ||||||
|  | 
 | ||||||
|  |     this.channelGeo$ = this.channel$.pipe( | ||||||
|  |       map((data) => { | ||||||
|  |         if (!data.node_left.longitude || !data.node_left.latitude || | ||||||
|  |           !data.node_right.longitude || !data.node_right.latitude) { | ||||||
|  |           return []; | ||||||
|  |         } else { | ||||||
|  |           return [ | ||||||
|  |             data.node_left.public_key, | ||||||
|  |             data.node_left.alias, | ||||||
|  |             data.node_left.longitude, data.node_left.latitude, | ||||||
|  |             data.node_right.public_key, | ||||||
|  |             data.node_right.alias, | ||||||
|  |             data.node_right.longitude, data.node_right.latitude, | ||||||
|  |           ]; | ||||||
|  |         } | ||||||
|  |       }), | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     this.transactions$ = this.channel$.pipe( | ||||||
|  |       switchMap((data) => { | ||||||
|  |         return zip([ | ||||||
|  |           data.transaction_id ? this.electrsApiService.getTransaction$(data.transaction_id) : of(null), | ||||||
|  |           data.closing_transaction_id ? this.electrsApiService.getTransaction$(data.closing_transaction_id) : of(null), | ||||||
|  |         ]); | ||||||
|  |       }), | ||||||
|  |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user