Wallet management/Settings improvements (#130)

* New Branch
Splits settings out into their own areas for performance reasons

* Formatting

* Adds cutout logo for navbar

* Better settings loading screen
Better cache handling

* Adds snackbar support
Adds error websocketmessage support

* pushing from one pc to another

* Rejoins settings after failure to be able to seperate them without big rewrites

* Wallet manipulation in settings

* Reformats wallet page
Updates menu to be 'wallets'

* Lists enabled exchanges in settings before you click for modal

* Fixes currency list issue

* Fixes object reference bug in exchange-grid.component.html

* password text
This commit is contained in:
Scott
2018-06-04 19:20:59 +10:00
committed by Adrian Gallagher
parent 0478c55b45
commit a23c145ccc
22 changed files with 382 additions and 242 deletions

View File

@@ -1,3 +1,5 @@
<h2>Currency List</h2>
<h3>Select and monitor currencies of the same type</h3>
<mat-accordion>
<mat-expansion-panel *ngFor="let currency of exchangeCurrencies | iterateMap">
<mat-expansion-panel-header [ngClass]="{'selected' : selectedCurrency == currency.value}" >
@@ -13,7 +15,7 @@
</div>
<form class="form-content">
<mat-list>
<mat-list-item [ngClass]="{'selected' : selectedExchange == exchange}" *ngFor="let exchange of currency.key" >
<mat-list-item [ngClass]="{'selected' : (selectedExchange == exchange && selectedCurrency == currency.value)}" *ngFor="let exchange of currency.key" >
<h4 matLine>{{exchange}}</h4>
<button mat-button (click)="selectCurrency(exchange, currency.value)">SELECT</button>
</mat-list-item>

View File

@@ -58,7 +58,6 @@ export class CurrencyListComponent implements OnInit {
}
}
}
this.exchangeCurrencies.forEach((value: string[], key: string) => {});
}
private getSettings(): void {
@@ -69,5 +68,4 @@ export class CurrencyListComponent implements OnInit {
this.ws.messages.next(WebSocketMessage.GetSettingsMessage());
}
}
}

View File

@@ -1,11 +1,11 @@
<h2>Exchange List</h2>
<h3>Select and monitor currencies from the same exchange</h3>
<mat-accordion>
<mat-expansion-panel *ngFor="let exchange of exchangeCurrencies | iterateMap">
<mat-expansion-panel-header [ngClass]="{'selected' : selectedExchange == exchange.value}">
<mat-expansion-panel-header [ngClass]="{'selected' : selectedExchange == exchange.key}">
<mat-panel-title>
{{exchange.value}}
{{exchange.value}}
</mat-panel-title>
<mat-panel-description>
</mat-panel-description>
</mat-expansion-panel-header>
image and blurb
<div>
@@ -13,7 +13,7 @@
</div>
<form class="form-content">
<mat-list>
<mat-list-item [ngClass]="{'selected' : selectedCurrency == currency.ParsedName}" *ngFor="let currency of exchange.key | enabledCurrencies" >
<mat-list-item [ngClass]="{'selected' : selectedCurrency == currency.ParsedName && selectedExchange == exchange.value }" *ngFor="let currency of exchange.key | enabledCurrencies" >
<h4 matLine>{{currency.ParsedName}}</h4>
<button mat-button (click)="selectCurrency(exchange.value,currency.ParsedName)">SELECT</button>
</mat-list-item>

View File

