tree view of wallet db
This commit is contained in:
parent
dbcd85451e
commit
d4be3906e3
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -29,6 +29,9 @@
|
||||
"**/*.js": {
|
||||
"when": "$(basename).ts"
|
||||
},
|
||||
"**/*?.js": {
|
||||
"when": "$(basename).tsx"
|
||||
},
|
||||
"**/*.js.map": true
|
||||
}
|
||||
}
|
45
lib/components.ts
Normal file
45
lib/components.ts
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2016 Inria
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* General helper components
|
||||
*
|
||||
* @author Florian Dold
|
||||
*/
|
||||
|
||||
export interface StateHolder<T> {
|
||||
(): T;
|
||||
(newState: T): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component that doesn't hold its state in one object,
|
||||
* but has multiple state holders.
|
||||
*/
|
||||
export abstract class ImplicitStateComponent<PropType> extends preact.Component<PropType, any> {
|
||||
makeState<StateType>(initial: StateType): StateHolder<StateType> {
|
||||
let state: StateType = initial;
|
||||
return (s?: StateType): StateType => {
|
||||
if (s !== undefined) {
|
||||
state = s;
|
||||
// In preact, this will always schedule a (debounced) redraw
|
||||
this.setState({} as any);
|
||||
}
|
||||
return state;
|
||||
};
|
||||
}
|
||||
}
|
@ -39,6 +39,7 @@ export interface QueryStream<T> {
|
||||
filter(f: (x: any) => boolean): QueryStream<T>;
|
||||
reduce<S>(f: (v: T, acc: S) => S, start?: S): Promise<S>;
|
||||
flatMap(f: (x: T) => T[]): QueryStream<T>;
|
||||
toArray(): Promise<T[]>;
|
||||
}
|
||||
|
||||
|
||||
@ -87,6 +88,23 @@ abstract class QueryStreamBase<T> implements QueryStream<T> {
|
||||
return new QueryStreamFilter(this, f);
|
||||
}
|
||||
|
||||
toArray(): Promise<T[]> {
|
||||
let {resolve, promise} = openPromise();
|
||||
let values: T[] = [];
|
||||
|
||||
this.subscribe((isDone, value) => {
|
||||
if (isDone) {
|
||||
resolve(values);
|
||||
return;
|
||||
}
|
||||
values.push(value);
|
||||
});
|
||||
|
||||
return Promise.resolve()
|
||||
.then(() => this.root.finish())
|
||||
.then(() => promise);
|
||||
}
|
||||
|
||||
reduce<A>(f: (x: any, acc?: A) => A, init?: A): Promise<any> {
|
||||
let {resolve, promise} = openPromise();
|
||||
let acc = init;
|
||||
|
@ -48,3 +48,16 @@ export function renderContract(contract: Contract): JSX.Element {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export function abbrev(s: string, n: number = 5) {
|
||||
let sAbbrev = s;
|
||||
if (s.length > n) {
|
||||
sAbbrev = s.slice(0, n) + "..";
|
||||
}
|
||||
return (
|
||||
<span className="abbrev" title={s}>
|
||||
{sAbbrev}
|
||||
</span>
|
||||
);
|
||||
}
|
@ -152,6 +152,8 @@ export interface Reserve {
|
||||
exchange_base_url: string
|
||||
reserve_priv: string;
|
||||
reserve_pub: string;
|
||||
created: number;
|
||||
current_amount: AmountJson;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1128,6 +1128,35 @@ export class Wallet {
|
||||
return { history };
|
||||
}
|
||||
|
||||
async getExchanges(): Promise<IExchangeInfo[]> {
|
||||
return Query(this.db)
|
||||
.iter<IExchangeInfo>("exchanges")
|
||||
.flatMap((e) => [e])
|
||||
.toArray();
|
||||
}
|
||||
|
||||
async getReserves(exchangeBaseUrl: string): Promise<Reserve[]> {
|
||||
return Query(this.db)
|
||||
.iter<Reserve>("reserves")
|
||||
.filter((r: Reserve) => r.exchange_base_url === exchangeBaseUrl)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
async getCoins(exchangeBaseUrl: string): Promise<Coin[]> {
|
||||
return Query(this.db)
|
||||
.iter<Coin>("coins")
|
||||
.filter((c: Coin) => c.exchangeBaseUrl === exchangeBaseUrl)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
async getPreCoins(exchangeBaseUrl: string): Promise<PreCoin[]> {
|
||||
return Query(this.db)
|
||||
.iter<PreCoin>("precoins")
|
||||
.filter((c: PreCoin) => c.exchangeBaseUrl === exchangeBaseUrl)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
|
||||
async hashContract(contract: any): Promise<string> {
|
||||
return this.cryptoApi.hashString(canonicalJson(contract));
|
||||
}
|
||||
|
@ -14,8 +14,14 @@
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import {AmountJson} from "./types";
|
||||
import {ReserveCreationInfo} from "./types";
|
||||
import {
|
||||
AmountJson,
|
||||
Coin,
|
||||
PreCoin,
|
||||
ReserveCreationInfo,
|
||||
IExchangeInfo,
|
||||
Reserve
|
||||
} from "./types";
|
||||
|
||||
/**
|
||||
* Interface to the wallet through WebExtension messaging.
|
||||
@ -39,3 +45,27 @@ export function getReserveCreationInfo(baseUrl: string,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function callBackend(type: string, detail?: any): Promise<any> {
|
||||
return new Promise<IExchangeInfo[]>((resolve, reject) => {
|
||||
chrome.runtime.sendMessage({ type, detail }, (resp) => {
|
||||
resolve(resp);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function getExchanges(): Promise<IExchangeInfo[]> {
|
||||
return await callBackend("get-exchanges");
|
||||
}
|
||||
|
||||
export async function getReserves(exchangeBaseUrl: string): Promise<Reserve[]> {
|
||||
return await callBackend("get-reserves", { exchangeBaseUrl });
|
||||
}
|
||||
|
||||
export async function getCoins(exchangeBaseUrl: string): Promise<Coin[]> {
|
||||
return await callBackend("get-coins", { exchangeBaseUrl });
|
||||
}
|
||||
|
||||
export async function getPreCoins(exchangeBaseUrl: string): Promise<PreCoin[]> {
|
||||
return await callBackend("get-precoins", { exchangeBaseUrl });
|
||||
}
|
@ -183,6 +183,27 @@ function makeHandlers(db: IDBDatabase,
|
||||
// TODO: limit history length
|
||||
return wallet.getHistory();
|
||||
},
|
||||
["get-exchanges"]: function (detail, sender) {
|
||||
return wallet.getExchanges();
|
||||
},
|
||||
["get-reserves"]: function (detail, sender) {
|
||||
if (typeof detail.exchangeBaseUrl !== "string") {
|
||||
return Promise.reject(Error("exchangeBaseUrl missing"));
|
||||
}
|
||||
return wallet.getReserves(detail.exchangeBaseUrl);
|
||||
},
|
||||
["get-coins"]: function (detail, sender) {
|
||||
if (typeof detail.exchangeBaseUrl !== "string") {
|
||||
return Promise.reject(Error("exchangBaseUrl missing"));
|
||||
}
|
||||
return wallet.getCoins(detail.exchangeBaseUrl);
|
||||
},
|
||||
["get-precoins"]: function (detail, sender) {
|
||||
if (typeof detail.exchangeBaseUrl !== "string") {
|
||||
return Promise.reject(Error("exchangBaseUrl missing"));
|
||||
}
|
||||
return wallet.getPreCoins(detail.exchangeBaseUrl);
|
||||
},
|
||||
["payment-failed"]: function (detail, sender) {
|
||||
// For now we just update exchanges (maybe the exchange did something
|
||||
// wrong and the keys were messed up).
|
||||
|
@ -27,6 +27,7 @@ import {AmountJson, CreateReserveResponse} from "../lib/wallet/types";
|
||||
import {ReserveCreationInfo, Amounts} from "../lib/wallet/types";
|
||||
import {Denomination} from "../lib/wallet/types";
|
||||
import {getReserveCreationInfo} from "../lib/wallet/wxApi";
|
||||
import {ImplicitStateComponent, StateHolder} from "../lib/components";
|
||||
|
||||
"use strict";
|
||||
|
||||
@ -63,30 +64,6 @@ class EventTrigger {
|
||||
}
|
||||
|
||||
|
||||
interface StateHolder<T> {
|
||||
(): T;
|
||||
(newState: T): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component that doesn't hold its state in one object,
|
||||
* but has multiple state holders.
|
||||
*/
|
||||
abstract class ImplicitStateComponent<PropType> extends preact.Component<PropType, void> {
|
||||
makeState<StateType>(initial: StateType): StateHolder<StateType> {
|
||||
let state: StateType = initial;
|
||||
return (s?: StateType): StateType => {
|
||||
if (s !== undefined) {
|
||||
state = s;
|
||||
// In preact, this will always schedule a (debounced) redraw
|
||||
this.setState({} as any);
|
||||
}
|
||||
return state;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function renderReserveCreationDetails(rci: ReserveCreationInfo|null) {
|
||||
if (!rci) {
|
||||
return <p>
|
||||
|
32
pages/tree.html
Normal file
32
pages/tree.html
Normal file
@ -0,0 +1,32 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Taler Wallet: Tree View</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="../style/lang.css">
|
||||
<link rel="stylesheet" type="text/css" href="../style/wallet.css">
|
||||
|
||||
<link rel="icon" href="../img/icon.png">
|
||||
|
||||
<script src="../lib/vendor/URI.js"></script>
|
||||
<script src="../lib/vendor/preact.js"></script>
|
||||
|
||||
<!-- i18n -->
|
||||
<script src="../lib/vendor/jed.js"></script>
|
||||
<script src="../lib/i18n.js"></script>
|
||||
<script src="../i18n/strings.js"></script>
|
||||
|
||||
<script src="../lib/vendor/system-csp-production.src.js"></script>
|
||||
<script src="../lib/module-trampoline.js"></script>
|
||||
|
||||
<style>
|
||||
.tree-item {
|
||||
margin: 2em;
|
||||
border-radius: 5px;
|
||||
border: 1px solid gray;
|
||||
padding: 1em;
|
||||
}
|
||||
</style>
|
||||
|
||||
</html>
|
305
pages/tree.tsx
Normal file
305
pages/tree.tsx
Normal file
@ -0,0 +1,305 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2016 Inria
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Show contents of the wallet as a tree.
|
||||
*
|
||||
* @author Florian Dold
|
||||
*/
|
||||
|
||||
/// <reference path="../lib/decl/preact.d.ts" />
|
||||
|
||||
import { IExchangeInfo } from "../lib/wallet/types";
|
||||
import { Reserve, Coin, PreCoin, Denomination } from "../lib/wallet/types";
|
||||
import { ImplicitStateComponent, StateHolder } from "../lib/components";
|
||||
import { getReserves, getExchanges, getCoins, getPreCoins } from "../lib/wallet/wxApi";
|
||||
import { prettyAmount, abbrev } from "../lib/wallet/renderHtml";
|
||||
|
||||
interface ReserveViewProps {
|
||||
reserve: Reserve;
|
||||
}
|
||||
|
||||
class ReserveView extends preact.Component<ReserveViewProps, void> {
|
||||
render(): JSX.Element {
|
||||
let r: Reserve = this.props.reserve;
|
||||
return (
|
||||
<div className="tree-item">
|
||||
<ul>
|
||||
<li>Key: {r.reserve_pub}</li>
|
||||
<li>Created: {(new Date(r.created * 1000).toString())}</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
interface ReserveListProps {
|
||||
exchangeBaseUrl: string;
|
||||
}
|
||||
|
||||
interface ToggleProps {
|
||||
expanded: StateHolder<boolean>;
|
||||
}
|
||||
|
||||
class Toggle extends ImplicitStateComponent<ToggleProps> {
|
||||
renderButton() {
|
||||
let show = () => {
|
||||
this.props.expanded(true);
|
||||
this.setState({});
|
||||
};
|
||||
let hide = () => {
|
||||
this.props.expanded(false);
|
||||
this.setState({});
|
||||
};
|
||||
if (this.props.expanded()) {
|
||||
return <button onClick={hide}>hide</button>;
|
||||
}
|
||||
return <button onClick={show}>show</button>;
|
||||
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div style="display:inline;">
|
||||
{this.renderButton()}
|
||||
{this.props.expanded() ? this.props.children : []}
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface CoinViewProps {
|
||||
coin: Coin;
|
||||
}
|
||||
|
||||
class CoinView extends preact.Component<CoinViewProps, void> {
|
||||
render() {
|
||||
let c = this.props.coin;
|
||||
return (
|
||||
<div className="tree-item">
|
||||
<ul>
|
||||
<li>Key: {c.coinPub}</li>
|
||||
<li>Current amount: {prettyAmount(c.currentAmount)}</li>
|
||||
<li>Denomination: {abbrev(c.denomPub, 20)}</li>
|
||||
<li>Suspended: {(c.suspended || false).toString()}</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
interface PreCoinViewProps {
|
||||
precoin: PreCoin;
|
||||
}
|
||||
|
||||
class PreCoinView extends preact.Component<PreCoinViewProps, void> {
|
||||
render() {
|
||||
let c = this.props.precoin;
|
||||
return (
|
||||
<div className="tree-item">
|
||||
<ul>
|
||||
<li>Key: {c.coinPub}</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
interface CoinListProps {
|
||||
exchangeBaseUrl: string;
|
||||
}
|
||||
|
||||
class CoinList extends ImplicitStateComponent<CoinListProps> {
|
||||
coins = this.makeState<Coin[] | null>(null);
|
||||
expanded = this.makeState<boolean>(false);
|
||||
|
||||
constructor(props: CoinListProps) {
|
||||
super(props);
|
||||
this.update();
|
||||
}
|
||||
|
||||
async update() {
|
||||
let coins = await getCoins(this.props.exchangeBaseUrl);
|
||||
this.coins(coins);
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
if (!this.coins()) {
|
||||
return <div>...</div>;
|
||||
}
|
||||
return (
|
||||
<div className="tree-item">
|
||||
Coins ({this.coins() !.length.toString()})
|
||||
{" "}
|
||||
<Toggle expanded={this.expanded}>
|
||||
{this.coins() !.map((c) => <CoinView coin={c} />)}
|
||||
</Toggle>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface PreCoinListProps {
|
||||
exchangeBaseUrl: string;
|
||||
}
|
||||
|
||||
class PreCoinList extends ImplicitStateComponent<PreCoinListProps> {
|
||||
precoins = this.makeState<PreCoin[] | null>(null);
|
||||
expanded = this.makeState<boolean>(false);
|
||||
|
||||
constructor(props: PreCoinListProps) {
|
||||
super(props);
|
||||
this.update();
|
||||
}
|
||||
|
||||
async update() {
|
||||
let precoins = await getPreCoins(this.props.exchangeBaseUrl);
|
||||
this.precoins(precoins);
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
if (!this.precoins()) {
|
||||
return <div>...</div>;
|
||||
}
|
||||
return (
|
||||
<div className="tree-item">
|
||||
Pre-Coins ({this.precoins() !.length.toString()})
|
||||
{" "}
|
||||
<Toggle expanded={this.expanded}>
|
||||
{this.precoins() !.map((c) => <PreCoinView precoin={c} />)}
|
||||
</Toggle>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
interface DenominationListProps {
|
||||
exchange: IExchangeInfo;
|
||||
}
|
||||
|
||||
class DenominationList extends ImplicitStateComponent<DenominationListProps> {
|
||||
expanded = this.makeState<boolean>(false);
|
||||
|
||||
renderDenom(d: Denomination) {
|
||||
return (
|
||||
<div className="tree-item">
|
||||
<ul>
|
||||
<li>Value: {prettyAmount(d.value)}</li>
|
||||
<li>Withdraw fee: {prettyAmount(d.fee_withdraw)}</li>
|
||||
<li>Refresh fee: {prettyAmount(d.fee_refresh)}</li>
|
||||
<li>Deposit fee: {prettyAmount(d.fee_deposit)}</li>
|
||||
<li>Refund fee: {prettyAmount(d.fee_refund)}</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
return (
|
||||
<div className="tree-item">
|
||||
Denominations ({this.props.exchange.active_denoms.length.toString()})
|
||||
{" "}
|
||||
<Toggle expanded={this.expanded}>
|
||||
{this.props.exchange.active_denoms.map((d) => this.renderDenom(d))}
|
||||
</Toggle>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ReserveList extends ImplicitStateComponent<ReserveListProps> {
|
||||
reserves = this.makeState<Reserve[] | null>(null);
|
||||
expanded = this.makeState<boolean>(false);
|
||||
|
||||
constructor(props: ReserveListProps) {
|
||||
super(props);
|
||||
this.update();
|
||||
}
|
||||
|
||||
async update() {
|
||||
let reserves = await getReserves(this.props.exchangeBaseUrl);
|
||||
this.reserves(reserves);
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
if (!this.reserves()) {
|
||||
return <div>...</div>;
|
||||
}
|
||||
return (
|
||||
<div className="tree-item">
|
||||
Reserves ({this.reserves() !.length.toString()})
|
||||
{" "}
|
||||
<Toggle expanded={this.expanded}>
|
||||
{this.reserves() !.map((r) => <ReserveView reserve={r} />)}
|
||||
</Toggle>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
interface ExchangeProps {
|
||||
exchange: IExchangeInfo;
|
||||
}
|
||||
|
||||
class ExchangeView extends preact.Component<ExchangeProps, void> {
|
||||
render(): JSX.Element {
|
||||
let e = this.props.exchange;
|
||||
return (
|
||||
<div className="tree-item">
|
||||
Url: {this.props.exchange.baseUrl}
|
||||
<DenominationList exchange={e} />
|
||||
<ReserveList exchangeBaseUrl={this.props.exchange.baseUrl} />
|
||||
<CoinList exchangeBaseUrl={this.props.exchange.baseUrl} />
|
||||
<PreCoinList exchangeBaseUrl={this.props.exchange.baseUrl} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
interface ExchangesListState {
|
||||
exchanges: IExchangeInfo[];
|
||||
}
|
||||
|
||||
class ExchangesList extends preact.Component<any, ExchangesListState> {
|
||||
constructor() {
|
||||
super();
|
||||
this.update();
|
||||
}
|
||||
|
||||
async update() {
|
||||
let exchanges = await getExchanges();
|
||||
console.log("exchanges: ", exchanges);
|
||||
this.setState({ exchanges });
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
if (!this.state.exchanges) {
|
||||
return <span>...</span>;
|
||||
}
|
||||
return (
|
||||
<div className="tree-item">
|
||||
Exchanges ({this.state.exchanges.length.toString()}):
|
||||
{this.state.exchanges.map(e => <ExchangeView exchange={e} />)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function main() {
|
||||
preact.render(<ExchangesList />, document.body);
|
||||
}
|
@ -29,6 +29,7 @@ import {substituteFulfillmentUrl} from "../lib/wallet/helpers";
|
||||
import BrowserClickedEvent = chrome.browserAction.BrowserClickedEvent;
|
||||
import {HistoryRecord, HistoryLevel} from "../lib/wallet/wallet";
|
||||
import {AmountJson} from "../lib/wallet/types";
|
||||
import {abbrev, prettyAmount} from "../lib/wallet/renderHtml";
|
||||
|
||||
declare var i18n: any;
|
||||
|
||||
@ -226,7 +227,7 @@ class WalletBalance extends preact.Component<any, any> {
|
||||
}
|
||||
console.log(wallet);
|
||||
let listing = Object.keys(wallet).map((key) => {
|
||||
return <p>{formatAmount(wallet[key])}</p>
|
||||
return <p>{prettyAmount(wallet[key])}</p>
|
||||
});
|
||||
if (listing.length > 0) {
|
||||
return <div>{listing}</div>;
|
||||
@ -237,25 +238,6 @@ class WalletBalance extends preact.Component<any, any> {
|
||||
}
|
||||
|
||||
|
||||
function formatAmount(amount: AmountJson) {
|
||||
let v = amount.value + amount.fraction / 1e6;
|
||||
return `${v.toFixed(2)} ${amount.currency}`;
|
||||
}
|
||||
|
||||
|
||||
function abbrev(s: string, n: number = 5) {
|
||||
let sAbbrev = s;
|
||||
if (s.length > n) {
|
||||
sAbbrev = s.slice(0, n) + "..";
|
||||
}
|
||||
return (
|
||||
<span className="abbrev" title={s}>
|
||||
{sAbbrev}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function formatHistoryItem(historyItem: HistoryRecord) {
|
||||
const d = historyItem.detail;
|
||||
const t = historyItem.timestamp;
|
||||
@ -264,14 +246,14 @@ function formatHistoryItem(historyItem: HistoryRecord) {
|
||||
case "create-reserve":
|
||||
return (
|
||||
<p>
|
||||
{i18n.parts`Bank requested reserve (${abbrev(d.reservePub)}) for ${formatAmount(
|
||||
{i18n.parts`Bank requested reserve (${abbrev(d.reservePub)}) for ${prettyAmount(
|
||||
d.requestedAmount)}.`}
|
||||
</p>
|
||||
);
|
||||
case "confirm-reserve": {
|
||||
// FIXME: eventually remove compat fix
|
||||
let exchange = d.exchangeBaseUrl ? URI(d.exchangeBaseUrl).host() : "??";
|
||||
let amount = formatAmount(d.requestedAmount);
|
||||
let amount = prettyAmount(d.requestedAmount);
|
||||
let pub = abbrev(d.reservePub);
|
||||
return (
|
||||
<p>
|
||||
@ -291,7 +273,7 @@ function formatHistoryItem(historyItem: HistoryRecord) {
|
||||
}
|
||||
case "depleted-reserve": {
|
||||
let exchange = d.exchangeBaseUrl ? URI(d.exchangeBaseUrl).host() : "??";
|
||||
let amount = formatAmount(d.requestedAmount);
|
||||
let amount = prettyAmount(d.requestedAmount);
|
||||
let pub = abbrev(d.reservePub);
|
||||
return (<p>
|
||||
{i18n.parts`Withdrew ${amount} from ${exchange} (${pub}).`}
|
||||
@ -304,7 +286,7 @@ function formatHistoryItem(historyItem: HistoryRecord) {
|
||||
let fulfillmentLinkElem = <a href={url} onClick={openTab(url)}>view product</a>;
|
||||
return (
|
||||
<p>
|
||||
{i18n.parts`Paid ${formatAmount(d.amount)} to merchant ${merchantElem}. (${fulfillmentLinkElem})`}
|
||||
{i18n.parts`Paid ${prettyAmount(d.amount)} to merchant ${merchantElem}. (${fulfillmentLinkElem})`}
|
||||
</p>);
|
||||
}
|
||||
default:
|
||||
|
@ -38,6 +38,7 @@
|
||||
"pages/show-db.ts",
|
||||
"pages/confirm-contract.tsx",
|
||||
"pages/confirm-create-reserve.tsx",
|
||||
"pages/tree.tsx",
|
||||
"test/tests/taler.ts"
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user