Adding support for optional frontend config.

Dropdown network selector is hidden by default, and enabled using config.
fixes #79
This commit is contained in:
softsimon 2020-06-22 22:10:49 +07:00
parent 7e9ba6b983
commit 0a264a7078
No known key found for this signature in database
GPG Key ID: 488D7DCFB5A430D7
11 changed files with 86 additions and 12 deletions

View File

@ -200,6 +200,13 @@ Build the frontend static HTML/CSS/JS, rsync the output into nginx folder:
sudo rsync -av --delete dist/mempool/ /var/www/html/
```
### Optional frontend configuration
In the `frontend` folder, make a copy of the sample config and modify it to fit your settings.
```bash
cp mempool-frontend-config.sample.json mempool-frontend-config.json
```
## Try It Out
If everything went okay you should see the beautiful mempool :grin:

4
frontend/.gitignore vendored
View File

@ -48,3 +48,7 @@ Thumbs.db
src/resources/assets.json
src/resources/assets.minimal.json
src/resources/pools.json
# environment config
mempool-frontend-config.json
generated-config.js

View File

@ -30,7 +30,9 @@
"styles": [
"src/styles.scss"
],
"scripts": []
"scripts": [
"generated-config.js"
]
},
"configurations": {
"production": {

View File

@ -0,0 +1,36 @@
var fs = require('fs');
const CONFIG_FILE_NAME = 'mempool-frontend-config.json';
const GENERATED_CONFIG_FILE_NAME = 'generated-config.js';
let settings = [];
let configContent = {};
try {
const rawConfig = fs.readFileSync(CONFIG_FILE_NAME);
configContent = JSON.parse(rawConfig);
} catch (e) {
if (e.code !== 'ENOENT') {
throw new Error(e);
}
}
for (setting in configContent) {
settings.push({
key: setting,
value: configContent[setting]
});
}
const code = `(function (window) {
window.__env = window.__env || {};${settings.reduce((str, obj) => `${str}
window.__env.${obj.key} = ${ typeof obj.value === 'string' ? `'${obj.value}'` : obj.value };`, '')}
}(this));`;
try {
fs.writeFileSync(GENERATED_CONFIG_FILE_NAME, code, 'utf8');
} catch (e) {
throw new Error(e);
}
console.log('Config file generated');

View File

@ -0,0 +1,6 @@
{
"TESTNET_ENABLED": false,
"LIQUID_ENABLED": false,
"ELCTRS_ITEMS_PER_PAGE": 25,
"KEEP_BLOCKS_AMOUNT": 8
}

View File

@ -21,10 +21,11 @@
"main": "index.ts",
"scripts": {
"ng": "ng",
"start": "npm run sync-assets-dev && ng serve --proxy-config proxy.conf.json",
"build": "ng build --prod && npm run sync-assets",
"start": "npm run generate-config && npm run sync-assets-dev && ng serve --proxy-config proxy.conf.json",
"build": "npm run generate-config && ng build --prod && npm run sync-assets",
"sync-assets": "node sync-assets.js",
"sync-assets-dev": "node sync-assets.js dev",
"generate-config": "node generate-config.js",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"

View File

@ -34,5 +34,21 @@ export const mempoolFeeColors = [
export const feeLevels = [1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 30, 40, 50, 60, 70, 80, 90, 100, 125, 150, 175, 200,
250, 300, 350, 400, 500, 600, 700, 800, 900, 1000, 1200, 1400, 1600, 1800, 2000];
export const ELCTRS_ITEMS_PER_PAGE = 25;
export const KEEP_BLOCKS_AMOUNT = 8;
interface Env {
TESTNET_ENABLED: boolean;
LIQUID_ENABLED: boolean;
ELCTRS_ITEMS_PER_PAGE: number;
KEEP_BLOCKS_AMOUNT: number;
};
const defaultEnv: Env = {
'TESTNET_ENABLED': false,
'LIQUID_ENABLED': false,
'ELCTRS_ITEMS_PER_PAGE': 25,
'KEEP_BLOCKS_AMOUNT': 8
};
const browserWindow = window || {};
// @ts-ignore
const browserWindowEnv = browserWindow.__env || {};
export const env: Env = Object.assign(defaultEnv, browserWindowEnv);

View File

@ -7,7 +7,7 @@ import { Block, Transaction, Vout } from '../../interfaces/electrs.interface';
import { of } from 'rxjs';
import { StateService } from '../../services/state.service';
import { SeoService } from 'src/app/services/seo.service';
import { ELCTRS_ITEMS_PER_PAGE } from 'src/app/app.constants';
import { env } from 'src/app/app.constants';
@Component({
selector: 'app-block',
@ -28,7 +28,7 @@ export class BlockComponent implements OnInit, OnDestroy {
fees: number;
paginationMaxSize: number;
page = 1;
itemsPerPage = ELCTRS_ITEMS_PER_PAGE;
itemsPerPage = env.ELCTRS_ITEMS_PER_PAGE;
constructor(
private route: ActivatedRoute,

View File

@ -6,14 +6,14 @@
<div class="badge badge-warning connection-badge" style="left: 30px;" *ngIf="connectionState === 1">Reconnecting...</div>
</a>
<div class="btn-group" style="margin-right: 16px;">
<div class="btn-group" style="margin-right: 16px;" *ngIf="env.TESTNET_ENABLED || env.LIQUID_ENABLED">
<button type="button" (click)="networkDropdownHidden = !networkDropdownHidden" class="btn btn-secondary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="sr-only">Toggle Dropdown</span>
</button>
<div class="dropdown-menu" [class.d-block]="!networkDropdownHidden">
<a class="dropdown-item mainnet" [class.active]="network === ''" routerLink="/"><img src="./resources/bitcoin-logo.png" style="width: 35.5px;"> Mainnet</a>
<a class="dropdown-item liquid" [class.active]="network === 'liquid'" routerLink="/liquid"><img src="./resources/liquid-logo.png" style="width: 35.5px;"> Liquid</a>
<a class="dropdown-item testnet" [class.active]="network === 'testnet'" routerLink="/testnet"><img src="./resources/testnet-logo.png" style="width: 35.5px;"> Testnet</a>
<a *ngIf="env.LIQUID_ENABLED" class="dropdown-item liquid" [class.active]="network === 'liquid'" routerLink="/liquid"><img src="./resources/liquid-logo.png" style="width: 35.5px;"> Liquid</a>
<a *ngIf="env.TESTNET_ENABLED" class="dropdown-item testnet" [class.active]="network === 'testnet'" routerLink="/testnet"><img src="./resources/testnet-logo.png" style="width: 35.5px;"> Testnet</a>
</div>
</div>

View File

@ -1,5 +1,6 @@
import { Component, OnInit, HostListener } from '@angular/core';
import { StateService } from '../../services/state.service';
import { env } from 'src/app/app.constants';
@Component({
selector: 'app-master-page',
@ -9,6 +10,7 @@ import { StateService } from '../../services/state.service';
export class MasterPageComponent implements OnInit {
network = '';
tvViewRoute = '/tv';
env = env;
navCollapsed = false;
connectionState = 2;

View File

@ -4,7 +4,7 @@ import { Block, Transaction } from '../interfaces/electrs.interface';
import { MempoolBlock, MemPoolState } from '../interfaces/websocket.interface';
import { OptimizedMempoolStats } from '../interfaces/node-api.interface';
import { Router, NavigationStart } from '@angular/router';
import { KEEP_BLOCKS_AMOUNT } from '../app.constants';
import { env } from '../app.constants';
import { shareReplay, map } from 'rxjs/operators';
interface MarkBlockState {
@ -21,7 +21,7 @@ export class StateService {
latestBlockHeight = 0;
networkChanged$ = new ReplaySubject<string>(1);
blocks$ = new ReplaySubject<[Block, boolean, boolean]>(KEEP_BLOCKS_AMOUNT);
blocks$ = new ReplaySubject<[Block, boolean, boolean]>(env.KEEP_BLOCKS_AMOUNT);
conversions$ = new ReplaySubject<any>(1);
mempoolStats$ = new ReplaySubject<MemPoolState>(1);
mempoolBlocks$ = new ReplaySubject<MempoolBlock[]>(1);