From 1fc35956cb3e7ec22356f05410d8286879313175 Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Thu, 10 Aug 2017 16:12:06 -0400 Subject: [PATCH 01/28] style the summary items and labels --- app/src/app/app.scss | 10 ++++++++++ app/src/components/transaction/transaction.html | 6 +++--- app/src/pages/address/address.html | 2 +- app/src/pages/block-detail/block-detail.html | 4 ++-- app/src/pages/transaction/transaction.html | 2 +- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/app/src/app/app.scss b/app/src/app/app.scss index 553250e..6e2f3a9 100644 --- a/app/src/app/app.scss +++ b/app/src/app/app.scss @@ -15,6 +15,16 @@ white-space: nowrap; } +.summary ion-label { + color: #333; + font-weight: bold; +} + +.summary ion-item { + color: #999; + font-size: 1.4rem; +} + // Shared Sass variables, which can be used to adjust Ionic's // default Sass variables, belong in "theme/variables.scss". // diff --git a/app/src/components/transaction/transaction.html b/app/src/components/transaction/transaction.html index ca9b1e8..39020c5 100644 --- a/app/src/components/transaction/transaction.html +++ b/app/src/components/transaction/transaction.html @@ -31,7 +31,7 @@

{{ vin.addr }} {{ vin.value + ' BTC' }}

-

Confirmations {{vin.confirmations}}

+

Confirmations {{vin.confirmations}}

scriptSig

@@ -44,10 +44,10 @@ - + - +
diff --git a/app/src/pages/address/address.html b/app/src/pages/address/address.html index 9e441f5..d70fc96 100644 --- a/app/src/pages/address/address.html +++ b/app/src/pages/address/address.html @@ -9,7 +9,7 @@

Summary

- + Total Received diff --git a/app/src/pages/block-detail/block-detail.html b/app/src/pages/block-detail/block-detail.html index 354ef77..fcd94f6 100644 --- a/app/src/pages/block-detail/block-detail.html +++ b/app/src/pages/block-detail/block-detail.html @@ -8,9 +8,9 @@

Summary

- + - Number of Transactions + Number of Transactions {{ block.tx.length }} diff --git a/app/src/pages/transaction/transaction.html b/app/src/pages/transaction/transaction.html index 26a1663..bed9bd1 100644 --- a/app/src/pages/transaction/transaction.html +++ b/app/src/pages/transaction/transaction.html @@ -8,7 +8,7 @@

Summary

- + Size From 5a551a5e3ba5dbdad74f7403e12baaf3a1c4603e Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Thu, 10 Aug 2017 17:19:31 -0400 Subject: [PATCH 02/28] add currency conversion button and action sheet --- app/src/app/app.module.ts | 4 +- app/src/components/head-nav/head-nav.html | 3 ++ app/src/components/head-nav/head-nav.ts | 48 +++++++++++++++++++- app/src/pages/block-detail/block-detail.html | 2 +- app/src/pages/block-detail/block-detail.ts | 3 +- 5 files changed, 56 insertions(+), 4 deletions(-) diff --git a/app/src/app/app.module.ts b/app/src/app/app.module.ts index ca547f3..c0b673b 100644 --- a/app/src/app/app.module.ts +++ b/app/src/app/app.module.ts @@ -8,6 +8,7 @@ import { InsightApp } from './app.component'; import { PagesModule, BlocksPage, BroadcastTxPage, NodeStatusPage, VerifyMessagePage } from '../pages'; import { BlocksService, StorageService } from '../services'; import { ApiProvider } from '../providers/api/api'; +import { CurrencyProvider } from '../providers/currency/currency'; @NgModule({ declarations: [ @@ -33,7 +34,8 @@ import { ApiProvider } from '../providers/api/api'; StorageService, BlocksService, {provide: ErrorHandler, useClass: IonicErrorHandler}, - ApiProvider + ApiProvider, + CurrencyProvider ] }) diff --git a/app/src/components/head-nav/head-nav.html b/app/src/components/head-nav/head-nav.html index b441164..e7f73fd 100644 --- a/app/src/components/head-nav/head-nav.html +++ b/app/src/components/head-nav/head-nav.html @@ -4,6 +4,9 @@ {{title}} + diff --git a/app/src/components/head-nav/head-nav.ts b/app/src/components/head-nav/head-nav.ts index 54fee4c..b38b01c 100644 --- a/app/src/components/head-nav/head-nav.ts +++ b/app/src/components/head-nav/head-nav.ts @@ -3,6 +3,8 @@ import { Input } from '@angular/core'; import { NavController } from 'ionic-angular'; import { Http } from '@angular/http'; import { ApiProvider } from '../../providers/api/api'; +import { CurrencyProvider } from '../../providers/currency/currency'; +import { ActionSheetController } from 'ionic-angular'; /** * Generated class for the HeadNavComponent component. @@ -21,7 +23,7 @@ export class HeadNavComponent { public q: string; public badQuery: boolean = false; - constructor(private navCtrl: NavController, private http: Http, private api: ApiProvider) { + constructor(private navCtrl: NavController, private http: Http, private api: ApiProvider, public currency: CurrencyProvider, public actionSheetCtrl: ActionSheetController) { } private resetSearch(): void { @@ -98,4 +100,48 @@ export class HeadNavComponent { }; /* tslint:enable:no-unused-variable */ + public changeCurrency() { + console.log('changeCurrency'); + this.presentActionSheet(); + } + + presentActionSheet() { + let actionSheet = this.actionSheetCtrl.create({ + title: 'Change Currency', + buttons: [ + { + text: 'USD', + handler: () => { + this.currency.setCurrency('USD'); + } + }, + { + text: 'BTC', + handler: () => { + this.currency.setCurrency('BTC'); + } + }, + { + text: 'mBTC', + handler: () => { + this.currency.setCurrency('mBTC'); + } + }, + { + text: 'bits', + handler: () => { + this.currency.setCurrency('bits'); + } + }, + { + text: 'Cancel', + role: 'cancel', + handler: () => { + console.log('Cancel clicked'); + } + } + ] + }); + actionSheet.present(); + } } diff --git a/app/src/pages/block-detail/block-detail.html b/app/src/pages/block-detail/block-detail.html index fcd94f6..daa0444 100644 --- a/app/src/pages/block-detail/block-detail.html +++ b/app/src/pages/block-detail/block-detail.html @@ -24,7 +24,7 @@ Block Reward - {{ block.reward + ' BTC' }} + {{ currency.getConversion(block.reward) }} diff --git a/app/src/pages/block-detail/block-detail.ts b/app/src/pages/block-detail/block-detail.ts index 66053d5..fb3b333 100644 --- a/app/src/pages/block-detail/block-detail.ts +++ b/app/src/pages/block-detail/block-detail.ts @@ -2,6 +2,7 @@ import { Component } from '@angular/core'; import { IonicPage, NavController, NavParams } from 'ionic-angular'; import { Http } from '@angular/http'; import { ApiProvider } from '../../providers/api/api'; +import { CurrencyProvider } from '../../providers/currency/currency'; /** * Generated class for the BlockDetailPage page. @@ -25,7 +26,7 @@ export class BlockDetailPage { tx: [] }; - constructor(public navCtrl: NavController, private http: Http, public navParams: NavParams, private api: ApiProvider) { + constructor(public navCtrl: NavController, private http: Http, public navParams: NavParams, private api: ApiProvider, public currency: CurrencyProvider) { this.blockHash = navParams.get('blockHash'); this.http.get(this.api.apiPrefix + 'block/' + this.blockHash).subscribe( From ac656802c96a363a7b29951c4d3760184aac77ad Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Thu, 10 Aug 2017 17:30:46 -0400 Subject: [PATCH 03/28] fixed lint warnings; renamed action sheet title --- app/src/components/head-nav/head-nav.ts | 32 ++++++++++--------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/app/src/components/head-nav/head-nav.ts b/app/src/components/head-nav/head-nav.ts index b38b01c..5333728 100644 --- a/app/src/components/head-nav/head-nav.ts +++ b/app/src/components/head-nav/head-nav.ts @@ -26,16 +26,11 @@ export class HeadNavComponent { constructor(private navCtrl: NavController, private http: Http, private api: ApiProvider, public currency: CurrencyProvider, public actionSheetCtrl: ActionSheetController) { } - private resetSearch(): void { - this.q = ''; - this.loading = false; - } - public search(): void { let apiPrefix: string = this.api.apiPrefix; this.http.get(apiPrefix + 'block/' + this.q).subscribe( - function (data: any) { + function (data: any): void { this.resetSearch(); console.log('block', data); let parsedData: any = JSON.parse(data._body); @@ -45,7 +40,7 @@ export class HeadNavComponent { }.bind(this), () => { this.http.get(apiPrefix + 'tx/' + this.q).subscribe( - function (data: any) { + function (data: any): void { this.resetSearch(); console.log('tx', data); let parsedData: any = JSON.parse(data._body); @@ -55,7 +50,7 @@ export class HeadNavComponent { }.bind(this), () => { this.http.get(apiPrefix + 'addr/' + this.q).subscribe( - function (data: any) { + function (data: any): void { this.resetSearch(); console.log('addr', data); let parsedData: any = JSON.parse(data._body); @@ -98,16 +93,16 @@ export class HeadNavComponent { 2000 ); }; + + private resetSearch(): void { + this.q = ''; + this.loading = false; + } /* tslint:enable:no-unused-variable */ - public changeCurrency() { - console.log('changeCurrency'); - this.presentActionSheet(); - } - - presentActionSheet() { - let actionSheet = this.actionSheetCtrl.create({ - title: 'Change Currency', + public changeCurrency(): void { + let actionSheet: any = this.actionSheetCtrl.create({ + title: 'Change Denomination', buttons: [ { text: 'USD', @@ -135,10 +130,7 @@ export class HeadNavComponent { }, { text: 'Cancel', - role: 'cancel', - handler: () => { - console.log('Cancel clicked'); - } + role: 'cancel' } ] }); From db5bf4420a5049ba310d271054e397f64f3e4be5 Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Thu, 10 Aug 2017 17:35:17 -0400 Subject: [PATCH 04/28] fixed e2e tests by adding provider dependencies --- app/src/test.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/test.ts b/app/src/test.ts index 5a0cc78..c317506 100644 --- a/app/src/test.ts +++ b/app/src/test.ts @@ -17,7 +17,9 @@ import { ConfigMock, PlatformMock } from './mocks'; import { BlocksServiceMock } from './services/mocks'; import { BlocksService } from './services'; import { ApiProvider } from './providers/api/api'; +import { CurrencyProvider } from './providers/currency/currency'; import { HeadNavComponentModule } from './components/head-nav/head-nav.module'; +import { ActionSheetController } from 'ionic-angular'; // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. declare var __karma__: any; @@ -63,7 +65,9 @@ export class TestUtils { {provide: Platform, useClass: PlatformMock}, {provide: Config, useClass: ConfigMock}, {provide: BlocksService, useClass: BlocksServiceMock}, - ApiProvider + ApiProvider, + CurrencyProvider, + ActionSheetController ], imports: [ FormsModule, From 3bc5959075516234d897a849d4047816f64f9c3f Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Thu, 10 Aug 2017 17:44:51 -0400 Subject: [PATCH 05/28] Added currency conversion to transaction component --- app/src/components/transaction/transaction.html | 8 ++++---- app/src/components/transaction/transaction.ts | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/components/transaction/transaction.html b/app/src/components/transaction/transaction.html index 39020c5..75cc9b4 100644 --- a/app/src/components/transaction/transaction.html +++ b/app/src/components/transaction/transaction.html @@ -29,7 +29,7 @@
-

{{ vin.addr }} {{ vin.value + ' BTC' }}

+

{{ vin.addr }} {{ currency.getConversion(vin.value) }}

Confirmations {{vin.confirmations}}

scriptSig

@@ -62,7 +62,7 @@
- {{ vout.value + ' BTC' }} + {{ currency.getConversion(vout.value) }} (S) (U)
@@ -73,11 +73,11 @@ - Fee {{ tx.fees + ' BTC' }} + Fee {{ currency.getConversion(tx.fees) }} {{ tx.confirmations }} Confirmations - {{ tx.valueOut + ' BTC' }} + {{ currency.getConversion(tx.valueOut) }} diff --git a/app/src/components/transaction/transaction.ts b/app/src/components/transaction/transaction.ts index 074ee97..b01a7bb 100644 --- a/app/src/components/transaction/transaction.ts +++ b/app/src/components/transaction/transaction.ts @@ -1,6 +1,7 @@ import { Component } from '@angular/core'; import { Input } from '@angular/core'; import { NavController } from 'ionic-angular'; +import { CurrencyProvider } from '../../providers/currency/currency'; /** * Generated class for the TransactionComponent component. @@ -17,7 +18,7 @@ export class TransactionComponent { public expanded: boolean = false; @Input() public tx: any = {}; - constructor(private navCtrl: NavController) { + constructor(private navCtrl: NavController, public currency: CurrencyProvider) { } public getAddress(vout: any): string { From 8ba0a0777262c21cb59d03fe18b6f3fa39e4c871 Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Thu, 10 Aug 2017 17:48:48 -0400 Subject: [PATCH 06/28] fixed tslint issues --- app/src/components/head-nav/head-nav.module.ts | 4 ++-- app/src/providers/currency/currency.spec.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/components/head-nav/head-nav.module.ts b/app/src/components/head-nav/head-nav.module.ts index 7fb2c00..96140da 100644 --- a/app/src/components/head-nav/head-nav.module.ts +++ b/app/src/components/head-nav/head-nav.module.ts @@ -4,10 +4,10 @@ import { HeadNavComponent } from './head-nav'; @NgModule({ declarations: [ - HeadNavComponent, + HeadNavComponent ], imports: [ - IonicModule, + IonicModule ], exports: [ HeadNavComponent diff --git a/app/src/providers/currency/currency.spec.ts b/app/src/providers/currency/currency.spec.ts index d1ef863..2170c01 100644 --- a/app/src/providers/currency/currency.spec.ts +++ b/app/src/providers/currency/currency.spec.ts @@ -4,7 +4,7 @@ import { HttpModule } from '@angular/http'; import { CurrencyProvider } from './currency'; describe('CurrencyProvider', () => { - let currency; + let currency: CurrencyProvider; beforeEach(() => { TestBed.configureTestingModule({ @@ -47,7 +47,7 @@ describe('CurrencyProvider', () => { }); it('rounds float using specified number of decimal places', () => { - let aFloat = 4.32943; + let aFloat: number = 4.32943; expect(currency.roundFloat(aFloat, 2)).toBe(4.33); expect(currency.roundFloat(aFloat, 3)).toBe(4.329); @@ -66,7 +66,7 @@ describe('CurrencyProvider', () => { }); it('gets proper conversion after changing currency', () => { - let aFloat = 12345.09876543; + let aFloat: number = 12345.09876543; expect(currency.getConversion(aFloat)).toBe('12345.09876543 BTC'); currency.setCurrency('mBTC'); From 1dfe384271dcd25e4280662faf4e43f01291f409 Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Fri, 11 Aug 2017 10:33:44 -0400 Subject: [PATCH 07/28] added USD conversion; added conversion to address page --- app/src/pages/address/address.html | 8 ++++---- app/src/pages/address/address.ts | 3 ++- app/src/providers/currency/currency.ts | 22 +++++++++++++++------- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/app/src/pages/address/address.html b/app/src/pages/address/address.html index d70fc96..752120a 100644 --- a/app/src/pages/address/address.html +++ b/app/src/pages/address/address.html @@ -5,7 +5,7 @@

Address

Address {{ address.addrStr }}

-

{{ address.balance }} BTC

+

{{ currency.getConversion(address.balance) }}

Summary

@@ -13,19 +13,19 @@ Total Received - {{ address.totalReceived }} BTC + {{ currency.getConversion(address.totalReceived) }} Total Sent - {{ address.totalSent }} BTC + {{ currency.getConversion(address.totalSent) }} Final Balance - {{ address.balance }} BTC + {{ currency.getConversion(address.balance) }} diff --git a/app/src/pages/address/address.ts b/app/src/pages/address/address.ts index e392a33..459f4de 100644 --- a/app/src/pages/address/address.ts +++ b/app/src/pages/address/address.ts @@ -2,6 +2,7 @@ import { Component } from '@angular/core'; import { IonicPage, NavController, NavParams } from 'ionic-angular'; import { Http } from '@angular/http'; import { ApiProvider } from '../../providers/api/api'; +import { CurrencyProvider } from '../../providers/currency/currency'; /** * Generated class for the AddressPage page. @@ -23,7 +24,7 @@ export class AddressPage { private addrStr: string; public address: any = {}; - constructor(public navCtrl: NavController, public navParams: NavParams, private http: Http, private api: ApiProvider) { + constructor(public navCtrl: NavController, public navParams: NavParams, private http: Http, private api: ApiProvider, public currency: CurrencyProvider) { this.addrStr = navParams.get('addrStr'); } diff --git a/app/src/providers/currency/currency.ts b/app/src/providers/currency/currency.ts index fe6f412..b89d2ff 100644 --- a/app/src/providers/currency/currency.ts +++ b/app/src/providers/currency/currency.ts @@ -1,5 +1,6 @@ import { Injectable } from '@angular/core'; import { Http } from '@angular/http'; +import { ApiProvider } from '../../providers/api/api'; import 'rxjs/add/operator/map'; /* @@ -14,8 +15,10 @@ export class CurrencyProvider { private defaultCurrency: string; private currencySymbol: string; private factor: number = 1; + private bitstamp: number; + private loading: boolean; - constructor(public http: Http) { + constructor(public http: Http, private api: ApiProvider) { this.defaultCurrency = 'BTC'; this.currencySymbol = this.defaultCurrency; } @@ -50,12 +53,17 @@ export class CurrencyProvider { localStorage.setItem('insight-currency', currency); if (currency === 'USD') { - // TODO Replace this with call - /* - Currency.get({}, function(res) { - $rootScope.currency.factor = $rootScope.currency.bitstamp = res.data.bitstamp; - }); - */ + this.http.get(this.api.apiPrefix + 'currency').subscribe( + (data) => { + let currencyParsed = JSON.parse(data['_body']); + this.factor = this.bitstamp = currencyParsed.data.bitstamp; + this.loading = false; + }, + (err) => { + console.log('err is', err); + this.loading = false; + } + ); } else if (currency === 'mBTC') { this.factor = 1000; } else if (currency === 'bits') { From 2226a2cc18335a72a30d0821657d1b8a0c3e9ea6 Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Fri, 11 Aug 2017 10:42:34 -0400 Subject: [PATCH 08/28] fixed lint warnings and tests --- app/src/providers/currency/currency.spec.ts | 2 ++ app/src/providers/currency/currency.ts | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/providers/currency/currency.spec.ts b/app/src/providers/currency/currency.spec.ts index 2170c01..02fa17a 100644 --- a/app/src/providers/currency/currency.spec.ts +++ b/app/src/providers/currency/currency.spec.ts @@ -2,6 +2,7 @@ import { TestBed, ComponentFixture, inject } from '@angular/core/testing'; import { HttpModule } from '@angular/http'; import { CurrencyProvider } from './currency'; +import { ApiProvider } from '../api/api'; describe('CurrencyProvider', () => { let currency: CurrencyProvider; @@ -12,6 +13,7 @@ describe('CurrencyProvider', () => { HttpModule ], providers: [ + ApiProvider, CurrencyProvider ] }); diff --git a/app/src/providers/currency/currency.ts b/app/src/providers/currency/currency.ts index b89d2ff..b3f571b 100644 --- a/app/src/providers/currency/currency.ts +++ b/app/src/providers/currency/currency.ts @@ -12,9 +12,9 @@ import 'rxjs/add/operator/map'; @Injectable() export class CurrencyProvider { - private defaultCurrency: string; - private currencySymbol: string; - private factor: number = 1; + public defaultCurrency: string; + public currencySymbol: string; + public factor: number = 1; private bitstamp: number; private loading: boolean; @@ -23,7 +23,7 @@ export class CurrencyProvider { this.currencySymbol = this.defaultCurrency; } - private roundFloat(aFloat: number, decimalPlaces: number): number { + public roundFloat(aFloat: number, decimalPlaces: number): number { return Math.round(aFloat * Math.pow(10, decimalPlaces)) / Math.pow(10, decimalPlaces); } @@ -55,7 +55,7 @@ export class CurrencyProvider { if (currency === 'USD') { this.http.get(this.api.apiPrefix + 'currency').subscribe( (data) => { - let currencyParsed = JSON.parse(data['_body']); + let currencyParsed: any = JSON.parse(data['_body']); this.factor = this.bitstamp = currencyParsed.data.bitstamp; this.loading = false; }, From 34792d5d658eb81b3eb60203c3892a0dd68eff22 Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Fri, 11 Aug 2017 17:29:29 -0400 Subject: [PATCH 09/28] fixed bug where block detail did not retain data after leaving view and coming back --- app/src/pages/block-detail/block-detail.ts | 6 ++---- app/src/pipes/split/split.ts | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/app/src/pages/block-detail/block-detail.ts b/app/src/pages/block-detail/block-detail.ts index fb3b333..95bdaf8 100644 --- a/app/src/pages/block-detail/block-detail.ts +++ b/app/src/pages/block-detail/block-detail.ts @@ -28,7 +28,9 @@ export class BlockDetailPage { constructor(public navCtrl: NavController, private http: Http, public navParams: NavParams, private api: ApiProvider, public currency: CurrencyProvider) { this.blockHash = navParams.get('blockHash'); + } + public ionViewDidLoad(): void { this.http.get(this.api.apiPrefix + 'block/' + this.blockHash).subscribe( (data) => { this.block = JSON.parse(data['_body']); @@ -41,10 +43,6 @@ export class BlockDetailPage { ); } - public ionViewWillLeave(): void { - this.loading = true; - } - public goToPreviousBlock(): void { this.navCtrl.push('block-detail', { 'blockHash': this.block.previousblockhash diff --git a/app/src/pipes/split/split.ts b/app/src/pipes/split/split.ts index ab08efd..1f2e7ca 100644 --- a/app/src/pipes/split/split.ts +++ b/app/src/pipes/split/split.ts @@ -15,7 +15,6 @@ export class SplitPipe implements PipeTransform { */ public transform(value: string, delimiter: string): Array { let array: Array = value.split(delimiter); - console.log('split is', array); return array; } } From a554e43c079801f3469c9cf7f9eb4d5390016d6f Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Mon, 14 Aug 2017 17:01:19 -0400 Subject: [PATCH 10/28] Added aggregateItems --- .../components/transaction/transaction.html | 14 ++-- app/src/components/transaction/transaction.ts | 72 +++++++++++++++++++ 2 files changed, 81 insertions(+), 5 deletions(-) diff --git a/app/src/components/transaction/transaction.html b/app/src/components/transaction/transaction.html index 75cc9b4..c5d29a5 100644 --- a/app/src/components/transaction/transaction.html +++ b/app/src/components/transaction/transaction.html @@ -27,19 +27,23 @@ - +
-

{{ vin.addr }} {{ currency.getConversion(vin.value) }}

+

{{ vin.addr }}

Confirmations {{vin.confirmations}}

-

scriptSig

-
-
+
+

scriptSig

+

{{item}}

+ +
+ {{ currency.getConversion(vin.value) }} +
diff --git a/app/src/components/transaction/transaction.ts b/app/src/components/transaction/transaction.ts index b01a7bb..772fed1 100644 --- a/app/src/components/transaction/transaction.ts +++ b/app/src/components/transaction/transaction.ts @@ -15,6 +15,8 @@ import { CurrencyProvider } from '../../providers/currency/currency'; }) export class TransactionComponent { + private COIN: number = 100000000; + public expanded: boolean = false; @Input() public tx: any = {}; @@ -44,4 +46,74 @@ export class TransactionComponent { public toggleExpanded(): void { this.expanded = !this.expanded; } + + public aggregateItems(items: Array): Array { + console.log('aggregateItems called'); + if (!items) return []; + + let l: number = items.length; + + let ret: Array = []; + let tmp: any = {}; + let u: number = 0; + + for (let i: number = 0; i < l; i++) { + + let notAddr: boolean = false; + // non standard input + if (items[i].scriptSig && !items[i].addr) { + items[i].addr = 'Unparsed address [' + u++ + ']'; + items[i].notAddr = true; + notAddr = true; + } + + // non standard output + if (items[i].scriptPubKey && !items[i].scriptPubKey.addresses) { + items[i].scriptPubKey.addresses = ['Unparsed address [' + u++ + ']']; + items[i].notAddr = true; + notAddr = true; + } + + // multiple addr at output + if (items[i].scriptPubKey && items[i].scriptPubKey.addresses.length > 1) { + items[i].addr = items[i].scriptPubKey.addresses.join(','); + ret.push(items[i]); + continue; + } + + let addr: string = items[i].addr || (items[i].scriptPubKey && items[i].scriptPubKey.addresses[0]); + + if (!tmp[addr]) { + tmp[addr] = {}; + tmp[addr].valueSat = 0; + tmp[addr].count = 0; + tmp[addr].addr = addr; + tmp[addr].items = []; + } + tmp[addr].isSpent = items[i].spentTxId; + + tmp[addr].doubleSpentTxID = tmp[addr].doubleSpentTxID || items[i].doubleSpentTxID; + tmp[addr].doubleSpentIndex = tmp[addr].doubleSpentIndex || items[i].doubleSpentIndex; + tmp[addr].dbError = tmp[addr].dbError || items[i].dbError; + tmp[addr].valueSat += Math.round(items[i].value * this.COIN); + tmp[addr].items.push(items[i]); + tmp[addr].notAddr = notAddr; + + if (items[i].unconfirmedInput) + tmp[addr].unconfirmedInput = true; + + tmp[addr].count++; + } + + console.log('tmp is', tmp); + + for (let v in tmp) { + let obj: any = tmp[v]; + console.log('obj isb', obj); + obj.value = obj.value || parseInt(obj.valueSat) / this.COIN; + ret.push(obj); + } + + return ret; + }; } From 0fe359bd1f92e867d3f9ef391ed6dcc7bf5fc178 Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Mon, 14 Aug 2017 18:44:57 -0400 Subject: [PATCH 11/28] get scriptSigs working again in expanded view --- app/src/components/transaction/transaction.html | 14 +++++++++----- app/src/components/transaction/transaction.ts | 4 ---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/components/transaction/transaction.html b/app/src/components/transaction/transaction.html index c5d29a5..d46d07c 100644 --- a/app/src/components/transaction/transaction.html +++ b/app/src/components/transaction/transaction.html @@ -32,10 +32,14 @@

{{ vin.addr }}

Confirmations {{vin.confirmations}}

-
-

scriptSig

-
-

{{item}}

+

scriptSig

+
+
+
+
+

{{ scriptSig }}

+
+
@@ -60,7 +64,7 @@

Type {{vout.scriptPubKey.type}}

scriptPubKey

- {{vout.scriptPubKey.asm}} +

{{vout.scriptPubKey.asm}}

diff --git a/app/src/components/transaction/transaction.ts b/app/src/components/transaction/transaction.ts index 772fed1..8d5cc19 100644 --- a/app/src/components/transaction/transaction.ts +++ b/app/src/components/transaction/transaction.ts @@ -48,7 +48,6 @@ export class TransactionComponent { } public aggregateItems(items: Array): Array { - console.log('aggregateItems called'); if (!items) return []; let l: number = items.length; @@ -105,11 +104,8 @@ export class TransactionComponent { tmp[addr].count++; } - console.log('tmp is', tmp); - for (let v in tmp) { let obj: any = tmp[v]; - console.log('obj isb', obj); obj.value = obj.value || parseInt(obj.valueSat) / this.COIN; ret.push(obj); } From cf4d45cf591738dc2acde1b79b4b60d5fa1a93e6 Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Tue, 15 Aug 2017 11:15:10 -0400 Subject: [PATCH 12/28] fixed responsiveness in the transaction grid --- .../components/transaction/transaction.html | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/app/src/components/transaction/transaction.html b/app/src/components/transaction/transaction.html index d46d07c..78b2ea6 100644 --- a/app/src/components/transaction/transaction.html +++ b/app/src/components/transaction/transaction.html @@ -18,7 +18,7 @@ - + @@ -29,7 +29,9 @@
-

{{ vin.addr }}

+

Confirmations {{vin.confirmations}}

scriptSig

@@ -52,14 +54,18 @@ - + + - + +
-

{{ getAddress(vout) }}

+

Type {{vout.scriptPubKey.type}}

scriptPubKey

@@ -80,11 +86,13 @@ - + Fee {{ currency.getConversion(tx.fees) }} - + {{ tx.confirmations }} Confirmations + + {{ currency.getConversion(tx.valueOut) }} From 7d2b27be7d6b5e81c9d780607d75f50eee845eab Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Tue, 15 Aug 2017 16:36:11 -0400 Subject: [PATCH 13/28] added toggle to searchbar; made text selectable --- app/ionic.config.json | 3 ++- app/package.json | 2 +- app/src/app/app.scss | 4 ++++ app/src/components/head-nav/head-nav.html | 4 ++-- app/src/components/head-nav/head-nav.ts | 6 ++++++ app/src/pages/block-detail/block-detail.html | 2 +- app/src/providers/api/api.ts | 2 +- 7 files changed, 17 insertions(+), 6 deletions(-) diff --git a/app/ionic.config.json b/app/ionic.config.json index b8ac8d6..1c03d6d 100644 --- a/app/ionic.config.json +++ b/app/ionic.config.json @@ -1,5 +1,6 @@ { "name": "insight-ui", "app_id": "", - "type": "ionic-angular" + "type": "ionic-angular", + "integrations": {} } diff --git a/app/package.json b/app/package.json index 1701978..88b33c8 100644 --- a/app/package.json +++ b/app/package.json @@ -43,7 +43,7 @@ "@types/jasmine": "2.5.41", "@types/node": "7.0.4", "codecov": "2.2.0", - "ionic": "3.7.0", + "ionic": "3.8.1", "jasmine-core": "2.5.2", "jasmine-spec-reporter": "3.2.0", "karma": "1.4.1", diff --git a/app/src/app/app.scss b/app/src/app/app.scss index 6e2f3a9..e254df4 100644 --- a/app/src/app/app.scss +++ b/app/src/app/app.scss @@ -25,6 +25,10 @@ font-size: 1.4rem; } +body { + user-select: text; +} + // Shared Sass variables, which can be used to adjust Ionic's // default Sass variables, belong in "theme/variables.scss". // diff --git a/app/src/components/head-nav/head-nav.html b/app/src/components/head-nav/head-nav.html index e7f73fd..1d5ff08 100644 --- a/app/src/components/head-nav/head-nav.html +++ b/app/src/components/head-nav/head-nav.html @@ -7,9 +7,9 @@ - - + diff --git a/app/src/components/head-nav/head-nav.ts b/app/src/components/head-nav/head-nav.ts index 5333728..b3122b6 100644 --- a/app/src/components/head-nav/head-nav.ts +++ b/app/src/components/head-nav/head-nav.ts @@ -18,6 +18,7 @@ import { ActionSheetController } from 'ionic-angular'; }) export class HeadNavComponent { + public showSearch: boolean = false; public loading: boolean; @Input() public title: string; public q: string; @@ -27,6 +28,7 @@ export class HeadNavComponent { } public search(): void { + this.showSearch = false; let apiPrefix: string = this.api.apiPrefix; this.http.get(apiPrefix + 'block/' + this.q).subscribe( @@ -136,4 +138,8 @@ export class HeadNavComponent { }); actionSheet.present(); } + + public toggleSearch() { + this.showSearch = !this.showSearch; + } } diff --git a/app/src/pages/block-detail/block-detail.html b/app/src/pages/block-detail/block-detail.html index daa0444..a20d197 100644 --- a/app/src/pages/block-detail/block-detail.html +++ b/app/src/pages/block-detail/block-detail.html @@ -35,7 +35,7 @@ Mined by - + {{ block.poolInfo.poolName }} diff --git a/app/src/providers/api/api.ts b/app/src/providers/api/api.ts index 31c1966..a15b48e 100644 --- a/app/src/providers/api/api.ts +++ b/app/src/providers/api/api.ts @@ -11,7 +11,7 @@ import 'rxjs/add/operator/map'; @Injectable() export class ApiProvider { - public apiPrefix: string = 'http://localhost:3001/insight-api/'; + public apiPrefix: string = 'https://insight.bitpay.com/api/'; constructor(public http: Http) { } From 90379522fe3324abcac4cc781ccded3db8440c1f Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Wed, 16 Aug 2017 11:11:20 -0400 Subject: [PATCH 14/28] added spinner to block detail --- app/src/pages/block-detail/block-detail.html | 180 ++++++++++--------- 1 file changed, 93 insertions(+), 87 deletions(-) diff --git a/app/src/pages/block-detail/block-detail.html b/app/src/pages/block-detail/block-detail.html index a20d197..aaebe36 100644 --- a/app/src/pages/block-detail/block-detail.html +++ b/app/src/pages/block-detail/block-detail.html @@ -3,96 +3,102 @@ -

Block #{{ block.height }}

-

BlockHash {{ block.hash }}

- -

Summary

- - - - Number of Transactions - - {{ block.tx.length }} - - - - Height - - {{ block.height }} (Mainchain) - - - - Block Reward - - {{ currency.getConversion(block.reward) }} - - - - Timestamp - - {{ block.time * 1000 | date:'medium' }} - - - - Mined by - - {{ block.poolInfo.poolName }} - - - - Merkle Root - - {{ block.merkleroot }} - - - - Previous Block - - {{ block.height - 1 }} - - - - Difficulty - - {{ block.difficulty }} - - - - Bits - - {{ block.bits }} - - - - Size (bytes) - - {{ block.size }} - - - - Version - - {{ block.version }} - - - - Nonce - - {{ block.nonce }} - - - - Next Block - - {{ block.height + 1 }} - - - +
+ +
-

Transactions

+

Block #{{ block.height }}

+

BlockHash {{ block.hash }}

- +

Summary

+ + + + Number of Transactions + + {{ block.tx.length }} + + + + Height + + {{ block.height }} (Mainchain) + + + + Block Reward + + {{ currency.getConversion(block.reward) }} + + + + Timestamp + + {{ block.time * 1000 | date:'medium' }} + + + + Mined by + + {{ block.poolInfo.poolName }} + + + + Merkle Root + + {{ block.merkleroot }} + + + + Previous Block + + {{ block.height - 1 }} + + + + Difficulty + + {{ block.difficulty }} + + + + Bits + + {{ block.bits }} + + + + Size (bytes) + + {{ block.size }} + + + + Version + + {{ block.version }} + + + + Nonce + + {{ block.nonce }} + + + + Next Block + + {{ block.height + 1 }} + + + + +
+

Transactions

+ + +
From c9a1b6b153275f433f58e72fedd6aca9a98e8ff4 Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Wed, 16 Aug 2017 12:46:08 -0400 Subject: [PATCH 15/28] added spinners to transaction and address pages and transaction list component --- app/src/components/head-nav/head-nav.ts | 2 +- .../transaction-list/transaction-list.html | 21 +++-- app/src/pages/address/address.html | 76 ++++++++++--------- app/src/pages/transaction/transaction.html | 68 +++++++++-------- 4 files changed, 93 insertions(+), 74 deletions(-) diff --git a/app/src/components/head-nav/head-nav.ts b/app/src/components/head-nav/head-nav.ts index b3122b6..664e77e 100644 --- a/app/src/components/head-nav/head-nav.ts +++ b/app/src/components/head-nav/head-nav.ts @@ -139,7 +139,7 @@ export class HeadNavComponent { actionSheet.present(); } - public toggleSearch() { + public toggleSearch(): void { this.showSearch = !this.showSearch; } } diff --git a/app/src/components/transaction-list/transaction-list.html b/app/src/components/transaction-list/transaction-list.html index 6620fc2..9c0a459 100644 --- a/app/src/components/transaction-list/transaction-list.html +++ b/app/src/components/transaction-list/transaction-list.html @@ -1,7 +1,14 @@ - - - - - - - +
+ +
+ + +
+ + + + + + + +
diff --git a/app/src/pages/address/address.html b/app/src/pages/address/address.html index 752120a..4dfc4d7 100644 --- a/app/src/pages/address/address.html +++ b/app/src/pages/address/address.html @@ -3,45 +3,51 @@ -

Address

-

Address {{ address.addrStr }}

-

{{ currency.getConversion(address.balance) }}

+
+ +
-

Summary

+
+

Address

+

Address {{ address.addrStr }}

+

{{ currency.getConversion(address.balance) }}

- - - Total Received - - {{ currency.getConversion(address.totalReceived) }} - - - - Total Sent - - {{ currency.getConversion(address.totalSent) }} - - - - Final Balance - - {{ currency.getConversion(address.balance) }} - - - - No. Transactions - - {{ address.txApperances }} - - - +

Summary

-

- -

+ + + Total Received + + {{ currency.getConversion(address.totalReceived) }} + + + + Total Sent + + {{ currency.getConversion(address.totalSent) }} + + + + Final Balance + + {{ currency.getConversion(address.balance) }} + + + + No. Transactions + + {{ address.txApperances }} + + + -

Transactions

+

+ +

- +

Transactions

+ + +
diff --git a/app/src/pages/transaction/transaction.html b/app/src/pages/transaction/transaction.html index bed9bd1..7f904dc 100644 --- a/app/src/pages/transaction/transaction.html +++ b/app/src/pages/transaction/transaction.html @@ -3,40 +3,46 @@ -

Transaction

-

Transaction {{ tx.txid }}

+
+ +
-

Summary

+
+

Transaction

+

Transaction {{ tx.txid }}

- - - Size - - {{ tx.size }} (bytes) - - - - Received Time - - {{ tx.time * 1000 | date:'medium' }} - - - - Mined Time - - {{ tx.blocktime * 1000 | date:'medium' }} - - - - Included in Block - - {{ tx.blockhash }} - - - +

Summary

-

Details

+ + + Size + + {{ tx.size }} (bytes) + + + + Received Time + + {{ tx.time * 1000 | date:'medium' }} + + + + Mined Time + + {{ tx.blocktime * 1000 | date:'medium' }} + + + + Included in Block + + {{ tx.blockhash }} + + + - +

Details

+ + +
From c817f5e62c722d37136ca7c49e298a8abb08eb59 Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Wed, 16 Aug 2017 15:10:18 -0400 Subject: [PATCH 16/28] update ionic-cli --- app/ionic.config.json | 4 +++- app/package.json | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/ionic.config.json b/app/ionic.config.json index 1c03d6d..a7bf4dd 100644 --- a/app/ionic.config.json +++ b/app/ionic.config.json @@ -2,5 +2,7 @@ "name": "insight-ui", "app_id": "", "type": "ionic-angular", - "integrations": {} + "integrations": { + "cordova": {} + } } diff --git a/app/package.json b/app/package.json index 8bee14f..ca2960b 100644 --- a/app/package.json +++ b/app/package.json @@ -42,7 +42,7 @@ "@types/jasmine": "2.5.41", "@types/node": "7.0.4", "codecov": "2.2.0", - "ionic": "3.8.1", + "ionic": "3.9.0", "jasmine-core": "2.5.2", "jasmine-spec-reporter": "3.2.0", "karma": "1.4.1", From 0cbff08f599dfa82411277882a78162a03eafe34 Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Wed, 16 Aug 2017 16:33:45 -0400 Subject: [PATCH 17/28] added HomePage --- .gitignore | 3 ++- app/src/app/app.component.ts | 2 ++ app/src/app/app.module.ts | 3 ++- app/src/pages/home/home.html | 29 +++++++++++++++++++++++++++++ app/src/pages/home/home.module.ts | 18 ++++++++++++++++++ app/src/pages/home/home.scss | 3 +++ app/src/pages/home/home.ts | 27 +++++++++++++++++++++++++++ app/src/pages/index.ts | 1 + app/src/pages/pages.module.ts | 2 ++ 9 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 app/src/pages/home/home.html create mode 100644 app/src/pages/home/home.module.ts create mode 100644 app/src/pages/home/home.scss create mode 100644 app/src/pages/home/home.ts diff --git a/.gitignore b/.gitignore index 05a92b9..c188cf5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules package-lock.json -*.log \ No newline at end of file +*.log +.DS_Store diff --git a/app/src/app/app.component.ts b/app/src/app/app.component.ts index fb4dd6e..99dcb4b 100644 --- a/app/src/app/app.component.ts +++ b/app/src/app/app.component.ts @@ -3,6 +3,7 @@ import { Platform, MenuController, Nav } from 'ionic-angular'; import { StatusBar } from '@ionic-native/status-bar'; import { SplashScreen } from '@ionic-native/splash-screen'; import { + HomePage, BlocksPage, BroadcastTxPage, NodeStatusPage, @@ -36,6 +37,7 @@ export class InsightApp { // set our app's pages this.pages = [ + { title: 'Home', component: HomePage }, { title: 'Blocks', component: BlocksPage }, { title: 'Broadcast Transaction', component: BroadcastTxPage }, { title: 'Verify Signed Message', component: VerifyMessagePage }, diff --git a/app/src/app/app.module.ts b/app/src/app/app.module.ts index c0b673b..9901a7b 100644 --- a/app/src/app/app.module.ts +++ b/app/src/app/app.module.ts @@ -5,7 +5,7 @@ import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular'; import { StatusBar } from '@ionic-native/status-bar'; import { SplashScreen } from '@ionic-native/splash-screen'; import { InsightApp } from './app.component'; -import { PagesModule, BlocksPage, BroadcastTxPage, NodeStatusPage, VerifyMessagePage } from '../pages'; +import { PagesModule, HomePage, BlocksPage, BroadcastTxPage, NodeStatusPage, VerifyMessagePage } from '../pages'; import { BlocksService, StorageService } from '../services'; import { ApiProvider } from '../providers/api/api'; import { CurrencyProvider } from '../providers/currency/currency'; @@ -23,6 +23,7 @@ import { CurrencyProvider } from '../providers/currency/currency'; bootstrap: [IonicApp], entryComponents: [ InsightApp, + HomePage, BlocksPage, BroadcastTxPage, NodeStatusPage, diff --git a/app/src/pages/home/home.html b/app/src/pages/home/home.html new file mode 100644 index 0000000..0c30c95 --- /dev/null +++ b/app/src/pages/home/home.html @@ -0,0 +1,29 @@ + + + + + + + + +

Latest Blocks

+

Latest Transactions

+

About

+

insight is an open-source Bitcoin blockchain explorer with complete REST and websocket APIs that can be used for writing web wallets and other apps that need more advanced blockchain queries than provided by bitcoind RPC. Check out the source code.

+

insight is still in development, so be sure to report any bugs and provide feedback for improvement at our github issue tracker.

+
+
+ Powered by +
+ + + + +
+
diff --git a/app/src/pages/home/home.module.ts b/app/src/pages/home/home.module.ts new file mode 100644 index 0000000..9a8ed53 --- /dev/null +++ b/app/src/pages/home/home.module.ts @@ -0,0 +1,18 @@ +import { NgModule } from '@angular/core'; +import { IonicPageModule } from 'ionic-angular'; +import { HomePage } from './home'; +import { HeadNavComponentModule } from '../../components/head-nav/head-nav.module'; + +@NgModule({ + declarations: [ + HomePage + ], + imports: [ + IonicPageModule.forChild(HomePage), + HeadNavComponentModule + ], + exports: [ + HomePage + ] +}) +export class HomePageModule {} diff --git a/app/src/pages/home/home.scss b/app/src/pages/home/home.scss new file mode 100644 index 0000000..d4cc8fc --- /dev/null +++ b/app/src/pages/home/home.scss @@ -0,0 +1,3 @@ +page-home { + +} diff --git a/app/src/pages/home/home.ts b/app/src/pages/home/home.ts new file mode 100644 index 0000000..5880022 --- /dev/null +++ b/app/src/pages/home/home.ts @@ -0,0 +1,27 @@ +import { Component } from '@angular/core'; +import { IonicPage, NavController, NavParams } from 'ionic-angular'; + +/** + * Generated class for the HomePage page. + * + * See http://ionicframework.com/docs/components/#navigation for more info + * on Ionic pages and navigation. + */ +@IonicPage({ + name: 'home', + segment: 'home' +}) +@Component({ + selector: 'page-home', + templateUrl: 'home.html' +}) +export class HomePage { + + constructor(public navCtrl: NavController, public navParams: NavParams) { + } + + public ionViewDidLoad(): void { + console.log('ionViewDidLoad HomePage'); + } + +} diff --git a/app/src/pages/index.ts b/app/src/pages/index.ts index a449179..19b1b7c 100644 --- a/app/src/pages/index.ts +++ b/app/src/pages/index.ts @@ -2,4 +2,5 @@ export * from './blocksPage/blocksPage'; export * from './broadcastTxPage/broadcastTxPage'; export * from './nodeStatusPage/nodeStatusPage'; export * from './verifyMessagePage/verifyMessagePage'; +export * from './home/home'; export * from './pages.module'; diff --git a/app/src/pages/pages.module.ts b/app/src/pages/pages.module.ts index 2da0e6a..b76bdd6 100644 --- a/app/src/pages/pages.module.ts +++ b/app/src/pages/pages.module.ts @@ -3,6 +3,7 @@ import { IonicModule } from 'ionic-angular'; import { ComponentsModule } from '../components'; import { HeadNavComponentModule } from '../components/head-nav/head-nav.module'; import { + HomePage, BlocksPage, BroadcastTxPage, NodeStatusPage, @@ -11,6 +12,7 @@ import { @NgModule({ declarations: [ + HomePage, BlocksPage, BroadcastTxPage, NodeStatusPage, From 05503371cfbd8cff621e07fd0613b669e2858bd0 Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Wed, 16 Aug 2017 16:51:09 -0400 Subject: [PATCH 18/28] add "powered by" icons --- app/src/assets/img/angularjs.png | Bin 0 -> 14875 bytes app/src/assets/img/bitcore.svg | 29 ++++++++++++++++++++++ app/src/assets/img/leveldb.png | Bin 0 -> 12009 bytes app/src/assets/img/nodejs.png | Bin 0 -> 3253 bytes app/src/pages/home/home.scss | 40 +++++++++++++++++++++++++++++++ 5 files changed, 69 insertions(+) create mode 100644 app/src/assets/img/angularjs.png create mode 100644 app/src/assets/img/bitcore.svg create mode 100644 app/src/assets/img/leveldb.png create mode 100644 app/src/assets/img/nodejs.png diff --git a/app/src/assets/img/angularjs.png b/app/src/assets/img/angularjs.png new file mode 100644 index 0000000000000000000000000000000000000000..21aefd40ad3c275cfb3dce86b8332a7f9f6dd417 GIT binary patch literal 14875 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 AtN;K2 literal 0 HcmV?d00001 diff --git a/app/src/assets/img/bitcore.svg b/app/src/assets/img/bitcore.svg new file mode 100644 index 0000000..856b0a1 --- /dev/null +++ b/app/src/assets/img/bitcore.svg @@ -0,0 +1,29 @@ + + + Group copy + bitcore copy@2x + Created with Sketch (http://www.bohemiancoding.com/sketch) + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/assets/img/leveldb.png b/app/src/assets/img/leveldb.png new file mode 100644 index 0000000000000000000000000000000000000000..da13a671aaabef5febe267d4d10fa663fbbab21a GIT binary patch literal 12009 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 literal 0 HcmV?d00001 diff --git a/app/src/assets/img/nodejs.png b/app/src/assets/img/nodejs.png new file mode 100644 index 0000000000000000000000000000000000000000..4cba6f8c6432f5aa83c366fd49d10d9ea84b296a GIT binary patch literal 3253 zcmV;m3`+BfP)u%bCJPqM zqcv+^pr%cm8vXn%BbPCbvH4=S9)Ar{|8Xj1_Eo6vtnHAnF|qud5Q5pp8*78H-^} zU2zH8Xr-^K0+*nTSpu#KT!Omd64Vt}T!Omd64Vt}T!Omdic3&eT!Omdic3&eTnUS} zqN1YSPwMgV%t+x64cY0Zgxbskervn=d`+pgu8tJNC69rzlLnb;M+th{q_I}E|2|_f zV;AFL#-~JTpWkJ)WUOFRHV`oeQm6@KD`TmsxBLdJd7`~c{G5oV0{levp`x!sN zq@BRHjqwYrzeedV!%*EAwm%H9c;8_xU_8n=#k!)(nld_d_ISMG?PYYrwT+SEds$-b zkcrtaQSOWGxAu%DDAe;PH|G^ISETXjJgQ16TO!rGo9xPXC_)jD@+}be&zLaB%^Xn9 z?ePT2>t%wPZ-DE-cz|)MP9Ik?{=xVUJ||Ps8Fw>&$!M+nZ2)5v<2lB!7#}5R3@sSb zF)?LXK`Hbi6ZBqiVisdO#<48jB2v z<4hslI~3}16}>;n=)+jV_?U4QCW^RvSxvAU7JaaZ;~!#dVQgpoMy#+AK_#ww3$D~k z7x)oq@sjvjBhxkSaEZUq1Zf=`$%vsD=__4#hF_`rH9){stysr+5Ulx&)!v z#w=xKj6<<;%m!b=5%9D7)f^v3I6paM@LMy)q`M-l{1ANi0W$GTs5nTe>lp(B zRBmMuW{Eiora6~P);%vWu`-eV$G92Qf_EBX6<1CUWA4n)Jdkjij*Ps+tj4DyST{9j_mZ5Z1X7HP2a}&QnP?UGVy@bT&^S5~UnXc{oDAc-Rkoa~9T7b`DNhQpX z`txHHYAlk1z0_eZLy60B*&$I9t4SygHC9m^n)Hc|LSZW@G3a?u`k1Ibe;qZE-*wTn zl+L7BzV1Ati}h?m#H6-sJqcEE6^xiFG6CZcmKE0xdM06#FIiZjudL8r%M8>x(`=IwC|-1 z;ka`jqf{&_ll3H$w&=_f>)BtSmK=N5ok?gowXl#qk-aZ5*e0A%R+EL^VV9uRMe2W2 za+{!w>EscqJO<3Ir*U-fq|(arquQN2mTS}7byo^}XuhjF5whX2mZSu&XPQ_~4pkFN zZ#_sHm%+tLf3UP1?nK-v`jYZwc-e+DkJPyYO}>P?rB=f_=o^^pMc9(c}CjhFwXBsF$mM|V%M|_s31k$)8uUTw_c>kUar@& zj*+M9VWPx4#~GAjvMe4~nyKd^{E%f9&qurYLd=7kHEP#Wp_H_!_0Ko)?>#6R$r6+I z@m&fK(4C_gZakKZKsb<%?GM_W&5{+$v*u^woKUhx>FYDqBPc=qv3CPhQx(icBPW3@ zw0bK^q}T`xQxUe{ocYq3axHQUgiLdF63HoTZnI5P0p!`W-ChUjPFqQ#=imbkZ#v(D z&x$qLwIUF7@lh=4Mr7X-W6COvLb&n)u$C=goXplW<=OojT$hkj`WJ4ZIFE;o2r5=) z7BaJyCQmLiD<89Ccgz!ta@gJ$zkR`K%1yZVA5-Xwj1zJI%9RPUS5E_jHSwbC8?k+% zgT(w8ajGOy@0r;CT?+L&T#u5G9g*&$@G^@F+_aRKj_ucI_sT%fqeV%oqz_aYLH+=5 zE9=y@qmm)A6c#_0vadB8Q!0eggj>A;-kq)C{vajthEtcZ^UG|Gr`GH30?MsC$d^`lsaY( zl8+LbS@!s7mNX@uZ&Hy)pX`nKZh#WFdC{e;OpqFJLmImdb(7jMRs^WQ^ z(TDLzMvbiUj0a`ps38&ud=N1^oRZdvTf`!cCSCDX*2ibxqz1Fe7@4HZURm9Doyl{C zC)xcJ>fnx=q>1(1{Dhw>N8UL zUCXP51lc*^R%K`zqONiVXZ33 z;89qDBC+Xo48Ghb(yA<#7%*nyybrPIC=nocV;rpzM$Nh>~y2h6Du)v4ZUtVeu04UE}{B+H Date: Wed, 16 Aug 2017 17:23:21 -0400 Subject: [PATCH 19/28] styled the About section --- app/src/pages/home/home.html | 25 ++++++++++++++----------- app/src/pages/home/home.scss | 7 +++++++ 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/app/src/pages/home/home.html b/app/src/pages/home/home.html index 0c30c95..5930d47 100644 --- a/app/src/pages/home/home.html +++ b/app/src/pages/home/home.html @@ -13,17 +13,20 @@

Latest Blocks

Latest Transactions

-

About

-

insight is an open-source Bitcoin blockchain explorer with complete REST and websocket APIs that can be used for writing web wallets and other apps that need more advanced blockchain queries than provided by bitcoind RPC. Check out the source code.

-

insight is still in development, so be sure to report any bugs and provide feedback for improvement at our github issue tracker.

-
-
- Powered by + +
+

About

+

insight is an open-source Bitcoin blockchain explorer with complete REST and websocket APIs that can be used for writing web wallets and other apps that need more advanced blockchain queries than provided by bitcoind RPC. Check out the source code.

+

insight is still in development, so be sure to report any bugs and provide feedback for improvement at our github issue tracker.

+
+
+ Powered by +
+ + + +
- - - -
diff --git a/app/src/pages/home/home.scss b/app/src/pages/home/home.scss index 1597e4c..91b4923 100644 --- a/app/src/pages/home/home.scss +++ b/app/src/pages/home/home.scss @@ -1,4 +1,11 @@ page-home { + .about { + background-color: #F4F4F4; + border: 1px solid #eee; + border-radius: 5px; + padding: 14px; + } + #powered .powered-text { border-top: 1px solid #ddd; margin: 30px auto 0; From e2c69203ec292f4c529ff02873a225eabf1bb14c Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Thu, 17 Aug 2017 11:03:08 -0400 Subject: [PATCH 20/28] Fixed e2e tests --- app/e2e/app.e2e-spec.ts | 4 ++-- app/e2e/broadcastTxPage.e2e-spec.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/e2e/app.e2e-spec.ts b/app/e2e/app.e2e-spec.ts index d1e06d8..03fa8a5 100644 --- a/app/e2e/app.e2e-spec.ts +++ b/app/e2e/app.e2e-spec.ts @@ -26,11 +26,11 @@ describe('InsightApp', () => { }); }); - it('the left menu has a link with title Blocks', () => { + it('the left menu has a link with title Home', () => { element(by.css('.bar-button-menutoggle')).click() .then(() => { browser.driver.sleep(2000); // wait for the animation - expect(element.all(by.css('ion-label')).first().getText()).toEqual('Blocks'); + expect(element.all(by.css('ion-label')).first().getText()).toEqual('Home'); }); }); }); diff --git a/app/e2e/broadcastTxPage.e2e-spec.ts b/app/e2e/broadcastTxPage.e2e-spec.ts index 11943c5..70c34fe 100644 --- a/app/e2e/broadcastTxPage.e2e-spec.ts +++ b/app/e2e/broadcastTxPage.e2e-spec.ts @@ -10,7 +10,7 @@ describe('BroadcastTxPage', () => { element(by.css('.bar-button-menutoggle')).click().then(() => { browser.driver.sleep(2000); // wait for the animation element.all(by.className('input-wrapper')).then((items) => { - items[1].click(); + items[2].click(); browser.driver.sleep(2000); // wait for the animation let theElem = element.all(by.css('ion-label')).first; console.log(theElem); From 879b87f2a6e056b6515546359586f5f3d6c1fd9e Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Thu, 17 Aug 2017 11:47:31 -0400 Subject: [PATCH 21/28] added LatestTransactions and LatestBlocks components with simple placeholders --- app/package.json | 2 +- .../latest-blocks/latest-blocks.html | 4 ++++ .../latest-blocks/latest-blocks.module.ts | 16 ++++++++++++++ .../latest-blocks/latest-blocks.scss | 3 +++ .../components/latest-blocks/latest-blocks.ts | 22 +++++++++++++++++++ .../latest-transactions.html | 4 ++++ .../latest-transactions.module.ts | 16 ++++++++++++++ .../latest-transactions.scss | 3 +++ .../latest-transactions.ts | 22 +++++++++++++++++++ app/src/pages/blocksPage/blocksPage.ts | 2 ++ app/src/pages/home/home.html | 11 ++++++++-- app/src/pages/home/home.module.ts | 4 +++- app/src/pages/pages.module.ts | 10 ++++++++- 13 files changed, 114 insertions(+), 5 deletions(-) create mode 100644 app/src/components/latest-blocks/latest-blocks.html create mode 100644 app/src/components/latest-blocks/latest-blocks.module.ts create mode 100644 app/src/components/latest-blocks/latest-blocks.scss create mode 100644 app/src/components/latest-blocks/latest-blocks.ts create mode 100644 app/src/components/latest-transactions/latest-transactions.html create mode 100644 app/src/components/latest-transactions/latest-transactions.module.ts create mode 100644 app/src/components/latest-transactions/latest-transactions.scss create mode 100644 app/src/components/latest-transactions/latest-transactions.ts diff --git a/app/package.json b/app/package.json index ca2960b..ef5ad15 100644 --- a/app/package.json +++ b/app/package.json @@ -42,7 +42,7 @@ "@types/jasmine": "2.5.41", "@types/node": "7.0.4", "codecov": "2.2.0", - "ionic": "3.9.0", + "ionic": "3.9.1", "jasmine-core": "2.5.2", "jasmine-spec-reporter": "3.2.0", "karma": "1.4.1", diff --git a/app/src/components/latest-blocks/latest-blocks.html b/app/src/components/latest-blocks/latest-blocks.html new file mode 100644 index 0000000..5d363cc --- /dev/null +++ b/app/src/components/latest-blocks/latest-blocks.html @@ -0,0 +1,4 @@ + +
+ {{text}} +
diff --git a/app/src/components/latest-blocks/latest-blocks.module.ts b/app/src/components/latest-blocks/latest-blocks.module.ts new file mode 100644 index 0000000..535f515 --- /dev/null +++ b/app/src/components/latest-blocks/latest-blocks.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from '@angular/core'; +import { IonicModule } from 'ionic-angular'; +import { LatestBlocksComponent } from './latest-blocks'; + +@NgModule({ + declarations: [ + LatestBlocksComponent + ], + imports: [ + IonicModule + ], + exports: [ + LatestBlocksComponent + ] +}) +export class LatestBlocksComponentModule {} diff --git a/app/src/components/latest-blocks/latest-blocks.scss b/app/src/components/latest-blocks/latest-blocks.scss new file mode 100644 index 0000000..f5def0b --- /dev/null +++ b/app/src/components/latest-blocks/latest-blocks.scss @@ -0,0 +1,3 @@ +latest-blocks { + +} diff --git a/app/src/components/latest-blocks/latest-blocks.ts b/app/src/components/latest-blocks/latest-blocks.ts new file mode 100644 index 0000000..db25c56 --- /dev/null +++ b/app/src/components/latest-blocks/latest-blocks.ts @@ -0,0 +1,22 @@ +import { Component } from '@angular/core'; + +/** + * Generated class for the LatestBlocksComponent component. + * + * See https://angular.io/docs/ts/latest/api/core/index/ComponentMetadata-class.html + * for more info on Angular Components. + */ +@Component({ + selector: 'latest-blocks', + templateUrl: 'latest-blocks.html' +}) +export class LatestBlocksComponent { + + private text: string; + + constructor() { + console.log('Hello LatestBlocksComponent Component'); + this.text = 'Hello Latest Blocks'; + } + +} diff --git a/app/src/components/latest-transactions/latest-transactions.html b/app/src/components/latest-transactions/latest-transactions.html new file mode 100644 index 0000000..948536e --- /dev/null +++ b/app/src/components/latest-transactions/latest-transactions.html @@ -0,0 +1,4 @@ + +
+ {{text}} +
diff --git a/app/src/components/latest-transactions/latest-transactions.module.ts b/app/src/components/latest-transactions/latest-transactions.module.ts new file mode 100644 index 0000000..7eb0b92 --- /dev/null +++ b/app/src/components/latest-transactions/latest-transactions.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from '@angular/core'; +import { IonicModule } from 'ionic-angular'; +import { LatestTransactionsComponent } from './latest-transactions'; + +@NgModule({ + declarations: [ + LatestTransactionsComponent + ], + imports: [ + IonicModule + ], + exports: [ + LatestTransactionsComponent + ] +}) +export class LatestTransactionsComponentModule {} diff --git a/app/src/components/latest-transactions/latest-transactions.scss b/app/src/components/latest-transactions/latest-transactions.scss new file mode 100644 index 0000000..570ea96 --- /dev/null +++ b/app/src/components/latest-transactions/latest-transactions.scss @@ -0,0 +1,3 @@ +latest-transactions { + +} diff --git a/app/src/components/latest-transactions/latest-transactions.ts b/app/src/components/latest-transactions/latest-transactions.ts new file mode 100644 index 0000000..5b8d68e --- /dev/null +++ b/app/src/components/latest-transactions/latest-transactions.ts @@ -0,0 +1,22 @@ +import { Component } from '@angular/core'; + +/** + * Generated class for the LatestTransactionsComponent component. + * + * See https://angular.io/docs/ts/latest/api/core/index/ComponentMetadata-class.html + * for more info on Angular Components. + */ +@Component({ + selector: 'latest-transactions', + templateUrl: 'latest-transactions.html' +}) +export class LatestTransactionsComponent { + + private text: string; + + constructor() { + console.log('Hello LatestTransactionsComponent Component'); + this.text = 'Hello Latest Transactions'; + } + +} diff --git a/app/src/pages/blocksPage/blocksPage.ts b/app/src/pages/blocksPage/blocksPage.ts index 5f2eeaf..b48f130 100644 --- a/app/src/pages/blocksPage/blocksPage.ts +++ b/app/src/pages/blocksPage/blocksPage.ts @@ -14,6 +14,8 @@ export class BlocksPage { public blocks: Observable; constructor(private navCtrl: NavController, private blocksService: BlocksService) { + // TODO Put loading spinner on page + this.title = 'Blocks'; this.blocks = blocksService.latestBlocks; this.blocks.subscribe((blocks) => { diff --git a/app/src/pages/home/home.html b/app/src/pages/home/home.html index 5930d47..b29ea51 100644 --- a/app/src/pages/home/home.html +++ b/app/src/pages/home/home.html @@ -11,8 +11,15 @@ -

Latest Blocks

-

Latest Transactions

+
+

Latest Blocks

+ +
+ +
+

Latest Transactions

+ +

About

diff --git a/app/src/pages/home/home.module.ts b/app/src/pages/home/home.module.ts index 9a8ed53..b3d3a15 100644 --- a/app/src/pages/home/home.module.ts +++ b/app/src/pages/home/home.module.ts @@ -2,6 +2,7 @@ import { NgModule } from '@angular/core'; import { IonicPageModule } from 'ionic-angular'; import { HomePage } from './home'; import { HeadNavComponentModule } from '../../components/head-nav/head-nav.module'; +import { LatestTransactionsComponentModule } from '../../components/latest-transactions/latest-transactions.module'; @NgModule({ declarations: [ @@ -9,7 +10,8 @@ import { HeadNavComponentModule } from '../../components/head-nav/head-nav.modul ], imports: [ IonicPageModule.forChild(HomePage), - HeadNavComponentModule + HeadNavComponentModule, + LatestTransactionsComponentModule ], exports: [ HomePage diff --git a/app/src/pages/pages.module.ts b/app/src/pages/pages.module.ts index b76bdd6..4787ac8 100644 --- a/app/src/pages/pages.module.ts +++ b/app/src/pages/pages.module.ts @@ -2,6 +2,8 @@ import { NgModule } from '@angular/core'; import { IonicModule } from 'ionic-angular'; import { ComponentsModule } from '../components'; import { HeadNavComponentModule } from '../components/head-nav/head-nav.module'; +import { LatestTransactionsComponentModule } from '../components/latest-transactions/latest-transactions.module'; +import { LatestBlocksComponentModule } from '../components/latest-blocks/latest-blocks.module'; import { HomePage, BlocksPage, @@ -18,7 +20,13 @@ import { NodeStatusPage, VerifyMessagePage ], - imports: [ IonicModule, ComponentsModule, HeadNavComponentModule ], + imports: [ + IonicModule, + ComponentsModule, + HeadNavComponentModule, + LatestTransactionsComponentModule, + LatestBlocksComponentModule + ], exports: [ // CustomComponent, ], From f2196bc297f3ace3801253981912357a1585d9b4 Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Thu, 17 Aug 2017 16:20:40 -0400 Subject: [PATCH 22/28] added angular2-moment library; added a BlocksProvider; added latest blocks grid to home page --- app/package.json | 1 + app/src/app/app.component.ts | 2 +- app/src/app/app.module.ts | 4 +- .../latest-blocks/latest-blocks.html | 23 ++ .../latest-blocks/latest-blocks.module.ts | 4 +- .../components/latest-blocks/latest-blocks.ts | 24 ++- app/src/providers/blocks/blocks.ts | 23 ++ app/yarn.lock | 203 ++++++++++++++++-- 8 files changed, 267 insertions(+), 17 deletions(-) create mode 100644 app/src/providers/blocks/blocks.ts diff --git a/app/package.json b/app/package.json index ef5ad15..bb7407e 100644 --- a/app/package.json +++ b/app/package.json @@ -27,6 +27,7 @@ "@ionic-native/splash-screen": "3.10.2", "@ionic-native/status-bar": "3.10.2", "@ionic/storage": "2.0.1", + "angular2-moment": "^1.6.0", "angular2-qrcode": "^2.0.1", "ionic-angular": "3.4.2", "ionicons": "3.0.0", diff --git a/app/src/app/app.component.ts b/app/src/app/app.component.ts index 99dcb4b..f089c75 100644 --- a/app/src/app/app.component.ts +++ b/app/src/app/app.component.ts @@ -32,7 +32,7 @@ export class InsightApp { this.splash = splash; this.status = status; - this.rootPage = BlocksPage; + this.rootPage = HomePage; this.initializeApp(); // set our app's pages diff --git a/app/src/app/app.module.ts b/app/src/app/app.module.ts index 9901a7b..7d0c351 100644 --- a/app/src/app/app.module.ts +++ b/app/src/app/app.module.ts @@ -9,6 +9,7 @@ import { PagesModule, HomePage, BlocksPage, BroadcastTxPage, NodeStatusPage, Ver import { BlocksService, StorageService } from '../services'; import { ApiProvider } from '../providers/api/api'; import { CurrencyProvider } from '../providers/currency/currency'; +import { BlocksProvider } from '../providers/blocks/blocks'; @NgModule({ declarations: [ @@ -36,7 +37,8 @@ import { CurrencyProvider } from '../providers/currency/currency'; BlocksService, {provide: ErrorHandler, useClass: IonicErrorHandler}, ApiProvider, - CurrencyProvider + CurrencyProvider, + BlocksProvider ] }) diff --git a/app/src/components/latest-blocks/latest-blocks.html b/app/src/components/latest-blocks/latest-blocks.html index 5d363cc..6595647 100644 --- a/app/src/components/latest-blocks/latest-blocks.html +++ b/app/src/components/latest-blocks/latest-blocks.html @@ -1,4 +1,27 @@
{{text}} + + + + Height + Age + Transactions + Size + + + + {{block.height}} + + + {{ block.time | amFromUnix | amTimeAgo }} + + + {{block.txlength}} + + + {{ block.size }} + + +
diff --git a/app/src/components/latest-blocks/latest-blocks.module.ts b/app/src/components/latest-blocks/latest-blocks.module.ts index 535f515..f2086b9 100644 --- a/app/src/components/latest-blocks/latest-blocks.module.ts +++ b/app/src/components/latest-blocks/latest-blocks.module.ts @@ -1,13 +1,15 @@ import { NgModule } from '@angular/core'; import { IonicModule } from 'ionic-angular'; import { LatestBlocksComponent } from './latest-blocks'; +import { MomentModule } from 'angular2-moment'; @NgModule({ declarations: [ LatestBlocksComponent ], imports: [ - IonicModule + IonicModule, + MomentModule ], exports: [ LatestBlocksComponent diff --git a/app/src/components/latest-blocks/latest-blocks.ts b/app/src/components/latest-blocks/latest-blocks.ts index db25c56..cb7ae42 100644 --- a/app/src/components/latest-blocks/latest-blocks.ts +++ b/app/src/components/latest-blocks/latest-blocks.ts @@ -1,4 +1,5 @@ import { Component } from '@angular/core'; +import { BlocksProvider } from '../../providers/blocks/blocks'; /** * Generated class for the LatestBlocksComponent component. @@ -13,10 +14,29 @@ import { Component } from '@angular/core'; export class LatestBlocksComponent { private text: string; + public blocks: Array = []; - constructor() { - console.log('Hello LatestBlocksComponent Component'); + constructor(private blocksProvider: BlocksProvider) { this.text = 'Hello Latest Blocks'; + + blocksProvider.getBlocks().subscribe( + (data) => { + this.blocks = JSON.parse(data['_body']).blocks; + console.log('blocks', this.blocks); + }, + (err) => { + console.log('err', err); + } + ); } + public goToBlock(hash: string): void { + console.log('go to', hash); + } + + public getBlocks(num: number = 10): Array { + /* tslint:disable:no-unused-variable */ + return this.blocks.filter((block, index) => index < num); + /* tslint:enable:no-unused-variable */ + } } diff --git a/app/src/providers/blocks/blocks.ts b/app/src/providers/blocks/blocks.ts new file mode 100644 index 0000000..6ab163c --- /dev/null +++ b/app/src/providers/blocks/blocks.ts @@ -0,0 +1,23 @@ +import { Injectable } from '@angular/core'; +import { Http } from '@angular/http'; +import 'rxjs/add/operator/map'; +import { ApiProvider } from '../../providers/api/api'; + +/* + Generated class for the BlocksProvider provider. + + See https://angular.io/docs/ts/latest/guide/dependency-injection.html + for more info on providers and Angular DI. +*/ +@Injectable() +export class BlocksProvider { + + constructor(public http: Http, private api: ApiProvider) { + console.log('Hello BlocksProvider Provider'); + } + + public getBlocks(): any { + return this.http.get(this.api.apiPrefix + 'blocks'); + } + +} diff --git a/app/yarn.lock b/app/yarn.lock index 53191d9..575bfc5 100644 --- a/app/yarn.lock +++ b/app/yarn.lock @@ -200,6 +200,39 @@ uuid "^3.0.1" wrap-ansi "^3.0.1" +"@ionic/cli-utils@1.9.1": + version "1.9.1" + resolved "https://registry.yarnpkg.com/@ionic/cli-utils/-/cli-utils-1.9.1.tgz#a0118819cb8de1f3bc4bc5b401e5b61d7f41d5b5" + dependencies: + "@types/gulp" "^3.8.33" + archiver "^2.0.0" + chalk "^2.0.0" + chokidar "^1.7.0" + ci-info "^1.0.0" + cross-spawn "^5.1.0" + dargs "^5.1.0" + diff "^3.3.0" + elementtree "^0.1.7" + express "^4.15.4" + inquirer "^3.2.1" + leek "0.0.24" + lodash "^4.17.4" + minimist "^1.2.0" + ncp "^2.0.0" + opn "^5.1.0" + proxy-middleware "^0.15.0" + semver "^5.4.1" + slice-ansi "^1.0.0" + ssh-config "^1.0.1" + string-width "^2.1.1" + strip-ansi "^4.0.0" + superagent "^3.5.2" + tar "^2.2.1" + tiny-lr "^1.0.5" + tslib "^1.7.1" + uuid "^3.0.1" + wrap-ansi "^3.0.1" + "@ionic/storage@2.0.1": version "2.0.1" resolved "https://registry.yarnpkg.com/@ionic/storage/-/storage-2.0.1.tgz#bb1a8c276007d008d7acdda426b56065b0fd3c0b" @@ -221,6 +254,14 @@ magic-string "^0.19.0" source-map "^0.5.6" +"@types/gulp@^3.8.33": + version "3.8.33" + resolved "https://registry.yarnpkg.com/@types/gulp/-/gulp-3.8.33.tgz#b1b076820738c9c4eb7808cd926bff1683e1c2ab" + dependencies: + "@types/node" "*" + "@types/orchestrator" "*" + "@types/vinyl" "*" + "@types/jasmine@2.5.41": version "2.5.41" resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.5.41.tgz#d5e86161a0af80d52062b310a33ed65b051a0713" @@ -229,6 +270,10 @@ version "0.0.30" resolved "https://registry.yarnpkg.com/@types/localforage/-/localforage-0.0.30.tgz#3d60a6bf6dda38e3f8a469611598379f1f649509" +"@types/node@*": + version "8.0.24" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.24.tgz#06c580084d9add1fb40c1510ef0b448961246fb1" + "@types/node@7.0.4": version "7.0.4" resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.4.tgz#9aabc135979ded383325749f508894c662948c8b" @@ -237,6 +282,17 @@ version "6.0.79" resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.79.tgz#5efe7d4a6d8c453c7e9eaf55d931f4a22fac5169" +"@types/orchestrator@*": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@types/orchestrator/-/orchestrator-0.3.0.tgz#bf84a1699c9330d4fe89cd81263e8fc09fb32978" + dependencies: + "@types/node" "*" + "@types/q" "^0" + +"@types/q@^0": + version "0.0.36" + resolved "https://registry.yarnpkg.com/@types/q/-/q-0.0.36.tgz#97d786389641bcbd0e22bfc729a534175976371d" + "@types/q@^0.0.32": version "0.0.32" resolved "https://registry.yarnpkg.com/@types/q/-/q-0.0.32.tgz#bd284e57c84f1325da702babfc82a5328190c0c5" @@ -245,6 +301,12 @@ version "2.53.42" resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-2.53.42.tgz#74cb77fb6052edaff2a8984ddafd88d419f25cac" +"@types/vinyl@*": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/vinyl/-/vinyl-2.0.0.tgz#fd213bf7f4136dde21fe1895500b12c186f8c268" + dependencies: + "@types/node" "*" + abbrev@1: version "1.1.0" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" @@ -335,6 +397,12 @@ amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" +angular2-moment@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/angular2-moment/-/angular2-moment-1.6.0.tgz#2be11b63d9cbdff8fee06f575c1beee2d863d62b" + dependencies: + moment "^2.16.0" + angular2-qrcode@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/angular2-qrcode/-/angular2-qrcode-2.0.1.tgz#1b4e65c302694b5078ca06f71138f7e4367754dc" @@ -1256,7 +1324,7 @@ chokidar@1.6.1: optionalDependencies: fsevents "^1.0.0" -chokidar@^1.4.1, chokidar@^1.4.3, chokidar@^1.6.0, chokidar@^1.6.1: +chokidar@^1.4.1, chokidar@^1.4.3, chokidar@^1.6.0, chokidar@^1.6.1, chokidar@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" dependencies: @@ -1800,7 +1868,7 @@ date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" -debug@*, debug@2, debug@2.6.8, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.6.3, debug@^2.6.8: +debug@*, debug@2, debug@2.6.8, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.6.3, debug@^2.6.8, debug@~2.6.7: version "2.6.8" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" dependencies: @@ -1880,6 +1948,10 @@ depd@1.1.0, depd@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" +depd@1.1.1, depd@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" + des.js@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" @@ -1917,6 +1989,10 @@ diff@^3.1.0, diff@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" +diff@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.0.tgz#056695150d7aa93237ca7e378ac3b1682b7963b9" + diffie-hellman@^5.0.0: version "5.0.2" resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e" @@ -2327,6 +2403,39 @@ express@^4.13.3: utils-merge "1.0.0" vary "~1.1.1" +express@^4.15.4: + version "4.15.4" + resolved "https://registry.yarnpkg.com/express/-/express-4.15.4.tgz#032e2253489cf8fce02666beca3d11ed7a2daed1" + dependencies: + accepts "~1.3.3" + array-flatten "1.1.1" + content-disposition "0.5.2" + content-type "~1.0.2" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "2.6.8" + depd "~1.1.1" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.8.0" + finalhandler "~1.0.4" + fresh "0.5.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.1" + path-to-regexp "0.1.7" + proxy-addr "~1.1.5" + qs "6.5.0" + range-parser "~1.2.0" + send "0.15.4" + serve-static "1.12.4" + setprototypeof "1.0.3" + statuses "~1.3.1" + type-is "~1.6.15" + utils-merge "1.0.0" + vary "~1.1.1" + extend@3, extend@^3.0.0, extend@~3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" @@ -2446,6 +2555,18 @@ finalhandler@1.0.3, finalhandler@~1.0.3: statuses "~1.3.1" unpipe "~1.0.0" +finalhandler@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.4.tgz#18574f2e7c4b98b8ae3b230c21f201f31bdb3fb7" + dependencies: + debug "2.6.8" + encodeurl "~1.0.1" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.1" + statuses "~1.3.1" + unpipe "~1.0.0" + find-up@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" @@ -2913,6 +3034,15 @@ http-errors@~1.6.1: setprototypeof "1.0.3" statuses ">= 1.3.1 < 2" +http-errors@~1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" + dependencies: + depd "1.1.1" + inherits "2.0.3" + setprototypeof "1.0.3" + statuses ">= 1.3.1 < 2" + http-proxy-middleware@~0.17.4: version "0.17.4" resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz#642e8848851d66f09d4f124912846dbaeb41b833" @@ -3093,20 +3223,16 @@ ionic-angular@3.4.2: version "3.4.2" resolved "https://registry.yarnpkg.com/ionic-angular/-/ionic-angular-3.4.2.tgz#762631f1af78a5ae1c0aa0f4d23b31435142abe1" -ionic@3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/ionic/-/ionic-3.7.0.tgz#a3c32174c6d5455c3bc74b6b9152e0f97dce23c8" +ionic@3.9.1: + version "3.9.1" + resolved "https://registry.yarnpkg.com/ionic/-/ionic-3.9.1.tgz#be50eea2f55bad40574772ecaeaf5a460fd16330" dependencies: - "@ionic/cli-utils" "1.7.0" + "@ionic/cli-utils" "1.9.1" chalk "^2.0.0" - diff "^3.2.0" - minimist "^1.2.0" opn "^5.1.0" os-name "^2.0.1" rimraf "^2.6.1" semver "^5.3.0" - ssh-config "^1.0.1" - tar "^2.2.1" tslib "^1.7.1" ionicons@3.0.0: @@ -3121,6 +3247,10 @@ ipaddr.js@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.3.0.tgz#1e03a52fdad83a8bbb2b25cbf4998b4cffcd3dec" +ipaddr.js@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.4.0.tgz#296aca878a821816e5b85d0a285a99bcff4582f0" + is-absolute-url@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" @@ -4106,6 +4236,10 @@ mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkd dependencies: minimist "0.0.8" +moment@^2.16.0: + version "2.18.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f" + ms@0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" @@ -5004,7 +5138,14 @@ proxy-addr@~1.1.3, proxy-addr@~1.1.4: forwarded "~0.1.0" ipaddr.js "1.3.0" -proxy-middleware@0.15.0: +proxy-addr@~1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.5.tgz#71c0ee3b102de3f202f3b64f608d173fcba1a918" + dependencies: + forwarded "~0.1.0" + ipaddr.js "1.4.0" + +proxy-middleware@0.15.0, proxy-middleware@^0.15.0: version "0.15.0" resolved "https://registry.yarnpkg.com/proxy-middleware/-/proxy-middleware-0.15.0.tgz#a3fdf1befb730f951965872ac2f6074c61477a56" @@ -5060,7 +5201,7 @@ qs@6.4.0, qs@~6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" -qs@^6.1.0, qs@^6.2.0: +qs@6.5.0, qs@^6.1.0, qs@^6.2.0, qs@^6.4.0: version "6.5.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.0.tgz#8d04954d364def3efc55b5a0793e1e2c8b1e6e49" @@ -5645,6 +5786,24 @@ send@0.15.3: range-parser "~1.2.0" statuses "~1.3.1" +send@0.15.4: + version "0.15.4" + resolved "https://registry.yarnpkg.com/send/-/send-0.15.4.tgz#985faa3e284b0273c793364a35c6737bd93905b9" + dependencies: + debug "2.6.8" + depd "~1.1.1" + destroy "~1.0.4" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.8.0" + fresh "0.5.0" + http-errors "~1.6.2" + mime "1.3.4" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.3.1" + serve-index@^1.7.2: version "1.9.0" resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.0.tgz#d2b280fc560d616ee81b48bf0fa82abed2485ce7" @@ -5666,6 +5825,15 @@ serve-static@1.12.3: parseurl "~1.3.1" send "0.15.3" +serve-static@1.12.4: + version "1.12.4" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.4.tgz#9b6aa98eeb7253c4eedc4c1f6fdbca609901a961" + dependencies: + encodeurl "~1.0.1" + escape-html "~1.0.3" + parseurl "~1.3.1" + send "0.15.4" + serve-static@~1.11.2: version "1.11.2" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.11.2.tgz#2cf9889bd4435a320cc36895c9aa57bd662e6ac7" @@ -6203,6 +6371,17 @@ tiny-lr@1.0.3: object-assign "^4.1.0" qs "^6.2.0" +tiny-lr@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-1.0.5.tgz#21f40bf84ebd1f853056680375eef1670c334112" + dependencies: + body "^5.1.0" + debug "~2.6.7" + faye-websocket "~0.10.0" + livereload-js "^2.2.2" + object-assign "^4.1.0" + qs "^6.4.0" + tmp@0.0.24: version "0.0.24" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.24.tgz#d6a5e198d14a9835cc6f2d7c3d9e302428c8cf12" From cdbc84e93a6fbe461ada07291276f8bc5b94a2ce Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Thu, 17 Aug 2017 16:42:09 -0400 Subject: [PATCH 23/28] added loading spinner and links to block detail --- .../latest-blocks/latest-blocks.html | 51 ++++++++++--------- .../components/latest-blocks/latest-blocks.ts | 16 +++--- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/app/src/components/latest-blocks/latest-blocks.html b/app/src/components/latest-blocks/latest-blocks.html index 6595647..320ae6f 100644 --- a/app/src/components/latest-blocks/latest-blocks.html +++ b/app/src/components/latest-blocks/latest-blocks.html @@ -1,27 +1,32 @@
- {{text}} - +
+ +
- - Height - Age - Transactions - Size - - - - {{block.height}} - - - {{ block.time | amFromUnix | amTimeAgo }} - - - {{block.txlength}} - - - {{ block.size }} - - -
+
+ + + + Height + Age + Transactions + Size + + + + {{block.height}} + + + {{ block.time | amFromUnix | amTimeAgo }} + + + {{block.txlength}} + + + {{ block.size }} + + + +
diff --git a/app/src/components/latest-blocks/latest-blocks.ts b/app/src/components/latest-blocks/latest-blocks.ts index cb7ae42..5ecbebe 100644 --- a/app/src/components/latest-blocks/latest-blocks.ts +++ b/app/src/components/latest-blocks/latest-blocks.ts @@ -1,5 +1,6 @@ import { Component } from '@angular/core'; import { BlocksProvider } from '../../providers/blocks/blocks'; +import { NavController } from 'ionic-angular'; /** * Generated class for the LatestBlocksComponent component. @@ -13,25 +14,26 @@ import { BlocksProvider } from '../../providers/blocks/blocks'; }) export class LatestBlocksComponent { - private text: string; + public loading: boolean = true; public blocks: Array = []; - constructor(private blocksProvider: BlocksProvider) { - this.text = 'Hello Latest Blocks'; - + constructor(private blocksProvider: BlocksProvider, private navCtrl: NavController) { blocksProvider.getBlocks().subscribe( (data) => { this.blocks = JSON.parse(data['_body']).blocks; - console.log('blocks', this.blocks); + this.loading = false; }, (err) => { console.log('err', err); + this.loading = false; } ); } - public goToBlock(hash: string): void { - console.log('go to', hash); + public goToBlock(blockHash: string): void { + this.navCtrl.push('block-detail', { + 'blockHash': blockHash + }); } public getBlocks(num: number = 10): Array { From 722eb21cfb4d01ab4754f4106d8ae952d92f3691 Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Fri, 18 Aug 2017 11:33:41 -0400 Subject: [PATCH 24/28] Added interval to get latest blocks and styled latest blocks grid --- .../latest-blocks/latest-blocks.scss | 16 ++++++++++ .../components/latest-blocks/latest-blocks.ts | 12 ++++++- .../latest-transactions.ts | 32 ++++++++++++++++++- .../components/transaction/transaction.scss | 3 ++ 4 files changed, 61 insertions(+), 2 deletions(-) diff --git a/app/src/components/latest-blocks/latest-blocks.scss b/app/src/components/latest-blocks/latest-blocks.scss index f5def0b..c9a1377 100644 --- a/app/src/components/latest-blocks/latest-blocks.scss +++ b/app/src/components/latest-blocks/latest-blocks.scss @@ -1,3 +1,19 @@ latest-blocks { + ion-grid { + // border: 2px solid green; + margin: 10px 0 20px; + ion-row { + border-top: 1px solid #ccc; + } + + ion-row:nth-child(even) { + background-color: #f4f4f4; + } + + ion-row:first-child { + background-color: white; + border-top: none; + } + } } diff --git a/app/src/components/latest-blocks/latest-blocks.ts b/app/src/components/latest-blocks/latest-blocks.ts index 5ecbebe..940fa05 100644 --- a/app/src/components/latest-blocks/latest-blocks.ts +++ b/app/src/components/latest-blocks/latest-blocks.ts @@ -18,7 +18,17 @@ export class LatestBlocksComponent { public blocks: Array = []; constructor(private blocksProvider: BlocksProvider, private navCtrl: NavController) { - blocksProvider.getBlocks().subscribe( + this.loadBlocks(); + setInterval( + function (): void { + this.loadBlocks.call(this); + }.bind(this), + 1000 * 30 + ); + } + + private loadBlocks(): void { + this.blocksProvider.getBlocks().subscribe( (data) => { this.blocks = JSON.parse(data['_body']).blocks; this.loading = false; diff --git a/app/src/components/latest-transactions/latest-transactions.ts b/app/src/components/latest-transactions/latest-transactions.ts index 5b8d68e..51a967c 100644 --- a/app/src/components/latest-transactions/latest-transactions.ts +++ b/app/src/components/latest-transactions/latest-transactions.ts @@ -1,4 +1,6 @@ import { Component } from '@angular/core'; +import { Http } from '@angular/http'; +import { ApiProvider } from '../../providers/api/api'; /** * Generated class for the LatestTransactionsComponent component. @@ -14,9 +16,37 @@ export class LatestTransactionsComponent { private text: string; - constructor() { + constructor(private http: Http, private api: ApiProvider) { console.log('Hello LatestTransactionsComponent Component'); this.text = 'Hello Latest Transactions'; + + /* + let url: string = this.api.apiPrefix + 'txs?' + this.queryType + '=' + this.queryValue; + + this.http.get(url).subscribe( + (data) => { + this.transactions = JSON.parse(data['_body']); + this.loading = false; + }, + (err) => { + console.log('err is', err); + this.loading = false; + } + ); + */ + + /* + this.http.get(this.api.apiPrefix + 'tx/' + this.txId).subscribe( + (data) => { + this.tx = JSON.parse(data['_body']); + this.loading = false; + }, + (err) => { + console.log('err is', err); + this.loading = false; + } + ); + */ } } diff --git a/app/src/components/transaction/transaction.scss b/app/src/components/transaction/transaction.scss index 59fc005..40a22fb 100644 --- a/app/src/components/transaction/transaction.scss +++ b/app/src/components/transaction/transaction.scss @@ -1,4 +1,7 @@ transaction { + // TODO Customize the grid to have 13 columns so that we have 6-col inputs, 6-col outputs, 1 col arrow + // See http://ionicframework.com/docs/api/components/grid/Grid/#customizing-the-grid + ion-grid { background-color: #F4F4F4; border: 1px solid #eee; From 44e85f0decf7509fea19d7db8fd494cb8b8f1296 Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Fri, 18 Aug 2017 15:08:36 -0400 Subject: [PATCH 25/28] added See All Blocks button to latest-blocks component; created new BlocksPage with ionic convention; deprecated previous BlocksPage; fixed e2e tests --- app/e2e/app.e2e-spec.ts | 6 +-- .../latest-blocks/latest-blocks.html | 5 +++ .../latest-blocks/latest-blocks.scss | 4 ++ .../components/latest-blocks/latest-blocks.ts | 6 +++ .../latest-transactions.ts | 6 +-- app/src/pages/blocks/blocks.html | 39 +++++++++++++++++++ app/src/pages/blocks/blocks.module.ts | 18 +++++++++ app/src/pages/blocks/blocks.scss | 23 +++++++++++ app/src/pages/blocks/blocks.ts | 37 ++++++++++++++++++ app/src/pages/blocksPage/blocksPage.ts | 4 +- app/src/pages/index.ts | 2 +- app/src/pages/pages.module.ts | 4 +- 12 files changed, 142 insertions(+), 12 deletions(-) create mode 100644 app/src/pages/blocks/blocks.html create mode 100644 app/src/pages/blocks/blocks.module.ts create mode 100644 app/src/pages/blocks/blocks.scss create mode 100644 app/src/pages/blocks/blocks.ts diff --git a/app/e2e/app.e2e-spec.ts b/app/e2e/app.e2e-spec.ts index 03fa8a5..4b8a378 100644 --- a/app/e2e/app.e2e-spec.ts +++ b/app/e2e/app.e2e-spec.ts @@ -7,17 +7,13 @@ describe('InsightApp', () => { }); it('should have a title', () => { - expect(browser.getTitle()).toEqual('Blocks'); + expect(browser.getTitle()).toEqual('Home'); }); it('should have {nav}', () => { expect(element(by.css('ion-navbar')).isPresent()).toEqual(true); }); - it('should have correct nav text for Home', () => { - expect(element(by.css('ion-navbar:first-child')).getText()).toContain('Blocks'); - }); - it('has a menu button that displays the left menu', () => { element(by.css('.bar-button-menutoggle')).click() .then(() => { diff --git a/app/src/components/latest-blocks/latest-blocks.html b/app/src/components/latest-blocks/latest-blocks.html index 320ae6f..d453741 100644 --- a/app/src/components/latest-blocks/latest-blocks.html +++ b/app/src/components/latest-blocks/latest-blocks.html @@ -27,6 +27,11 @@ {{ block.size }} + + + + +
diff --git a/app/src/components/latest-blocks/latest-blocks.scss b/app/src/components/latest-blocks/latest-blocks.scss index c9a1377..0ae897d 100644 --- a/app/src/components/latest-blocks/latest-blocks.scss +++ b/app/src/components/latest-blocks/latest-blocks.scss @@ -15,5 +15,9 @@ latest-blocks { background-color: white; border-top: none; } + + ion-row:last-child { + background-color: white; + } } } diff --git a/app/src/components/latest-blocks/latest-blocks.ts b/app/src/components/latest-blocks/latest-blocks.ts index 940fa05..34200b1 100644 --- a/app/src/components/latest-blocks/latest-blocks.ts +++ b/app/src/components/latest-blocks/latest-blocks.ts @@ -19,12 +19,14 @@ export class LatestBlocksComponent { constructor(private blocksProvider: BlocksProvider, private navCtrl: NavController) { this.loadBlocks(); + /* setInterval( function (): void { this.loadBlocks.call(this); }.bind(this), 1000 * 30 ); + */ } private loadBlocks(): void { @@ -51,4 +53,8 @@ export class LatestBlocksComponent { return this.blocks.filter((block, index) => index < num); /* tslint:enable:no-unused-variable */ } + + public goToBlocks(): void { + this.navCtrl.push('blocks'); + } } diff --git a/app/src/components/latest-transactions/latest-transactions.ts b/app/src/components/latest-transactions/latest-transactions.ts index 51a967c..4650fff 100644 --- a/app/src/components/latest-transactions/latest-transactions.ts +++ b/app/src/components/latest-transactions/latest-transactions.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; -import { Http } from '@angular/http'; -import { ApiProvider } from '../../providers/api/api'; +// import { Http } from '@angular/http'; +// import { ApiProvider } from '../../providers/api/api'; /** * Generated class for the LatestTransactionsComponent component. @@ -16,7 +16,7 @@ export class LatestTransactionsComponent { private text: string; - constructor(private http: Http, private api: ApiProvider) { + constructor(/*private http: Http, private api: ApiProvider*/) { console.log('Hello LatestTransactionsComponent Component'); this.text = 'Hello Latest Transactions'; diff --git a/app/src/pages/blocks/blocks.html b/app/src/pages/blocks/blocks.html new file mode 100644 index 0000000..6f82937 --- /dev/null +++ b/app/src/pages/blocks/blocks.html @@ -0,0 +1,39 @@ + + + + + +
+ +
+ +
+

Blocks

+ + + Height + Timestamp + Transactions + Mined By + Size + + + + {{block.height}} + + + {{ block.time * 1000 | date:'medium' }} + + + {{ block.txlength }} + + + {{block.poolInfo.poolName}} + + + {{ block.size }} + + + +
+
diff --git a/app/src/pages/blocks/blocks.module.ts b/app/src/pages/blocks/blocks.module.ts new file mode 100644 index 0000000..0ec9cc7 --- /dev/null +++ b/app/src/pages/blocks/blocks.module.ts @@ -0,0 +1,18 @@ +import { NgModule } from '@angular/core'; +import { IonicPageModule } from 'ionic-angular'; +import { BlocksPage } from './blocks'; +import { HeadNavComponentModule } from '../../components/head-nav/head-nav.module'; + +@NgModule({ + declarations: [ + BlocksPage + ], + imports: [ + IonicPageModule.forChild(BlocksPage), + HeadNavComponentModule + ], + exports: [ + BlocksPage + ] +}) +export class BlocksPageModule {} diff --git a/app/src/pages/blocks/blocks.scss b/app/src/pages/blocks/blocks.scss new file mode 100644 index 0000000..563b211 --- /dev/null +++ b/app/src/pages/blocks/blocks.scss @@ -0,0 +1,23 @@ +page-blocks { + ion-grid { + // border: 2px solid green; + margin: 10px 0 20px; + + ion-row { + border-top: 1px solid #ccc; + } + + ion-row:nth-child(even) { + background-color: #f4f4f4; + } + + ion-row:first-child { + background-color: white; + border-top: none; + } + + ion-row:last-child { + background-color: white; + } + } +} diff --git a/app/src/pages/blocks/blocks.ts b/app/src/pages/blocks/blocks.ts new file mode 100644 index 0000000..5dcf67c --- /dev/null +++ b/app/src/pages/blocks/blocks.ts @@ -0,0 +1,37 @@ +import { Component } from '@angular/core'; +import { IonicPage, NavController, NavParams } from 'ionic-angular'; +import { BlocksProvider } from '../../providers/blocks/blocks'; + +/** + * Generated class for the BlocksPage page. + * + * See http://ionicframework.com/docs/components/#navigation for more info + * on Ionic pages and navigation. + */ +@IonicPage({ + name: 'blocks', + segment: 'blocks/' +}) +@Component({ + selector: 'page-blocks', + templateUrl: 'blocks.html' +}) +export class BlocksPage { + + public loading: boolean = true; + public blocks: Array = []; + + constructor(public navCtrl: NavController, public navParams: NavParams, private blocksProvider: BlocksProvider) { + this.blocksProvider.getBlocks().subscribe( + (data) => { + this.blocks = JSON.parse(data['_body']).blocks; + console.log('this.blocks', this.blocks); + this.loading = false; + }, + (err) => { + console.log('err', err); + this.loading = false; + } + ); + } +} diff --git a/app/src/pages/blocksPage/blocksPage.ts b/app/src/pages/blocksPage/blocksPage.ts index b48f130..e5273a4 100644 --- a/app/src/pages/blocksPage/blocksPage.ts +++ b/app/src/pages/blocksPage/blocksPage.ts @@ -4,10 +4,12 @@ import { Observable } from 'rxjs'; import { Block } from '../../models'; import { BlocksService } from '../../services'; +/** + * @deprecated Use BlocksPage from ../blocks/blocks + */ @Component({ templateUrl: './blocksPage.html' }) - export class BlocksPage { public title: string; diff --git a/app/src/pages/index.ts b/app/src/pages/index.ts index 19b1b7c..67a109d 100644 --- a/app/src/pages/index.ts +++ b/app/src/pages/index.ts @@ -1,6 +1,6 @@ -export * from './blocksPage/blocksPage'; export * from './broadcastTxPage/broadcastTxPage'; export * from './nodeStatusPage/nodeStatusPage'; export * from './verifyMessagePage/verifyMessagePage'; export * from './home/home'; +export * from './blocks/blocks'; export * from './pages.module'; diff --git a/app/src/pages/pages.module.ts b/app/src/pages/pages.module.ts index 4787ac8..6156b14 100644 --- a/app/src/pages/pages.module.ts +++ b/app/src/pages/pages.module.ts @@ -1,12 +1,12 @@ import { NgModule } from '@angular/core'; import { IonicModule } from 'ionic-angular'; import { ComponentsModule } from '../components'; +import { BlocksPageModule } from '../pages/blocks/blocks.module'; import { HeadNavComponentModule } from '../components/head-nav/head-nav.module'; import { LatestTransactionsComponentModule } from '../components/latest-transactions/latest-transactions.module'; import { LatestBlocksComponentModule } from '../components/latest-blocks/latest-blocks.module'; import { HomePage, - BlocksPage, BroadcastTxPage, NodeStatusPage, VerifyMessagePage @@ -15,7 +15,6 @@ import { @NgModule({ declarations: [ HomePage, - BlocksPage, BroadcastTxPage, NodeStatusPage, VerifyMessagePage @@ -23,6 +22,7 @@ import { imports: [ IonicModule, ComponentsModule, + BlocksPageModule, HeadNavComponentModule, LatestTransactionsComponentModule, LatestBlocksComponentModule From 5e79d1d4f34df107822b922d3961e2af0fc8a04e Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Fri, 18 Aug 2017 15:59:57 -0400 Subject: [PATCH 26/28] wrapped setInterval in ngZone to make e2e tests work properly --- .../components/latest-blocks/latest-blocks.ts | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/app/src/components/latest-blocks/latest-blocks.ts b/app/src/components/latest-blocks/latest-blocks.ts index 34200b1..cd1155a 100644 --- a/app/src/components/latest-blocks/latest-blocks.ts +++ b/app/src/components/latest-blocks/latest-blocks.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, NgZone } from '@angular/core'; import { BlocksProvider } from '../../providers/blocks/blocks'; import { NavController } from 'ionic-angular'; @@ -17,16 +17,18 @@ export class LatestBlocksComponent { public loading: boolean = true; public blocks: Array = []; - constructor(private blocksProvider: BlocksProvider, private navCtrl: NavController) { + constructor(private blocksProvider: BlocksProvider, private navCtrl: NavController, ngZone: NgZone) { this.loadBlocks(); - /* - setInterval( - function (): void { - this.loadBlocks.call(this); - }.bind(this), - 1000 * 30 - ); - */ + ngZone.runOutsideAngular(() => { + setInterval( + function (): void { + ngZone.run(function (): void { + this.loadBlocks.call(this); + }.bind(this)); + }.bind(this), + 1000 * 30 + ); + }); } private loadBlocks(): void { From d5adf90a9b84cf45eb4237e0f8263800c4102817 Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Fri, 18 Aug 2017 17:08:58 -0400 Subject: [PATCH 27/28] added input parms for latest-blocks component; replaced block grid on blocks page with latest-blocks component --- .../latest-blocks/latest-blocks.html | 16 ++++++++--- .../components/latest-blocks/latest-blocks.ts | 9 ++++--- app/src/pages/blocks/blocks.html | 27 +------------------ app/src/pages/blocks/blocks.module.ts | 4 ++- app/src/pages/home/home.html | 2 +- 5 files changed, 23 insertions(+), 35 deletions(-) diff --git a/app/src/components/latest-blocks/latest-blocks.html b/app/src/components/latest-blocks/latest-blocks.html index d453741..b269bdd 100644 --- a/app/src/components/latest-blocks/latest-blocks.html +++ b/app/src/components/latest-blocks/latest-blocks.html @@ -9,25 +9,33 @@ Height - Age + Age + Timestamp Transactions + Mined By Size - + {{block.height}} - + {{ block.time | amFromUnix | amTimeAgo }} + + {{ block.time * 1000 | date:'medium' }} + {{block.txlength}} + + {{block.poolInfo.poolName}} + {{ block.size }} - + diff --git a/app/src/components/latest-blocks/latest-blocks.ts b/app/src/components/latest-blocks/latest-blocks.ts index cd1155a..21fc1e4 100644 --- a/app/src/components/latest-blocks/latest-blocks.ts +++ b/app/src/components/latest-blocks/latest-blocks.ts @@ -1,4 +1,4 @@ -import { Component, NgZone } from '@angular/core'; +import { Component, NgZone, Input } from '@angular/core'; import { BlocksProvider } from '../../providers/blocks/blocks'; import { NavController } from 'ionic-angular'; @@ -16,6 +16,9 @@ export class LatestBlocksComponent { public loading: boolean = true; public blocks: Array = []; + @Input() public numBlocks: number; + @Input() public showAllBlocksButton: boolean; + @Input() public showTimeAs: string; constructor(private blocksProvider: BlocksProvider, private navCtrl: NavController, ngZone: NgZone) { this.loadBlocks(); @@ -50,9 +53,9 @@ export class LatestBlocksComponent { }); } - public getBlocks(num: number = 10): Array { + public getBlocks(): Array { /* tslint:disable:no-unused-variable */ - return this.blocks.filter((block, index) => index < num); + return this.blocks.filter((block, index) => index < this.numBlocks); /* tslint:enable:no-unused-variable */ } diff --git a/app/src/pages/blocks/blocks.html b/app/src/pages/blocks/blocks.html index 6f82937..54d52dc 100644 --- a/app/src/pages/blocks/blocks.html +++ b/app/src/pages/blocks/blocks.html @@ -9,31 +9,6 @@

Blocks

- - - Height - Timestamp - Transactions - Mined By - Size - - - - {{block.height}} - - - {{ block.time * 1000 | date:'medium' }} - - - {{ block.txlength }} - - - {{block.poolInfo.poolName}} - - - {{ block.size }} - - - +
diff --git a/app/src/pages/blocks/blocks.module.ts b/app/src/pages/blocks/blocks.module.ts index 0ec9cc7..521ae44 100644 --- a/app/src/pages/blocks/blocks.module.ts +++ b/app/src/pages/blocks/blocks.module.ts @@ -2,6 +2,7 @@ import { NgModule } from '@angular/core'; import { IonicPageModule } from 'ionic-angular'; import { BlocksPage } from './blocks'; import { HeadNavComponentModule } from '../../components/head-nav/head-nav.module'; +import { LatestBlocksComponentModule } from '../../components/latest-blocks/latest-blocks.module'; @NgModule({ declarations: [ @@ -9,7 +10,8 @@ import { HeadNavComponentModule } from '../../components/head-nav/head-nav.modul ], imports: [ IonicPageModule.forChild(BlocksPage), - HeadNavComponentModule + HeadNavComponentModule, + LatestBlocksComponentModule ], exports: [ BlocksPage diff --git a/app/src/pages/home/home.html b/app/src/pages/home/home.html index b29ea51..ad57d6d 100644 --- a/app/src/pages/home/home.html +++ b/app/src/pages/home/home.html @@ -13,7 +13,7 @@

Latest Blocks

- +
From d4d5e500d6785423a7266f8473fe83a8ff2c764a Mon Sep 17 00:00:00 2001 From: Darren Nelsen Date: Fri, 18 Aug 2017 18:00:17 -0400 Subject: [PATCH 28/28] hide the "mined by" column when in "portrait" mode --- app/src/components/latest-blocks/latest-blocks.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/components/latest-blocks/latest-blocks.html b/app/src/components/latest-blocks/latest-blocks.html index b269bdd..8268be4 100644 --- a/app/src/components/latest-blocks/latest-blocks.html +++ b/app/src/components/latest-blocks/latest-blocks.html @@ -12,7 +12,7 @@ Age Timestamp Transactions - Mined By + Mined By Size @@ -28,7 +28,7 @@ {{block.txlength}} - + {{block.poolInfo.poolName}}