@@ -1,19 +1,42 @@
<div class="loading-spinner" *ngIf="settings === null">
<mat-progress-spinner color="accent" mode="indeterminate"></mat-progress-spinner>
</div>
<div *ngIf="settings !== null">
<div *ngIf="settings !== null && ready">
<button matTooltip="Save" (click)="saveSettings()" mat-fab color="accent" class="mat-fab mat-fab-bottom-right"><mat-icon >save</mat-icon></button>
<mat-accordion>
<mat-expansion-panel *ngIf="settings.SMSGlobal != null">
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
SMS Global
Credentials
</mat-panel-title>
<mat-panel-description>
SMS configuration and contact management
<mat-icon>phone_iphone</mat-icon>
User Settings
<mat-icon>person</mat-icon>
</mat-panel-description>
</mat-expansion-panel-header>
<form class="form-content">
<mat-form-field>
<input matInput name="username" [(ngModel)]="settings.Webserver.AdminUsername" placeholder="Username">
</mat-form-field>
<mat-form-field>
<input matInput name="password" type="password" [(ngModel)]="settings.Webserver.AdminPassword" placeholder="Password">
</mat-form-field>
<mat-form-field>
<input type="number" matInput name="connection-limit" [(ngModel)]="settings.Webserver.WebsocketConnectionLimit" placeholder="Websocket connection limit">
</mat-form-field>
<mat-checkbox name="allow-insecure-origin" [(ngModel)]="settings.Webserver.WebsocketAllowInsecureOrigin">Allow Insecure Websocket Origin</mat-checkbox>
</form>
</mat-expansion-panel>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
SMS Notifications
</mat-panel-title>
<mat-panel-description>
Notification Settings
<mat-icon>sms</mat-icon>
</mat-panel-description>
</mat-expansion-panel-header>
<form class="form-content">
@@ -23,9 +46,9 @@
<input matInput name="smsUsername" [(ngModel)]="settings.SMSGlobal.Username" [disabled]="!settings?.SMSGlobal.Enabled" placeholder="Username">
</mat-form-field>
<mat-form-field>
<input matInput name="smsPassword" [(ngModel)]="settings.SMSGlobal.Password" [disabled]="!settings?.SMSGlobal.Enabled" placeholder="Password">
<input matInput name="smsPassword" type="password" [(ngModel)]="settings.SMSGlobal.Password" [disabled]="!settings?.SMSGlobal.Enabled" placeholder="Password">
</mat-form-field>
<div *ngFor="let contact of settings.SMSGlobal?.Contacts">
<mat-checkbox name="contactEnabled" [disabled]="!settings?.SMSGlobal.Enabled" [(ngModel)]="contact.Enabled">Enabled</mat-checkbox>
<div mat-line></div>
@@ -37,9 +60,39 @@
</mat-form-field>
</div>
</form>
<mat-action-row>
<button mat-button>ADD</button>
</mat-action-row>
</mat-expansion-panel>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
Wallets
</mat-panel-title>
<mat-panel-description>
Wallet Address Settings
<mat-icon>account_balance_wallet</mat-icon>
</mat-panel-description>
</mat-expansion-panel-header>
<div *ngFor="let wallet of settings.PortfolioAddresses?.Addresses">
<mat-form-field class="long">
<input matInput name="wallet-address" [(ngModel)]="wallet.Address" placeholder="Address" />
</mat-form-field>
<mat-form-field>
<input matInput name="wallet-cointype" [(ngModel)]="wallet.CoinType" placeholder="Coin Type" />
</mat-form-field>
<mat-form-field>
<input matInput name="wallet-description" [(ngModel)]="wallet.Description" placeholder="Description" />
</mat-form-field>
<button mat-button (click)="removeWallet(wallet)">REMOVE</button>
</div>
<mat-action-row>
<button mat-button (click)="addWallet()">ADD</button>
</mat-action-row>
</mat-expansion-panel>
<mat-expansion-panel *ngFor="let exchange of settings?.Exchanges">
<mat-expansion-panel-header>
<mat-panel-title>
@@ -47,7 +100,7 @@
</mat-panel-title>
<mat-panel-description>
Exchange Settings
<mat-icon>attach_money</mat-icon>
<mat-icon>poll</mat-icon>
</mat-panel-description>
</mat-expansion-panel-header>
<form class="form-content">
@@ -57,7 +110,7 @@
<input matInput name="apiKey" [(ngModel)]="exchange.APIKey" [disabled]="!exchange.Enabled" placeholder="API Key*">
</mat-form-field>
<mat-form-field>
<input matInput name="apiSecretKey" [(ngModel)]="exchange.APISecret" [disabled]="!exchange.Enabled" placeholder="API Secret Key*">
<input matInput name="apiSecretKey" type="password" [(ngModel)]="exchange.APISecret" [disabled]="!exchange.Enabled" placeholder="API Secret Key*">
</mat-form-field>
<mat-form-field>
<input matInput name="apiClientId" [(ngModel)]="exchange.ClientID" [disabled]="!exchange.Enabled" placeholder="API ClientID">
@@ -66,12 +119,10 @@
<h4>
Enabled currencies
</h4>
<div *ngFor="let currency of exchange.Pairs">
<p>{{currency.Name}}</p>
<mat-checkbox name="{{currency.Name}}2" [(ngModel)]="currency.Enabled"></mat-checkbox>
</div>
<p ><span *ngFor="let pair of exchange.Pairs | enabledCurrencies; let isLast=last">{{pair.Name}}{{isLast ? '' : ', '}}</span> </p>
<button mat-button [disabled]="!exchange.Enabled" (click)="openModal(exchange.Pairs)">CHANGE</button>
</form>
</mat-expansion-panel>
</mat-accordion>
</mat-accordion>
</div>

