Skip to content

Commit

Permalink
feature(insight): clean up, document
Browse files Browse the repository at this point in the history
  • Loading branch information
bitjson committed Feb 11, 2019
1 parent 5276b5a commit 6ed6fcb
Show file tree
Hide file tree
Showing 14 changed files with 99 additions and 147 deletions.
29 changes: 29 additions & 0 deletions packages/insight/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,35 @@ import {
availableChainsMatcher
} from './guards/available-chain.guard';

/**
* **Implementation note**
* In Insight, the router is the source-of-truth for most state in the app. When
* the app loads, the route is check to select the proper view and data to
* display. (`AvailableChainGuard` checks to see if the Chain referenced by the
* route is enabled by the connected `bitcore-node` instance.)
*
* When any link is clicked, the router should be updated, and all components
* derive their state by watching the `ActivatedRoute`. It's important to encode
* all important state into routing; we want end-users to always be able to
* copy/paste the link to whatever they're seeing.
*
* **TODO**
* TODO: address route: `CHAIN/address/:address`
* TODO: search routes (and search API to `bitcore-node`):
* `/CHAIN/search`: an empty-state search route (happens when the user taps the search icon)
* `/CHAIN/search/:query`: a full listing of matches for `query` (addresses, transactions, blocks)
*
* In `bitcore-node`, a "first bits" search is quite easy, and already indexed:
* `coins.find({address: {$gt: '1JasonD', $lt: '1JasonE'} })`. The same first
* bits search is also easy for transaction hashes and block hashes.
*
* E.g. `/BCH/search/1JasonD` – should be a search listing showing at least 1
* address: `1JasonDm4iqi3TJwgpHKSJYfewJBtKewxP` and at least 4 transactions:
* `43bab209c68f3f7334e38a681b007127af5df0d169e998e9e0dd46cb7ab7f783` – mints to a matching address
* `9871be1cfff51d1180ed3069326f83927503e785a015b8ecd4054a8300068b78` - spends from a matching address
* `217cb4071f20a31599c4353becf39b72f15d5cb71851c00a12514be6568fbfbd` - mints to a matching address
* `628a4a10458c0385e845850fc3fb0a4219baa743dad3b091ec7c9324615bab6d` - spends from a matching address
*/
const routes: Routes = [
{
path: '',
Expand Down
1 change: 0 additions & 1 deletion packages/insight/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Component } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { Platform } from '@ionic/angular';
import { ConfigService } from './services/config/config.service';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject, fromEvent } from 'rxjs';

