Skip to content

Commit

Permalink
Allow add new RPC (#117)
Browse files Browse the repository at this point in the history
* Allow add new RPC

* Allow add new RPC

* Set reasonable default

* Lint prettier

* Lint prettier

* Lint prettier

* Update changelog

* Update changelog
  • Loading branch information
dev-ptera authored Dec 8, 2023
1 parent 12ce869 commit ce01cb8
Show file tree
Hide file tree
Showing 16 changed files with 264 additions and 28 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Change Log

## v4.4.0 (December 8, 2023)

### Added

- Added option to add custom RPC node on settings page.

## v4.3.0 (September 30, 2023)

### Added
Expand Down
3 changes: 0 additions & 3 deletions cypress/e2e/message_sign.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ describe('Message Sign', () => {
);
signingRobot
.checkSigningPageExists()
.clickMessageSigningExpand()
.checkMessageSignButtonDisabled()
.enterMessage('samplemessage')
.clickMessageSignButton()
Expand Down Expand Up @@ -63,7 +62,6 @@ describe('Message Sign', () => {
);
signingRobot
.checkSigningPageExists()
.clickMessageSigningExpand()
.checkMessageSignButtonDisabled()
.enterMessage('samplemessage')
.clickMessageSignButton()
Expand Down Expand Up @@ -92,7 +90,6 @@ describe('Message Sign', () => {
);
signingRobot
.checkSigningPageExists()
.clickMessageSigningExpand()
.clickMessageSignButton()
.checkSignatureEquals(
'C4E6ADE8957E39D4BC18CC703A848B9F0251B406D47EA1A7B5A045AAFBF185AC25438EF21E4FDF55A7E724D3C5A3011D28D27F751545B9AED93F3291156B7F03'
Expand Down
16 changes: 12 additions & 4 deletions cypress/robots/signing.robot.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/// <reference types="cypress"/>

export class SigningRobot {
// TODO: Remove this; should not be required.
reasonableInputTimeEntryDelayMs = 1000;

checkSigningPageExists(): SigningRobot {
cy.get('[data-cy=signing-page]').should('exist');
return this;
Expand All @@ -17,26 +20,30 @@ export class SigningRobot {
}

enterMessage(message: string): SigningRobot {
cy.wait(100);
cy.wait(this.reasonableInputTimeEntryDelayMs);
cy.get('[data-cy=signing-input]').type(message);
cy.wait(this.reasonableInputTimeEntryDelayMs);
return this;
}

enterVerificationAddress(address: string): SigningRobot {
cy.wait(100);
cy.wait(this.reasonableInputTimeEntryDelayMs);
cy.get('[data-cy=verification-address-input]').type(address);
cy.wait(this.reasonableInputTimeEntryDelayMs);
return this;
}

enterVerificationMessage(message: string): SigningRobot {
cy.wait(100);
cy.wait(this.reasonableInputTimeEntryDelayMs);
cy.get('[data-cy=verification-message-input]').type(message);
cy.wait(this.reasonableInputTimeEntryDelayMs);
return this;
}

enterVerificationSignature(sig: string): SigningRobot {
cy.wait(100);
cy.wait(this.reasonableInputTimeEntryDelayMs);
cy.get('[data-cy=verification-signature-input]').type(sig);
cy.wait(this.reasonableInputTimeEntryDelayMs);
return this;
}

Expand Down Expand Up @@ -64,6 +71,7 @@ export class SigningRobot {
}

checkSignatureEquals(message: string): SigningRobot {
cy.wait(this.reasonableInputTimeEntryDelayMs);
cy.get('input[name="signature"]')
.invoke('val')
.then((val) => {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "thebananostand",
"version": "4.3.0",
"version": "4.4.0",
"scripts": {
"ng": "ng",
"start": "ng serve --open --host 0.0.0.0",
Expand Down
6 changes: 6 additions & 0 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ import { provideUserIdleConfig } from 'angular-user-idle';
import { MatSliderModule } from '@angular/material/slider';
import { LOAD_WASM, NgxScannerQrcodeModule } from 'ngx-scanner-qrcode';
import { CommaPipe } from './pipes/comma.pipe';
import { AddRpcOverlayComponent } from '@app/overlays/actions/add-rpc/add-rpc.component';
import { AddRpcDialogComponent } from '@app/overlays/dialogs/add-rpc/add-rpc-dialog.component';
import { AddRpcBottomSheetComponent } from '@app/overlays/bottom-sheet/add-rpc/add-rpc-bottom-sheet.component';

LOAD_WASM().subscribe((res: any) => console.log('WASM ngx-scanner-qrcode loaded', res));

Expand All @@ -108,6 +111,9 @@ LOAD_WASM().subscribe((res: any) => console.log('WASM ngx-scanner-qrcode loaded'
AddIndexBottomSheetComponent,
AddIndexDialogComponent,
AddIndexOverlayComponent,
AddRpcOverlayComponent,
AddRpcDialogComponent,
AddRpcBottomSheetComponent,
AddressBookComponent,
AppAccountSettingsComponent,
AppComponent,
Expand Down
11 changes: 11 additions & 0 deletions src/app/overlays/actions/add-rpc/add-rpc.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.add-rpc-overlay {
width: 380px;
}

.add-rpc-example {
font-family: monospace;
background: #e6e6e6;
padding: 0 4px;
border-radius: 4px;
margin-top: 8px;
}
66 changes: 66 additions & 0 deletions src/app/overlays/actions/add-rpc/add-rpc.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Component, EventEmitter, Output } from '@angular/core';
import { FormControl } from '@angular/forms';
import { ADD_RPC_NODE_BY_URL } from '@app/services/wallet-events.service';

@Component({
selector: 'app-add-rpc-overlay',
styleUrls: ['add-rpc.component.scss'],
template: `
<div class="add-rpc-overlay overlay-action-container">
<div class="overlay-header">Add new Banano RPC Node</div>
<div class="overlay-body">
<div class="mat-body-1" style="margin-bottom: 16px">
If the default Banano nodes are unavailable, you can add a custom RPC node to handle all send,
receive, change transactions.
</div>
<div class="mat-body-1">
<div>Use the input field below to enter the URL of your new Banano node e.g:</div>
<div class="add-rpc-example mat-body-1">https://booster.dev-ptera.com/banano-rpc</div>
</div>
<form style="margin: 32px 0 16px 0">
<mat-form-field style="width: 100%" appearance="fill">
<mat-label>RPC Node URL</mat-label>
<textarea
type="text"
matInput
(keyup.enter)="addRpcNode()"
[formControl]="urlFormControl"
data-cy="add-new-rpc-input"
></textarea>
</mat-form-field>
</form>
</div>
<div class="overlay-footer">
<button mat-stroked-button mat-dialog-close color="primary" (click)="close.emit()">Close</button>
<button
data-cy="add-rpc-overlay-button"
mat-flat-button
color="primary"
[disabled]="isDisabled()"
(click)="addRpcNode()"
>
Add
</button>
</div>
</div>
`,
})
export class AddRpcOverlayComponent {
urlFormControl = new FormControl('');

@Output() close: EventEmitter<void> = new EventEmitter<void>();

isDisabled(): boolean {
return !this.urlFormControl.value;
}

addRpcNode(): void {
if (this.isDisabled()) {
return;
}

// TODO: Add checks to see if the node is accessible and online before adding it to the list.
ADD_RPC_NODE_BY_URL.next(this.urlFormControl.value);
this.close.emit();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Component } from '@angular/core';
import { MatBottomSheetRef } from '@angular/material/bottom-sheet';

@Component({
selector: 'app-add-rpc-bottom-sheet',
template: ` <app-add-rpc-overlay (close)="closeDialog()"></app-add-rpc-overlay> `,
})
export class AddRpcBottomSheetComponent {
constructor(private readonly _sheet: MatBottomSheetRef<AddRpcBottomSheetComponent>) {}

closeDialog(): void {
this._sheet.dismiss();
}
}
14 changes: 14 additions & 0 deletions src/app/overlays/dialogs/add-rpc/add-rpc-dialog.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Component } from '@angular/core';
import { MatDialogRef } from '@angular/material/dialog';

@Component({
selector: 'app-add-rpc-dialog',
template: ` <app-add-rpc-overlay (close)="closeDialog()"></app-add-rpc-overlay> `,
})
export class AddRpcDialogComponent {
constructor(private readonly _dialogRef: MatDialogRef<AddRpcDialogComponent>) {}

closeDialog(): void {
this._dialogRef.close();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import { MatTableDataSource } from '@angular/material/table';
import { ViewportService } from '@app/services/viewport.service';
import { Router } from '@angular/router';
import { UtilService } from '@app/services/util.service';
import { MatDialog } from '@angular/material/dialog';
import { MatBottomSheet } from '@angular/material/bottom-sheet';
import { ThemeService } from '@app/services/theme.service';
import { AccountService } from '@app/services/account.service';
import { MatSort } from '@angular/material/sort';
Expand Down Expand Up @@ -148,8 +146,6 @@ export class AccountTableComponent implements OnInit {
public vp: ViewportService,
private readonly _router: Router,
private readonly _util: UtilService,
private readonly _dialog: MatDialog,
private readonly _sheet: MatBottomSheet,
private readonly _themeService: ThemeService,
private readonly _accountService: AccountService,
private readonly _appStateService: AppStateService
Expand Down
3 changes: 1 addition & 2 deletions src/app/pages/dashboard/dashboard.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Component, ViewEncapsulation } from '@angular/core';
import * as Colors from '@brightlayer-ui/colors';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { ActivatedRoute, Params } from '@angular/router';
import { UtilService } from '@app/services/util.service';
import { MatDialog } from '@angular/material/dialog';
import { ViewportService } from '@app/services/viewport.service';
Expand Down Expand Up @@ -54,7 +54,6 @@ export class DashboardComponent {
constructor(
public vp: ViewportService,
private readonly _route: ActivatedRoute,
private readonly _router: Router,
private readonly _dialog: MatDialog,
private readonly _util: UtilService,
private readonly _sheet: MatBottomSheet,
Expand Down
64 changes: 58 additions & 6 deletions src/app/pages/settings/settings.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ import { Router } from '@angular/router';
import {
EDIT_MINIMUM_INCOMING_THRESHOLD,
REMOVE_ALL_WALLET_DATA,
REMOVE_CUSTOM_RPC_NODE_BY_INDEX,
SELECT_LOCALIZATION_CURRENCY,
SELECTED_RPC_DATASOURCE_CHANGE,
} from '@app/services/wallet-events.service';
import { MatRadioChange } from '@angular/material/radio';
import { CurrencyConversionService } from '@app/services/currency-conversion.service';
import { AppStateService } from '@app/services/app-state.service';
import { MatSelectChange } from '@angular/material/select';
import { UntilDestroy } from '@ngneat/until-destroy';
import { AddRpcBottomSheetComponent } from '@app/overlays/bottom-sheet/add-rpc/add-rpc-bottom-sheet.component';
import { AddRpcDialogComponent } from '@app/overlays/dialogs/add-rpc/add-rpc-dialog.component';

@Pipe({ name: 'available' })
export class DatasourceAvailablePipe implements PipeTransform {
Expand Down Expand Up @@ -60,7 +64,6 @@ export class DatasourceAvailablePipe implements PipeTransform {
mat-stroked-button
blui-inline
color="primary"
class="preserve-non-mobile"
(click)="openChangePasswordOverlay()"
data-cy="change-password-button"
>
Expand All @@ -80,7 +83,6 @@ export class DatasourceAvailablePipe implements PipeTransform {
mat-stroked-button
blui-inline
color="warn"
class="preserve-non-mobile"
longPress
(mouseLongPress)="clearStorage()"
data-cy="clear-storage-button"
Expand Down Expand Up @@ -114,8 +116,24 @@ export class DatasourceAvailablePipe implements PipeTransform {
<mat-card appearance="outlined" style="margin-bottom: 32px">
<div class="mat-headline-6">Data Sources</div>
<mat-divider></mat-divider>
<div class="mat-overline" style="margin-top: 16px">Node RPC Datasource</div>
<div class="mat-body-2">The node which broadcasts send, receive and change transactions.</div>
<div class="account-security-option" responsive style="margin-bottom: 0">
<div style="padding-top: 16px; flex: 1">
<div class="mat-overline">Node RPC Datasource</div>
<div class="mat-body-2">
The node which broadcasts send, receive and change transactions.
</div>
</div>
<button
mat-stroked-button
blui-inline
color="primary"
(click)="openAddRpcOverlay()"
data-cy="add-new-rpc-node-button"
>
<mat-icon>control_point</mat-icon>
<span>Add New</span>
</button>
</div>
<mat-radio-group
style="margin-bottom: 8px; display: inline-block"
aria-label="Select a RPC source"
Expand All @@ -129,6 +147,25 @@ export class DatasourceAvailablePipe implements PipeTransform {
>
<ng-template *ngTemplateOutlet="radioData; context: { source }"></ng-template>
</mat-radio-button>
<div *ngIf="datasourceService.customRpcDataSources.length > 0" class="mat-overline">
Custom Entries
</div>
<div
*ngFor="let source of datasourceService.customRpcDataSources; let i = index"
style="display: flex; align-items: center; justify-content: space-between"
>
<mat-radio-button [value]="source" [aria-label]="'Custom Source ' + i">
<ng-template *ngTemplateOutlet="radioData; context: { source }"></ng-template>
</mat-radio-button>
<button
mat-icon-button
[matTooltip]="'Remove ' + source.alias"
color="warn"
(click)="removeCustomRpcNode(i)"
>
<mat-icon color="warn">clear</mat-icon>
</button>
</div>
</mat-radio-group>
<mat-divider></mat-divider>
<div class="mat-overline" style="margin-top: 16px">Spyglass API Datasource</div>
Expand Down Expand Up @@ -198,8 +235,8 @@ export class DatasourceAvailablePipe implements PipeTransform {
styleUrls: ['./settings.component.scss'],
})
export class SettingsPageComponent implements OnInit {
selectedRpcSource: any;
selectedSpyglassApi: any;
selectedRpcSource: Datasource;
selectedSpyglassApi: Datasource;
selectedCurrencyCode: string;
minimumThreshold: number;

Expand All @@ -216,6 +253,9 @@ export class SettingsPageComponent implements OnInit {
this._appStateService.store.subscribe((data) => {
this.selectedCurrencyCode = data.localCurrencyCode;
});
SELECTED_RPC_DATASOURCE_CHANGE.subscribe((source) => {
this.selectedRpcSource = source;
});
}

async ngOnInit(): Promise<void> {
Expand All @@ -236,6 +276,18 @@ export class SettingsPageComponent implements OnInit {
}
}

openAddRpcOverlay(): void {
if (this.vp.sm) {
this._sheet.open(AddRpcBottomSheetComponent);
} else {
this._dialog.open(AddRpcDialogComponent);
}
}

removeCustomRpcNode(index: number): void {
REMOVE_CUSTOM_RPC_NODE_BY_INDEX.next(index);
}

clearStorage(): void {
REMOVE_ALL_WALLET_DATA.next();
void this._router.navigate(['/']);
Expand Down
Loading

0 comments on commit ce01cb8

Please sign in to comment.