View File

@@ -9,4 +9,17 @@
.form-content {
margin: 20px;
}
.main {
margin-top: 20px;
}
.mat-card {
height: 100%;
width: 100%;
}
.long {
width:450px;
}

View File

@@ -1,7 +1,9 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Component, OnInit, OnDestroy, Inject } from '@angular/core';
import { WebsocketResponseHandlerService } from './../../services/websocket-response-handler/websocket-response-handler.service';
import { WebSocketMessageType, WebSocketMessage } from './../../shared/classes/websocket';
import { Config, CurrencyPairRedux } from './../../shared/classes/config';
import { Config, CurrencyPairRedux, Wallet } from './../../shared/classes/config';
import { MatSnackBar, MatDialog, MatDialogRef, MAT_DIALOG_DATA} from '@angular/material';
import { WalletComponent } from '../wallet/wallet.component';
@Component({
selector: 'app-settings',
@@ -9,36 +11,68 @@ import { Config, CurrencyPairRedux } from './../../shared/classes/config';
styleUrls: ['./settings.component.scss'],
})
export class SettingsComponent implements OnInit {
export class SettingsComponent {
public settings: Config = new Config();
private ws: WebsocketResponseHandlerService;
public ready: boolean = false;
private snackBar: MatSnackBar;
private dialogue;
constructor(private websocketHandler: WebsocketResponseHandlerService) {
constructor(private websocketHandler: WebsocketResponseHandlerService, snackBar: MatSnackBar, public dialog: MatDialog) {
this.ws = websocketHandler;
this.snackBar = snackBar;
}
ngOnInit() {
this.ws.shared.subscribe(msg => {
if (msg.event === WebSocketMessageType.GetConfig) {
this.settings.setConfig(msg.data);
this.ready = true;
} else if (msg.event === WebSocketMessageType.SaveConfig) {
// check if err is returned, then display some notification
if(msg.error !== null || msg.error.length > 0) {
this.snackBar.open(msg.error, '', {
duration: 4000,
});
}
if (msg.error === null || msg.error === '') {
this.settings.clearCache();
this.getSettings();
this.snackBar.open('Success', msg.data, {
duration: 1000,
});
}
}
});
this.getSettings();
}
public addWallet() :void {
this.settings.PortfolioAddresses.Addresses.push(<Wallet>{});
}
public removeWallet(wallet:any) {
this.settings.PortfolioAddresses.Addresses.splice(this.settings.PortfolioAddresses.Addresses.indexOf(wallet), 1);
}
public openModal(pairs: any): void {
let dialogRef = this.dialog.open(EnabledCurrenciesDialogueComponent, {
width: '20%',
height: '40%',
data: { pairs: pairs }
});
}
private getSettings(): void {
if(this.settings.isConfigCacheValid()) {
this.settings.setConfig(JSON.parse(window.localStorage['config']))
this.ready = true;
} else {
this.settings.clearCache();
this.ws.messages.next(WebSocketMessage.GetSettingsMessage());
}
}
private saveSettings(): void {
this.settings.fromReduxToArray()
var settingsSave = {
Event: 'SaveConfig',
@@ -48,3 +82,25 @@ export class SettingsComponent implements OnInit {
}
}
@Component({
selector: 'dialog-overview-example-dialog',
template: '<h4>Enabled Currencies</h4><div *ngFor="let currency of data.pairs"><mat-checkbox name="{{currency.Name}}2" [(ngModel)]="currency.Enabled">{{currency.Name}}</mat-checkbox></div><button mat-raised-button color="primary" (click)="close()">DONE</button>',
})
export class EnabledCurrenciesDialogueComponent {
constructor(
public dialogRef: MatDialogRef<EnabledCurrenciesDialogueComponent>,
@Inject(MAT_DIALOG_DATA) public data: any) { }
onNoClick(): void {
this.dialogRef.close();
}
public close(): void {
this.dialogRef.close();
}
}

View File

@@ -1,114 +1,84 @@
<div class="loading-spinner" *ngIf="wallet === null">
<mat-progress-spinner color="accent" mode="indeterminate"></mat-progress-spinner>
<mat-progress-spinner color="accent" mode="indeterminate"></mat-progress-spinner>
</div>
<mat-accordion *ngIf="wallet !== null">
<mat-expansion-panel [expanded]="true">
<mat-expansion-panel-header>
<mat-panel-title>
Coin Totals
</mat-panel-title>
</mat-expansion-panel-header>
<mat-list>
<div *ngIf="wallet !== null">
<button matTooltip="Recalculate" (click)="setWallet()" mat-fab color="accent" class="mat-fab mat-fab-bottom-right">
<mat-icon>dialpad</mat-icon>
</button>
<mat-card>
<mat-card-content>
<h4>Coin Totals</h4>
<mat-list>
<mat-list-item *ngFor="let coin of wallet?.coin_totals">
<i [ngClass]="coin.icon"></i>
<h4 mat-line>{{coin.coin}}</h4>
<h4 mat-line>{{coin.balance}}</h4>
<h4 mat-line><i [ngClass]="coin.icon"></i> {{coin.coin}}</h4>
<h4 mat-line>{{coin.balance}}</h4>
</mat-list-item>
</mat-list>
</mat-expansion-panel>
</mat-list>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
Online Summary
</mat-panel-title>
</mat-expansion-panel-header>
<mat-list>
<mat-divider></mat-divider>
<h4>Offline Coins</h4>
<mat-list>
<mat-list-item *ngFor="let coin of wallet?.coins_offline">
<h4 mat-line><i [ngClass]="coin.icon"></i> {{coin.coin}}</h4>
<h4 mat-line>{{coin.balance}}</h4>
</mat-list-item>
</mat-list>
<mat-divider></mat-divider>
<h4>Offline Summary</h4>
<mat-list>
<mat-list-item *ngFor="let coin of wallet?.offline_summary.BTC">
<i class="cc btc"></i>
<h4 mat-line>Address: {{coin.address}}</h4>
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
</mat-list-item>
<mat-list-item *ngFor="let coin of wallet?.offline_summary.LTC">
<i class="cc ltc"></i>
<h4 mat-line>Address: {{coin.address}}</h4>
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
</mat-list-item>
<mat-list-item *ngFor="let coin of wallet?.offline_summary.ETH">
<i class="cc eth"></i>
<h4 mat-line>Address: {{coin.address}}</h4>
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
</mat-list-item>
</mat-list>
<mat-divider></mat-divider>
<h4>Online Coins</h4>
<mat-list>
<mat-list-item *ngFor="let coin of wallet?.coins_online">
<i [ngClass]="coin.icon"></i>
<h4 mat-line>{{coin.coin}}</h4>
<h4 mat-line>{{coin.balance}}</h4>
</mat-list-item>
</mat-list>
<mat-divider></mat-divider>
<h4> Online Summary</h4>
<mat-list>
<mat-list-item *ngFor="let coin of wallet?.online_summary.BTC">
<i class="cc btc"></i>
<h4 mat-line>Address: {{coin.address}}</h4>
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
<i class="cc btc"></i>
<h4 mat-line>Address: {{coin.address}}</h4>
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item *ngFor="let coin of wallet?.online_summary.LTC">
<i class="cc ltc"></i>
<h4 mat-line>Address: {{coin.address}}</h4>
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
<i class="cc ltc"></i>
<h4 mat-line>Address: {{coin.address}}</h4>
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item *ngFor="let coin of wallet?.online_summary.ETH">
<i class="cc eth"></i>
<h4 mat-line>Address: {{coin.address}}</h4>
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
<i class="cc eth"></i>
<h4 mat-line>Address: {{coin.address}}</h4>
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
</mat-list-item>
</mat-list>
</mat-expansion-panel>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
Offline Summary
</mat-panel-title>
</mat-expansion-panel-header>
<mat-list>
<mat-list-item *ngFor="let coin of wallet?.offline_summary.BTC">
<i class="cc btc"></i>
<h4 mat-line>Address: {{coin.address}}</h4>
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item *ngFor="let coin of wallet?.offline_summary.LTC">
<i class="cc ltc"></i>
<h4 mat-line>Address: {{coin.address}}</h4>
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item *ngFor="let coin of wallet?.offline_summary.ETH">
<i class="cc eth"></i>
<h4 mat-line>Address: {{coin.address}}</h4>
<h4 mat-line>{{coin.balance}}{{coin.coin}} - {{coin.percentage}}%</h4>
</mat-list-item>
</mat-list>
</mat-expansion-panel>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
Online Coins
</mat-panel-title>
</mat-expansion-panel-header>
<mat-list>
<mat-list-item *ngFor="let coin of wallet?.coins_online">
<i [ngClass]="coin.icon"></i>
<h4 mat-line>{{coin.coin}}</h4>
<h4 mat-line>{{coin.balance}}</h4>
</mat-list-item>
</mat-list>
</mat-expansion-panel>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
Offline Coins
</mat-panel-title>
</mat-expansion-panel-header>
<mat-list>
<mat-list-item *ngFor="let coin of wallet?.coins_offline">
<i [ngClass]="coin.icon"></i>
<h4 mat-line>{{coin.coin}}</h4>
<h4 mat-line>{{coin.balance}}</h4>
</mat-list-item>
</mat-list>
</mat-expansion-panel>
</mat-accordion>
</mat-list>
</mat-card-content>
</mat-card>
</div>

View File

@@ -1,7 +1,3 @@
.wallet-card {
width: 80%;
margin: 10px auto;
}
.BTC {
color:orange;
@@ -11,4 +7,24 @@
}
.ETH {
color:darkslategrey;
}
}
// FAB
.mat-fab {
top: auto;
right: 30px;
bottom: 20px;
left: auto;
position: fixed;
z-index:9;
}
mat-grid-list {
height: 90vh;
}
mat-card {
width:90%;
}
mat-grid-tile {
box-shadow: 0 3px 3px 0 rgba(0, 0, 0, 0.37);
}

View File

@@ -28,6 +28,7 @@ export class WalletComponent implements OnInit {
this.ws.shared.subscribe(msg => {
if (msg.event === WebSocketMessageType.GetPortfolio) {
this.wallet = <Wallet>msg.data;
console.log(msg.data);
this.attachIcon(this.wallet.coin_totals);
this.attachIcon(this.wallet.coins_offline);
this.attachIcon(this.wallet.coins_online);