// TODO: network connected/disconnected notification
@Injectable({
providedIn: 'root'
})
Expand Down
45 changes: 29 additions & 16 deletions packages/insight/src/app/shared/output/output.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,35 @@
</span>
</div>
<ng-container *ngIf="!summary">
<div class="property">
<span class="key">Not summary</span>
<span class="value">something else</span>
</div>
<p>
TODO: this should be the most linked-to view in Insight. It is the ideal
place for most wallets to link to when showing users their previous
"transactions". For most wallets (including Copay/BitPay currently),
users are sending a single payment to a single address in a
"transaction", i.e. an Output. Showing the user only that output makes
for a much better, easier to understand experience.
</p>
<p>
E.g. Alice sends Bob $10. Her wallet creates a transaction using the
closest available output – in Alice's case, she's not used the wallet
much before, and just withdrew $1000 from an exchange. The wallet sends
$10 to Bob, and $990 back to an internal change address. In the
transaction history, Alice can see the $10 payment. Out of curiosity,
she clicks through to "view her transaction on the blockchain". When she
sees the "$1000 transaction" panic ensues.
</p>
<p>
Outputs still need to be designed – we could consider a view that looks
almost like a transaction receipt. If any view in Insight is also for a
"non-technical" audience, it's this one. The most important element is
the `value` (in the user's displayAs currency). Other data we will want
to include: `timeNormalized`, `address` (or `lockingScript` if no
address format applies), "included in transaction", "mined in block",
"confirmations" and if it has already been spent, "used in input".
`lockingScript` should always be possible to see, even if the output has
a valid address (maybe in a detail view, or if the user clicks on the
address).
</p>
</ng-container>
</app-card-item>
</div>
<!-- <div class="card" *ngIf="!summary">
<app-card-item
*ngIf="block.transactionCount > 0"
class="section"
header="Transactions"
headerCount="{{ block.transactionCount }}"
type="forward"
[routerLink]="[
'/' + block.chain + '/block/' + block.hash + '/transactions'
]"
></app-card-item>
</div> -->
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
>
Pending
</span>
<!-- TODO: red "Conflicting" label for `conflicting` -->
</div>
<app-date-time [value]="transaction.blockTimeNormalized" class="time">
</app-date-time>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export class TransactionComponent {
transaction: TransactionJSON;

pending = SpentHeightIndicators.pending;
conflicting = SpentHeightIndicators.conflicting;

/**
* The unit in which to display value – can be either a valid denomination for
Expand Down
2 changes: 2 additions & 0 deletions packages/insight/src/app/transaction/input/input.page.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@
</ion-header>

<ion-content padding> <div></div> </ion-content>

<!-- TODO: create `input` in `shared` components - see OutputPage -->
49 changes: 3 additions & 46 deletions packages/insight/src/app/transaction/input/input.page.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,10 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { combineLatest, from, Subject } from 'rxjs';
import { map, switchMap, take, tap } from 'rxjs/operators';
import { ApiService } from '../../services/api/api.service';
import { ConfigService } from '../../services/config/config.service';
import {
Direction,
StreamingFindOptions,
TransactionJSON
} from '../../types/bitcore-node';
import { Component } from '@angular/core';

@Component({
selector: 'app-input-page',
templateUrl: 'input.page.html',
styleUrls: ['input.page.scss']
})
export class InputPage implements OnInit {
private _query$: Subject<
StreamingFindOptions<TransactionJSON> & {
blockHeight?: number;
blockHash?: string;
}
> = new Subject();
query$ = this._query$.asObservable();

hash = this.route.params
.pipe(
take(1),
map(param => param['hash'])
)
.toPromise() as Promise<string>;

block$ = combineLatest(from(this.hash), this.config.currentChain$).pipe(
switchMap(([hash, chain]) => this.apiService.streamBlock(chain, hash))
);

constructor(
public config: ConfigService,
private route: ActivatedRoute,
private apiService: ApiService
) {}
ngOnInit() {
this.hash.then(hash => {
this._query$.next({
blockHash: hash,
limit: 20,
direction: Direction.ascending,
paging: 'txid'
});
});
}
export class InputPage {
// TODO: see OutputPage
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@
other details? This section should blend into the page, rather than being a
clickable-card.
</div>
<div>TODO: inputs list</div>
</ion-content>
49 changes: 3 additions & 46 deletions packages/insight/src/app/transaction/inputs/inputs.page.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,10 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { combineLatest, from, Subject } from 'rxjs';
import { map, switchMap, take, tap } from 'rxjs/operators';
import { ApiService } from '../../services/api/api.service';
import { ConfigService } from '../../services/config/config.service';
import {
Direction,
StreamingFindOptions,
TransactionJSON
} from '../../types/bitcore-node';
import { Component } from '@angular/core';

@Component({
selector: 'app-inputs-page',
templateUrl: 'inputs.page.html',
styleUrls: ['inputs.page.scss']
})
export class InputsPage implements OnInit {
private _query$: Subject<
StreamingFindOptions<TransactionJSON> & {
blockHeight?: number;
blockHash?: string;
}
> = new Subject();
query$ = this._query$.asObservable();

hash = this.route.params
.pipe(
take(1),
map(param => param['hash'])
)
.toPromise() as Promise<string>;

block$ = combineLatest(from(this.hash), this.config.currentChain$).pipe(
switchMap(([hash, chain]) => this.apiService.streamBlock(chain, hash))
);

constructor(
public config: ConfigService,
private route: ActivatedRoute,
private apiService: ApiService
) {}
ngOnInit() {
this.hash.then(hash => {
this._query$.next({
blockHash: hash,
limit: 20,
direction: Direction.ascending,
paging: 'txid'
});
});
}
export class InputsPage {
// TODO: see OutputsPage
}
9 changes: 8 additions & 1 deletion packages/insight/src/app/transaction/output/output.page.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,11 @@
</ion-toolbar>
</ion-header>

<ion-content padding> </ion-content>
<ion-content padding>
<app-output
*ngIf="(coin$ | async) as coin"
[coin]="coin"
[summary]="false"
[displayValueCode]="config.displayValueCode$ | async"
></app-output>
</ion-content>
53 changes: 20 additions & 33 deletions packages/insight/src/app/transaction/output/output.page.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,40 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { combineLatest, from, Subject } from 'rxjs';
import { map, switchMap, take, tap } from 'rxjs/operators';
import { combineLatest, from, Observable, of } from 'rxjs';
import { filter, map, switchMap } from 'rxjs/operators';
import { ApiService } from '../../services/api/api.service';
import { ConfigService } from '../../services/config/config.service';
import {
Direction,
StreamingFindOptions,
TransactionJSON
} from '../../types/bitcore-node';
import { CoinJSON } from '../../types/bitcore-node';

@Component({
selector: 'app-output-page',
templateUrl: 'output.page.html',
styleUrls: ['output.page.scss']
})
export class OutputPage implements OnInit {
private _query$: Subject<
StreamingFindOptions<TransactionJSON> & {
blockHeight?: number;
blockHash?: string;
}
> = new Subject();
query$ = this._query$.asObservable();

hash = this.route.params
.pipe(
take(1),
map(param => param['hash'])
)
.toPromise() as Promise<string>;

block$ = combineLatest(from(this.hash), this.config.currentChain$).pipe(
switchMap(([hash, chain]) => this.apiService.streamBlock(chain, hash))
);
coin$: Observable<CoinJSON>;

constructor(
public config: ConfigService,
private route: ActivatedRoute,
private apiService: ApiService
) {}

ngOnInit() {
this.hash.then(hash => {
this._query$.next({
blockHash: hash,
limit: 20,
direction: Direction.ascending,
paging: 'txid'
});
});
this.coin$ = combineLatest(
this.config.currentChain$,
this.route.paramMap.pipe(
switchMap(params => of([params.get('hash'), params.get('output')])),
filter<[string, string]>(
([hash, output]) => hash !== null && output !== null
)
)
).pipe(
switchMap(([chain, [hash, index]]) =>
this.apiService
.streamTransactionCoins(chain, hash)
.pipe(map(listing => listing.outputs[index]))
)
);
}
}
2 changes: 1 addition & 1 deletion packages/insight/src/app/transaction/transaction.page.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { combineLatest, Observable, of } from 'rxjs';
import { filter, map, switchMap, tap } from 'rxjs/operators';
import { filter, switchMap } from 'rxjs/operators';
import { ApiService } from '../services/api/api.service';
import { ConfigService } from '../services/config/config.service';
import { TransactionJSON } from '../types/bitcore-node';
Expand Down
3 changes: 1 addition & 2 deletions packages/insight/src/environments/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ export const environment = {
apiPrefix: '/api',
production: false,
debugRouting: false,
// pollingRateMilliseconds: 60 * 1000,
pollingRateMilliseconds: 5 * 1000,
pollingRateMilliseconds: 20 * 1000,
...{
loggingSettings: {
...environmentProd.loggingSettings,
Expand Down

0 comments on commit 6ed6fcb

Please sign in to comment.