Merge branch 'master' into save-flow-preference
This commit is contained in:
commit
2742acf6ee
@ -129,6 +129,56 @@ class NodesApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async $getFeeHistogram(node_public_key: string): Promise<unknown> {
|
||||||
|
try {
|
||||||
|
const inQuery = `
|
||||||
|
SELECT CASE WHEN fee_rate <= 10.0 THEN CEIL(fee_rate)
|
||||||
|
WHEN (fee_rate > 10.0 and fee_rate <= 100.0) THEN CEIL(fee_rate / 10.0) * 10.0
|
||||||
|
WHEN (fee_rate > 100.0 and fee_rate <= 1000.0) THEN CEIL(fee_rate / 100.0) * 100.0
|
||||||
|
WHEN fee_rate > 1000.0 THEN CEIL(fee_rate / 1000.0) * 1000.0
|
||||||
|
END as bucket,
|
||||||
|
count(short_id) as count,
|
||||||
|
sum(capacity) as capacity
|
||||||
|
FROM (
|
||||||
|
SELECT CASE WHEN node1_public_key = ? THEN node2_fee_rate WHEN node2_public_key = ? THEN node1_fee_rate END as fee_rate,
|
||||||
|
short_id as short_id,
|
||||||
|
capacity as capacity
|
||||||
|
FROM channels
|
||||||
|
WHERE status = 1 AND (channels.node1_public_key = ? OR channels.node2_public_key = ?)
|
||||||
|
) as fee_rate_table
|
||||||
|
GROUP BY bucket;
|
||||||
|
`;
|
||||||
|
const [inRows]: any[] = await DB.query(inQuery, [node_public_key, node_public_key, node_public_key, node_public_key]);
|
||||||
|
|
||||||
|
const outQuery = `
|
||||||
|
SELECT CASE WHEN fee_rate <= 10.0 THEN CEIL(fee_rate)
|
||||||
|
WHEN (fee_rate > 10.0 and fee_rate <= 100.0) THEN CEIL(fee_rate / 10.0) * 10.0
|
||||||
|
WHEN (fee_rate > 100.0 and fee_rate <= 1000.0) THEN CEIL(fee_rate / 100.0) * 100.0
|
||||||
|
WHEN fee_rate > 1000.0 THEN CEIL(fee_rate / 1000.0) * 1000.0
|
||||||
|
END as bucket,
|
||||||
|
count(short_id) as count,
|
||||||
|
sum(capacity) as capacity
|
||||||
|
FROM (
|
||||||
|
SELECT CASE WHEN node1_public_key = ? THEN node1_fee_rate WHEN node2_public_key = ? THEN node2_fee_rate END as fee_rate,
|
||||||
|
short_id as short_id,
|
||||||
|
capacity as capacity
|
||||||
|
FROM channels
|
||||||
|
WHERE status = 1 AND (channels.node1_public_key = ? OR channels.node2_public_key = ?)
|
||||||
|
) as fee_rate_table
|
||||||
|
GROUP BY bucket;
|
||||||
|
`;
|
||||||
|
const [outRows]: any[] = await DB.query(outQuery, [node_public_key, node_public_key, node_public_key, node_public_key]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
incoming: inRows.length > 0 ? inRows : [],
|
||||||
|
outgoing: outRows.length > 0 ? outRows : [],
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
logger.err(`Cannot get node fee distribution for ${node_public_key}. Reason: ${(e instanceof Error ? e.message : e)}`);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async $getAllNodes(): Promise<any> {
|
public async $getAllNodes(): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const query = `SELECT * FROM nodes`;
|
const query = `SELECT * FROM nodes`;
|
||||||
|
@ -20,6 +20,7 @@ class NodesRoutes {
|
|||||||
.get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/rankings/connectivity', this.$getTopNodesByChannels)
|
.get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/rankings/connectivity', this.$getTopNodesByChannels)
|
||||||
.get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/rankings/age', this.$getOldestNodes)
|
.get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/rankings/age', this.$getOldestNodes)
|
||||||
.get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/:public_key/statistics', this.$getHistoricalNodeStats)
|
.get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/:public_key/statistics', this.$getHistoricalNodeStats)
|
||||||
|
.get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/:public_key/fees/histogram', this.$getFeeHistogram)
|
||||||
.get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/:public_key', this.$getNode)
|
.get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/:public_key', this.$getNode)
|
||||||
.get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/group/:name', this.$getNodeGroup)
|
.get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/group/:name', this.$getNodeGroup)
|
||||||
;
|
;
|
||||||
@ -95,6 +96,22 @@ class NodesRoutes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async $getFeeHistogram(req: Request, res: Response) {
|
||||||
|
try {
|
||||||
|
const node = await nodesApi.$getFeeHistogram(req.params.public_key);
|
||||||
|
if (!node) {
|
||||||
|
res.status(404).send('Node not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res.header('Pragma', 'public');
|
||||||
|
res.header('Cache-control', 'public');
|
||||||
|
res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString());
|
||||||
|
res.json(node);
|
||||||
|
} catch (e) {
|
||||||
|
res.status(500).send(e instanceof Error ? e.message : e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async $getNodesRanking(req: Request, res: Response): Promise<void> {
|
private async $getNodesRanking(req: Request, res: Response): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const topCapacityNodes = await nodesApi.$getTopCapacityNodes(false);
|
const topCapacityNodes = await nodesApi.$getTopCapacityNodes(false);
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"ng": "./node_modules/@angular/cli/bin/ng.js",
|
"ng": "./node_modules/@angular/cli/bin/ng.js",
|
||||||
"tsc": "./node_modules/typescript/bin/tsc",
|
"tsc": "./node_modules/typescript/bin/tsc",
|
||||||
"i18n-extract-from-source": "./node_modules/@angular/cli/bin/ng extract-i18n --out-file ./src/locale/messages.xlf",
|
"i18n-extract-from-source": "npm run ng -- extract-i18n --out-file ./src/locale/messages.xlf",
|
||||||
"i18n-pull-from-transifex": "tx pull -a --parallel --minimum-perc 1 --force",
|
"i18n-pull-from-transifex": "tx pull -a --parallel --minimum-perc 1 --force",
|
||||||
"serve": "npm run generate-config && npm run ng -- serve -c local",
|
"serve": "npm run generate-config && npm run ng -- serve -c local",
|
||||||
"serve:stg": "npm run generate-config && npm run ng -- serve -c staging",
|
"serve:stg": "npm run generate-config && npm run ng -- serve -c staging",
|
||||||
|
@ -74,12 +74,14 @@ let routes: Routes = [
|
|||||||
children: [],
|
children: [],
|
||||||
component: AddressComponent,
|
component: AddressComponent,
|
||||||
data: {
|
data: {
|
||||||
ogImage: true
|
ogImage: true,
|
||||||
|
networkSpecific: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'tx',
|
path: 'tx',
|
||||||
component: StartComponent,
|
component: StartComponent,
|
||||||
|
data: { networkSpecific: true },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: ':id',
|
path: ':id',
|
||||||
@ -90,6 +92,7 @@ let routes: Routes = [
|
|||||||
{
|
{
|
||||||
path: 'block',
|
path: 'block',
|
||||||
component: StartComponent,
|
component: StartComponent,
|
||||||
|
data: { networkSpecific: true },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: ':id',
|
path: ':id',
|
||||||
@ -102,6 +105,7 @@ let routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'block-audit',
|
path: 'block-audit',
|
||||||
|
data: { networkSpecific: true },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: ':id',
|
path: ':id',
|
||||||
@ -121,12 +125,13 @@ let routes: Routes = [
|
|||||||
{
|
{
|
||||||
path: 'lightning',
|
path: 'lightning',
|
||||||
loadChildren: () => import('./lightning/lightning.module').then(m => m.LightningModule),
|
loadChildren: () => import('./lightning/lightning.module').then(m => m.LightningModule),
|
||||||
data: { preload: browserWindowEnv && browserWindowEnv.LIGHTNING === true },
|
data: { preload: browserWindowEnv && browserWindowEnv.LIGHTNING === true, networks: ['bitcoin'] },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'status',
|
path: 'status',
|
||||||
|
data: { networks: ['bitcoin', 'liquid'] },
|
||||||
component: StatusViewComponent
|
component: StatusViewComponent
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -185,11 +190,13 @@ let routes: Routes = [
|
|||||||
children: [],
|
children: [],
|
||||||
component: AddressComponent,
|
component: AddressComponent,
|
||||||
data: {
|
data: {
|
||||||
ogImage: true
|
ogImage: true,
|
||||||
|
networkSpecific: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'tx',
|
path: 'tx',
|
||||||
|
data: { networkSpecific: true },
|
||||||
component: StartComponent,
|
component: StartComponent,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
@ -200,6 +207,7 @@ let routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'block',
|
path: 'block',
|
||||||
|
data: { networkSpecific: true },
|
||||||
component: StartComponent,
|
component: StartComponent,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
@ -213,6 +221,7 @@ let routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'block-audit',
|
path: 'block-audit',
|
||||||
|
data: { networkSpecific: true },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: ':id',
|
path: ':id',
|
||||||
@ -230,12 +239,14 @@ let routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'lightning',
|
path: 'lightning',
|
||||||
|
data: { networks: ['bitcoin'] },
|
||||||
loadChildren: () => import('./lightning/lightning.module').then(m => m.LightningModule)
|
loadChildren: () => import('./lightning/lightning.module').then(m => m.LightningModule)
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'status',
|
path: 'status',
|
||||||
|
data: { networks: ['bitcoin', 'liquid'] },
|
||||||
component: StatusViewComponent
|
component: StatusViewComponent
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -291,11 +302,13 @@ let routes: Routes = [
|
|||||||
children: [],
|
children: [],
|
||||||
component: AddressComponent,
|
component: AddressComponent,
|
||||||
data: {
|
data: {
|
||||||
ogImage: true
|
ogImage: true,
|
||||||
|
networkSpecific: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'tx',
|
path: 'tx',
|
||||||
|
data: { networkSpecific: true },
|
||||||
component: StartComponent,
|
component: StartComponent,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
@ -306,6 +319,7 @@ let routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'block',
|
path: 'block',
|
||||||
|
data: { networkSpecific: true },
|
||||||
component: StartComponent,
|
component: StartComponent,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
@ -319,6 +333,7 @@ let routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'block-audit',
|
path: 'block-audit',
|
||||||
|
data: { networkSpecific: true },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: ':id',
|
path: ':id',
|
||||||
@ -336,6 +351,7 @@ let routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'lightning',
|
path: 'lightning',
|
||||||
|
data: { networks: ['bitcoin'] },
|
||||||
loadChildren: () => import('./lightning/lightning.module').then(m => m.LightningModule)
|
loadChildren: () => import('./lightning/lightning.module').then(m => m.LightningModule)
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -359,6 +375,7 @@ let routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'status',
|
path: 'status',
|
||||||
|
data: { networks: ['bitcoin', 'liquid'] },
|
||||||
component: StatusViewComponent
|
component: StatusViewComponent
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -422,11 +439,13 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
|
|||||||
children: [],
|
children: [],
|
||||||
component: AddressComponent,
|
component: AddressComponent,
|
||||||
data: {
|
data: {
|
||||||
ogImage: true
|
ogImage: true,
|
||||||
|
networkSpecific: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'tx',
|
path: 'tx',
|
||||||
|
data: { networkSpecific: true },
|
||||||
component: StartComponent,
|
component: StartComponent,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
@ -437,6 +456,7 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'block',
|
path: 'block',
|
||||||
|
data: { networkSpecific: true },
|
||||||
component: StartComponent,
|
component: StartComponent,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
@ -450,18 +470,22 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'assets',
|
path: 'assets',
|
||||||
|
data: { networks: ['liquid'] },
|
||||||
component: AssetsNavComponent,
|
component: AssetsNavComponent,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: 'all',
|
path: 'all',
|
||||||
|
data: { networks: ['liquid'] },
|
||||||
component: AssetsComponent,
|
component: AssetsComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'asset/:id',
|
path: 'asset/:id',
|
||||||
|
data: { networkSpecific: true },
|
||||||
component: AssetComponent
|
component: AssetComponent
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'group/:id',
|
path: 'group/:id',
|
||||||
|
data: { networkSpecific: true },
|
||||||
component: AssetGroupComponent
|
component: AssetGroupComponent
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -482,6 +506,7 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'status',
|
path: 'status',
|
||||||
|
data: { networks: ['bitcoin', 'liquid'] },
|
||||||
component: StatusViewComponent
|
component: StatusViewComponent
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -532,11 +557,13 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
|
|||||||
children: [],
|
children: [],
|
||||||
component: AddressComponent,
|
component: AddressComponent,
|
||||||
data: {
|
data: {
|
||||||
ogImage: true
|
ogImage: true,
|
||||||
|
networkSpecific: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'tx',
|
path: 'tx',
|
||||||
|
data: { networkSpecific: true },
|
||||||
component: StartComponent,
|
component: StartComponent,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
@ -547,6 +574,7 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'block',
|
path: 'block',
|
||||||
|
data: { networkSpecific: true },
|
||||||
component: StartComponent,
|
component: StartComponent,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
@ -560,22 +588,27 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'assets',
|
path: 'assets',
|
||||||
|
data: { networks: ['liquid'] },
|
||||||
component: AssetsNavComponent,
|
component: AssetsNavComponent,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: 'featured',
|
path: 'featured',
|
||||||
|
data: { networkSpecific: true },
|
||||||
component: AssetsFeaturedComponent,
|
component: AssetsFeaturedComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'all',
|
path: 'all',
|
||||||
|
data: { networks: ['liquid'] },
|
||||||
component: AssetsComponent,
|
component: AssetsComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'asset/:id',
|
path: 'asset/:id',
|
||||||
|
data: { networkSpecific: true },
|
||||||
component: AssetComponent
|
component: AssetComponent
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'group/:id',
|
path: 'group/:id',
|
||||||
|
data: { networkSpecific: true },
|
||||||
component: AssetGroupComponent
|
component: AssetGroupComponent
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -609,6 +642,7 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'status',
|
path: 'status',
|
||||||
|
data: { networks: ['bitcoin', 'liquid']},
|
||||||
component: StatusViewComponent
|
component: StatusViewComponent
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -20,14 +20,17 @@ const routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'markets',
|
path: 'markets',
|
||||||
|
data: { networks: ['bisq'] },
|
||||||
component: BisqDashboardComponent,
|
component: BisqDashboardComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'transactions',
|
path: 'transactions',
|
||||||
|
data: { networks: ['bisq'] },
|
||||||
component: BisqTransactionsComponent
|
component: BisqTransactionsComponent
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'market/:pair',
|
path: 'market/:pair',
|
||||||
|
data: { networkSpecific: true },
|
||||||
component: BisqMarketComponent,
|
component: BisqMarketComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -36,6 +39,7 @@ const routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'tx/:id',
|
path: 'tx/:id',
|
||||||
|
data: { networkSpecific: true },
|
||||||
component: BisqTransactionComponent
|
component: BisqTransactionComponent
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -45,14 +49,17 @@ const routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'block/:id',
|
path: 'block/:id',
|
||||||
|
data: { networkSpecific: true },
|
||||||
component: BisqBlockComponent,
|
component: BisqBlockComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'address/:id',
|
path: 'address/:id',
|
||||||
|
data: { networkSpecific: true },
|
||||||
component: BisqAddressComponent,
|
component: BisqAddressComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'stats',
|
path: 'stats',
|
||||||
|
data: { networks: ['bisq'] },
|
||||||
component: BisqStatsComponent,
|
component: BisqStatsComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -44,13 +44,13 @@
|
|||||||
<app-svg-images name="bisq" width="20" height="20" viewBox="0 0 75 75" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images>
|
<app-svg-images name="bisq" width="20" height="20" viewBox="0 0 75 75" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images>
|
||||||
</button>
|
</button>
|
||||||
<div ngbDropdownMenu [ngClass]="{'dropdown-menu-right' : isMobile}">
|
<div ngbDropdownMenu [ngClass]="{'dropdown-menu-right' : isMobile}">
|
||||||
<a [href]="env.MEMPOOL_WEBSITE_URL + urlLanguage" ngbDropdownItem class="mainnet"><app-svg-images name="bitcoin" width="22" height="22" viewBox="0 0 65 65" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Mainnet</a>
|
<a [href]="env.MEMPOOL_WEBSITE_URL + urlLanguage + (networkPaths['mainnet'] || '/')" ngbDropdownItem class="mainnet"><app-svg-images name="bitcoin" width="22" height="22" viewBox="0 0 65 65" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Mainnet</a>
|
||||||
<a [href]="env.MEMPOOL_WEBSITE_URL + urlLanguage + '/signet'" ngbDropdownItem *ngIf="env.SIGNET_ENABLED" class="signet"><app-svg-images name="signet" width="22" height="22" viewBox="0 0 65 65" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Signet</a>
|
<a [href]="env.MEMPOOL_WEBSITE_URL + urlLanguage + (networkPaths['signet'] || '/signet')" ngbDropdownItem *ngIf="env.SIGNET_ENABLED" class="signet"><app-svg-images name="signet" width="22" height="22" viewBox="0 0 65 65" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Signet</a>
|
||||||
<a [href]="env.MEMPOOL_WEBSITE_URL + urlLanguage + '/testnet'" ngbDropdownItem *ngIf="env.TESTNET_ENABLED" class="testnet"><app-svg-images name="testnet" width="22" height="22" viewBox="0 0 65 65" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Testnet</a>
|
<a [href]="env.MEMPOOL_WEBSITE_URL + urlLanguage + (networkPaths['testnet'] || '/testnet')" ngbDropdownItem *ngIf="env.TESTNET_ENABLED" class="testnet"><app-svg-images name="testnet" width="22" height="22" viewBox="0 0 65 65" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Testnet</a>
|
||||||
<h6 class="dropdown-header" i18n="master-page.layer2-networks-header">Layer 2 Networks</h6>
|
<h6 class="dropdown-header" i18n="master-page.layer2-networks-header">Layer 2 Networks</h6>
|
||||||
<a ngbDropdownItem class="mainnet active" routerLink="/"><app-svg-images name="bisq" width="20" height="20" viewBox="0 0 75 75" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Bisq</a>
|
<a ngbDropdownItem class="mainnet active" [routerLink]="networkPaths['bisq'] || '/'"><app-svg-images name="bisq" width="20" height="20" viewBox="0 0 75 75" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Bisq</a>
|
||||||
<a [href]="env.LIQUID_WEBSITE_URL + urlLanguage" ngbDropdownItem *ngIf="env.LIQUID_ENABLED" class="liquid"><app-svg-images name="liquid" width="22" height="22" viewBox="0 0 125 125" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Liquid</a>
|
<a [href]="env.LIQUID_WEBSITE_URL + urlLanguage + (networkPaths['liquid'] || '/')" ngbDropdownItem *ngIf="env.LIQUID_ENABLED" class="liquid"><app-svg-images name="liquid" width="22" height="22" viewBox="0 0 125 125" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Liquid</a>
|
||||||
<a [href]="env.LIQUID_WEBSITE_URL + urlLanguage + '/testnet'" ngbDropdownItem *ngIf="env.LIQUID_TESTNET_ENABLED" class="liquidtestnet"><app-svg-images name="liquidtestnet" width="22" height="22" viewBox="0 0 125 125" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Liquid Testnet</a>
|
<a [href]="env.LIQUID_WEBSITE_URL + urlLanguage + (networkPaths['liquidtestnet'] || '/testnet')" ngbDropdownItem *ngIf="env.LIQUID_TESTNET_ENABLED" class="liquidtestnet"><app-svg-images name="liquidtestnet" width="22" height="22" viewBox="0 0 125 125" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Liquid Testnet</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ import { Env, StateService } from '../../services/state.service';
|
|||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { LanguageService } from '../../services/language.service';
|
import { LanguageService } from '../../services/language.service';
|
||||||
import { EnterpriseService } from '../../services/enterprise.service';
|
import { EnterpriseService } from '../../services/enterprise.service';
|
||||||
|
import { NavigationService } from '../../services/navigation.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-bisq-master-page',
|
selector: 'app-bisq-master-page',
|
||||||
@ -15,17 +16,23 @@ export class BisqMasterPageComponent implements OnInit {
|
|||||||
env: Env;
|
env: Env;
|
||||||
isMobile = window.innerWidth <= 767.98;
|
isMobile = window.innerWidth <= 767.98;
|
||||||
urlLanguage: string;
|
urlLanguage: string;
|
||||||
|
networkPaths: { [network: string]: string };
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
private languageService: LanguageService,
|
private languageService: LanguageService,
|
||||||
private enterpriseService: EnterpriseService,
|
private enterpriseService: EnterpriseService,
|
||||||
|
private navigationService: NavigationService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.env = this.stateService.env;
|
this.env = this.stateService.env;
|
||||||
this.connectionState$ = this.stateService.connectionState$;
|
this.connectionState$ = this.stateService.connectionState$;
|
||||||
this.urlLanguage = this.languageService.getLanguageForUrl();
|
this.urlLanguage = this.languageService.getLanguageForUrl();
|
||||||
|
this.navigationService.subnetPaths.subscribe((paths) => {
|
||||||
|
console.log('network paths updated...');
|
||||||
|
this.networkPaths = paths;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
collapse(): void {
|
collapse(): void {
|
||||||
|
@ -31,17 +31,17 @@
|
|||||||
<button class="btn btn-primary w-100" id="dropdownBasic1" ngbDropdownToggle i18n="lightning">Lightning</button>
|
<button class="btn btn-primary w-100" id="dropdownBasic1" ngbDropdownToggle i18n="lightning">Lightning</button>
|
||||||
<div ngbDropdownMenu aria-labelledby="dropdownBasic1">
|
<div ngbDropdownMenu aria-labelledby="dropdownBasic1">
|
||||||
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/lightning/nodes-networks' | relativeUrl]"
|
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/lightning/nodes-networks' | relativeUrl]"
|
||||||
i18n="lightning.nodes-networks">Lightning nodes per network</a>
|
i18n="lightning.nodes-networks">Lightning Nodes Per Network</a>
|
||||||
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/lightning/capacity' | relativeUrl]"
|
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/lightning/capacity' | relativeUrl]"
|
||||||
i18n="lightning.capacity">Network capacity</a>
|
i18n="lightning.network-capacity">Lightning Network Capacity</a>
|
||||||
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/lightning/nodes-per-isp' | relativeUrl]"
|
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/lightning/nodes-per-isp' | relativeUrl]"
|
||||||
i18n="lightning.nodes-per-isp">Lightning nodes per ISP</a>
|
i18n="lightning.nodes-per-isp">Lightning Nodes Per ISP</a>
|
||||||
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/lightning/nodes-per-country' | relativeUrl]"
|
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/lightning/nodes-per-country' | relativeUrl]"
|
||||||
i18n="lightning.nodes-per-country">Lightning nodes per country</a>
|
i18n="lightning.nodes-per-country">Lightning Nodes Per Country</a>
|
||||||
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/lightning/nodes-map' | relativeUrl]"
|
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/lightning/nodes-map' | relativeUrl]"
|
||||||
i18n="lightning.lightning.nodes-heatmap">Lightning nodes world map</a>
|
i18n="lightning.lightning.nodes-heatmap">Lightning Nodes World Map</a>
|
||||||
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/lightning/nodes-channels-map' | relativeUrl]"
|
<a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/lightning/nodes-channels-map' | relativeUrl]"
|
||||||
i18n="lightning.nodes-channels-world-map">Lightning nodes channels world map</a>
|
i18n="lightning.nodes-channels-world-map">Lightning Nodes Channels World Map</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -49,13 +49,13 @@
|
|||||||
<app-svg-images [name]="network.val === '' ? 'liquid' : network.val" width="22" height="22" viewBox="0 0 125 125" style="width: 30px; height: 30px; margin-right: 5px;"></app-svg-images>
|
<app-svg-images [name]="network.val === '' ? 'liquid' : network.val" width="22" height="22" viewBox="0 0 125 125" style="width: 30px; height: 30px; margin-right: 5px;"></app-svg-images>
|
||||||
</button>
|
</button>
|
||||||
<div ngbDropdownMenu [ngClass]="{'dropdown-menu-right' : isMobile}">
|
<div ngbDropdownMenu [ngClass]="{'dropdown-menu-right' : isMobile}">
|
||||||
<a [href]="env.MEMPOOL_WEBSITE_URL + urlLanguage" ngbDropdownItem class="mainnet"><app-svg-images name="bitcoin" width="22" height="22" viewBox="0 0 65 65" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Mainnet</a>
|
<a [href]="env.MEMPOOL_WEBSITE_URL + urlLanguage + (networkPaths['mainnet'] || '')" ngbDropdownItem class="mainnet"><app-svg-images name="bitcoin" width="22" height="22" viewBox="0 0 65 65" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Mainnet</a>
|
||||||
<a [href]="env.MEMPOOL_WEBSITE_URL + urlLanguage + '/signet'" ngbDropdownItem *ngIf="env.SIGNET_ENABLED" class="signet"><app-svg-images name="signet" width="22" height="22" viewBox="0 0 65 65" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Signet</a>
|
<a [href]="env.MEMPOOL_WEBSITE_URL + urlLanguage + (networkPaths['signet'] || '/signet')" ngbDropdownItem *ngIf="env.SIGNET_ENABLED" class="signet"><app-svg-images name="signet" width="22" height="22" viewBox="0 0 65 65" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Signet</a>
|
||||||
<a [href]="env.MEMPOOL_WEBSITE_URL + urlLanguage + '/testnet'" ngbDropdownItem *ngIf="env.TESTNET_ENABLED" class="testnet"><app-svg-images name="testnet" width="22" height="22" viewBox="0 0 65 65" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Testnet</a>
|
<a [href]="env.MEMPOOL_WEBSITE_URL + urlLanguage + (networkPaths['testnet'] || '/testnet')" ngbDropdownItem *ngIf="env.TESTNET_ENABLED" class="testnet"><app-svg-images name="testnet" width="22" height="22" viewBox="0 0 65 65" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Testnet</a>
|
||||||
<h6 class="dropdown-header" i18n="master-page.layer2-networks-header">Layer 2 Networks</h6>
|
<h6 class="dropdown-header" i18n="master-page.layer2-networks-header">Layer 2 Networks</h6>
|
||||||
<a [href]="env.BISQ_WEBSITE_URL + urlLanguage" ngbDropdownItem class="mainnet"><app-svg-images name="bisq" width="22" height="22" viewBox="0 0 75 75" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Bisq</a>
|
<a [href]="env.BISQ_WEBSITE_URL + urlLanguage + (networkPaths['bisq'] || '')" ngbDropdownItem class="mainnet"><app-svg-images name="bisq" width="22" height="22" viewBox="0 0 75 75" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Bisq</a>
|
||||||
<a ngbDropdownItem class="liquid mr-1" [class.active]="network.val === 'liquid'" routerLink="/"><app-svg-images name="liquid" width="22" height="22" viewBox="0 0 125 125" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Liquid</a>
|
<a ngbDropdownItem class="liquid mr-1" [class.active]="network.val === 'liquid'" [routerLink]="networkPaths['liquid'] || '/'"><app-svg-images name="liquid" width="22" height="22" viewBox="0 0 125 125" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Liquid</a>
|
||||||
<a ngbDropdownItem *ngIf="env.LIQUID_TESTNET_ENABLED" class="liquidtestnet" [class.active]="network.val === 'liquidtestnet'" routerLink="/testnet"><app-svg-images name="liquidtestnet" width="22" height="22" viewBox="0 0 125 125" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Liquid Testnet</a>
|
<a ngbDropdownItem *ngIf="env.LIQUID_TESTNET_ENABLED" class="liquidtestnet" [class.active]="network.val === 'liquidtestnet'" [routerLink]="networkPaths['liquidtestnet'] || '/testnet'"><app-svg-images name="liquidtestnet" width="22" height="22" viewBox="0 0 125 125" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Liquid Testnet</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ import { Env, StateService } from '../../services/state.service';
|
|||||||
import { merge, Observable, of} from 'rxjs';
|
import { merge, Observable, of} from 'rxjs';
|
||||||
import { LanguageService } from '../../services/language.service';
|
import { LanguageService } from '../../services/language.service';
|
||||||
import { EnterpriseService } from '../../services/enterprise.service';
|
import { EnterpriseService } from '../../services/enterprise.service';
|
||||||
|
import { NavigationService } from '../../services/navigation.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-liquid-master-page',
|
selector: 'app-liquid-master-page',
|
||||||
@ -17,11 +18,13 @@ export class LiquidMasterPageComponent implements OnInit {
|
|||||||
officialMempoolSpace = this.stateService.env.OFFICIAL_MEMPOOL_SPACE;
|
officialMempoolSpace = this.stateService.env.OFFICIAL_MEMPOOL_SPACE;
|
||||||
network$: Observable<string>;
|
network$: Observable<string>;
|
||||||
urlLanguage: string;
|
urlLanguage: string;
|
||||||
|
networkPaths: { [network: string]: string };
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
private languageService: LanguageService,
|
private languageService: LanguageService,
|
||||||
private enterpriseService: EnterpriseService,
|
private enterpriseService: EnterpriseService,
|
||||||
|
private navigationService: NavigationService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@ -29,6 +32,10 @@ export class LiquidMasterPageComponent implements OnInit {
|
|||||||
this.connectionState$ = this.stateService.connectionState$;
|
this.connectionState$ = this.stateService.connectionState$;
|
||||||
this.network$ = merge(of(''), this.stateService.networkChanged$);
|
this.network$ = merge(of(''), this.stateService.networkChanged$);
|
||||||
this.urlLanguage = this.languageService.getLanguageForUrl();
|
this.urlLanguage = this.languageService.getLanguageForUrl();
|
||||||
|
this.navigationService.subnetPaths.subscribe((paths) => {
|
||||||
|
console.log('network paths updated...');
|
||||||
|
this.networkPaths = paths;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
collapse(): void {
|
collapse(): void {
|
||||||
|
@ -22,13 +22,13 @@
|
|||||||
<app-svg-images [name]="network.val === '' ? 'bitcoin' : network.val" width="20" height="20" viewBox="0 0 65 65" style="width: 30px; height: 30px; margin-right: 5px;"></app-svg-images>
|
<app-svg-images [name]="network.val === '' ? 'bitcoin' : network.val" width="20" height="20" viewBox="0 0 65 65" style="width: 30px; height: 30px; margin-right: 5px;"></app-svg-images>
|
||||||
</button>
|
</button>
|
||||||
<div ngbDropdownMenu [ngClass]="{'dropdown-menu-right' : isMobile}">
|
<div ngbDropdownMenu [ngClass]="{'dropdown-menu-right' : isMobile}">
|
||||||
<a ngbDropdownItem class="mainnet" routerLink="/"><app-svg-images name="bitcoin" width="22" height="22" viewBox="0 0 65 65" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Mainnet</a>
|
<a ngbDropdownItem class="mainnet" [routerLink]="networkPaths['mainnet'] || '/'"><app-svg-images name="bitcoin" width="22" height="22" viewBox="0 0 65 65" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Mainnet</a>
|
||||||
<a ngbDropdownItem *ngIf="env.SIGNET_ENABLED" class="signet" [class.active]="network.val === 'signet'" routerLink="/signet"><app-svg-images name="signet" width="22" height="22" viewBox="0 0 65 65" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Signet</a>
|
<a ngbDropdownItem *ngIf="env.SIGNET_ENABLED" class="signet" [class.active]="network.val === 'signet'" [routerLink]="networkPaths['signet'] || '/signet'"><app-svg-images name="signet" width="22" height="22" viewBox="0 0 65 65" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Signet</a>
|
||||||
<a ngbDropdownItem *ngIf="env.TESTNET_ENABLED" class="testnet" [class.active]="network.val === 'testnet'" routerLink="/testnet"><app-svg-images name="testnet" width="22" height="22" viewBox="0 0 65 65" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Testnet</a>
|
<a ngbDropdownItem *ngIf="env.TESTNET_ENABLED" class="testnet" [class.active]="network.val === 'testnet'" [routerLink]="networkPaths['testnet'] || '/testnet'"><app-svg-images name="testnet" width="22" height="22" viewBox="0 0 65 65" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Testnet</a>
|
||||||
<h6 *ngIf="env.LIQUID_ENABLED || env.BISQ_ENABLED" class="dropdown-header" i18n="master-page.layer2-networks-header">Layer 2 Networks</h6>
|
<h6 *ngIf="env.LIQUID_ENABLED || env.BISQ_ENABLED" class="dropdown-header" i18n="master-page.layer2-networks-header">Layer 2 Networks</h6>
|
||||||
<a [href]="env.BISQ_WEBSITE_URL + urlLanguage" ngbDropdownItem *ngIf="env.BISQ_ENABLED" class="bisq"><app-svg-images name="bisq" width="20" height="20" viewBox="0 0 75 75" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Bisq</a>
|
<a [href]="env.BISQ_WEBSITE_URL + urlLanguage + (networkPaths['bisq'] || '')" ngbDropdownItem *ngIf="env.BISQ_ENABLED" class="bisq"><app-svg-images name="bisq" width="20" height="20" viewBox="0 0 75 75" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Bisq</a>
|
||||||
<a [href]="env.LIQUID_WEBSITE_URL + urlLanguage" ngbDropdownItem *ngIf="env.LIQUID_ENABLED" class="liquid" [class.active]="network.val === 'liquid'"><app-svg-images name="liquid" width="22" height="22" viewBox="0 0 125 125" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Liquid</a>
|
<a [href]="env.LIQUID_WEBSITE_URL + urlLanguage + (networkPaths['liquid'] || '')" ngbDropdownItem *ngIf="env.LIQUID_ENABLED" class="liquid" [class.active]="network.val === 'liquid'"><app-svg-images name="liquid" width="22" height="22" viewBox="0 0 125 125" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Liquid</a>
|
||||||
<a [href]="env.LIQUID_WEBSITE_URL + urlLanguage + '/testnet'" ngbDropdownItem *ngIf="env.LIQUID_TESTNET_ENABLED" class="liquidtestnet" [class.active]="network.val === 'liquid'"><app-svg-images name="liquidtestnet" width="22" height="22" viewBox="0 0 125 125" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Liquid Testnet</a>
|
<a [href]="env.LIQUID_WEBSITE_URL + urlLanguage + (networkPaths['liquidtestnet'] || '/testnet')" ngbDropdownItem *ngIf="env.LIQUID_TESTNET_ENABLED" class="liquidtestnet" [class.active]="network.val === 'liquid'"><app-svg-images name="liquidtestnet" width="22" height="22" viewBox="0 0 125 125" style="width: 25px; height: 25px;" class="mainnet mr-1"></app-svg-images> Liquid Testnet</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ import { Env, StateService } from '../../services/state.service';
|
|||||||
import { Observable, merge, of } from 'rxjs';
|
import { Observable, merge, of } from 'rxjs';
|
||||||
import { LanguageService } from '../../services/language.service';
|
import { LanguageService } from '../../services/language.service';
|
||||||
import { EnterpriseService } from '../../services/enterprise.service';
|
import { EnterpriseService } from '../../services/enterprise.service';
|
||||||
|
import { NavigationService } from '../../services/navigation.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-master-page',
|
selector: 'app-master-page',
|
||||||
@ -18,11 +19,13 @@ export class MasterPageComponent implements OnInit {
|
|||||||
officialMempoolSpace = this.stateService.env.OFFICIAL_MEMPOOL_SPACE;
|
officialMempoolSpace = this.stateService.env.OFFICIAL_MEMPOOL_SPACE;
|
||||||
urlLanguage: string;
|
urlLanguage: string;
|
||||||
subdomain = '';
|
subdomain = '';
|
||||||
|
networkPaths: { [network: string]: string };
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public stateService: StateService,
|
public stateService: StateService,
|
||||||
private languageService: LanguageService,
|
private languageService: LanguageService,
|
||||||
private enterpriseService: EnterpriseService,
|
private enterpriseService: EnterpriseService,
|
||||||
|
private navigationService: NavigationService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@ -31,6 +34,10 @@ export class MasterPageComponent implements OnInit {
|
|||||||
this.network$ = merge(of(''), this.stateService.networkChanged$);
|
this.network$ = merge(of(''), this.stateService.networkChanged$);
|
||||||
this.urlLanguage = this.languageService.getLanguageForUrl();
|
this.urlLanguage = this.languageService.getLanguageForUrl();
|
||||||
this.subdomain = this.enterpriseService.getSubdomain();
|
this.subdomain = this.enterpriseService.getSubdomain();
|
||||||
|
this.navigationService.subnetPaths.subscribe((paths) => {
|
||||||
|
console.log('network paths updated...');
|
||||||
|
this.networkPaths = paths;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
collapse(): void {
|
collapse(): void {
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
</span>
|
</span>
|
||||||
<span class="field col-sm-4 text-center"><ng-container *ngIf="transactionTime > 0">‎{{ transactionTime * 1000 | date:'yyyy-MM-dd HH:mm' }}</ng-container></span>
|
<span class="field col-sm-4 text-center"><ng-container *ngIf="transactionTime > 0">‎{{ transactionTime * 1000 | date:'yyyy-MM-dd HH:mm' }}</ng-container></span>
|
||||||
<span class="field col-sm-4 text-right"><span class="label" i18n="transaction.fee|Transaction fee">Fee </span>{{ tx.fee | number }} <span class="symbol" i18n="shared.sat|sat">sat</span></span>
|
<span class="field col-sm-4 text-right"><span class="label" i18n="transaction.fee|Transaction fee">Fee</span> {{ tx.fee | number }} <span class="symbol" i18n="shared.sat|sat">sat</span></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.container-buttons {
|
.container-buttons {
|
||||||
align-self: flex-start;
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title-block {
|
.title-block {
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
<ng-container [ngSwitch]="line.type">
|
<ng-container [ngSwitch]="line.type">
|
||||||
<span *ngSwitchCase="'input'" i18n="transaction.input">Input</span>
|
<span *ngSwitchCase="'input'" i18n="transaction.input">Input</span>
|
||||||
<span *ngSwitchCase="'output'" i18n="transaction.output">Output</span>
|
<span *ngSwitchCase="'output'" i18n="transaction.output">Output</span>
|
||||||
<span *ngSwitchCase="'fee'" i18n="transaction.fee">Fee</span>
|
<span *ngSwitchCase="'fee'" i18n="transaction.fee|Transaction fee">Fee</span>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<span *ngIf="line.type !== 'fee'"> #{{ line.index + 1 }}</span>
|
<span *ngIf="line.type !== 'fee'"> #{{ line.index + 1 }}</span>
|
||||||
</p>
|
</p>
|
||||||
|
@ -68,7 +68,7 @@
|
|||||||
<path
|
<path
|
||||||
[attr.d]="input.path"
|
[attr.d]="input.path"
|
||||||
class="line {{input.class}}"
|
class="line {{input.class}}"
|
||||||
[class.highlight]="inputData[i].index === inputIndex"
|
[class.highlight]="inputIndex != null && inputData[i].index === inputIndex"
|
||||||
[style]="input.style"
|
[style]="input.style"
|
||||||
attr.marker-start="url(#{{input.class}}-arrow)"
|
attr.marker-start="url(#{{input.class}}-arrow)"
|
||||||
(pointerover)="onHover($event, 'input', i);"
|
(pointerover)="onHover($event, 'input', i);"
|
||||||
@ -80,7 +80,7 @@
|
|||||||
<path
|
<path
|
||||||
[attr.d]="output.path"
|
[attr.d]="output.path"
|
||||||
class="line {{output.class}}"
|
class="line {{output.class}}"
|
||||||
[class.highlight]="outputData[i].index === outputIndex"
|
[class.highlight]="outputIndex != null && outputData[i].index === outputIndex"
|
||||||
[style]="output.style"
|
[style]="output.style"
|
||||||
attr.marker-start="url(#{{output.class}}-arrow)"
|
attr.marker-start="url(#{{output.class}}-arrow)"
|
||||||
(pointerover)="onHover($event, 'output', i);"
|
(pointerover)="onHover($event, 'output', i);"
|
||||||
|
@ -123,7 +123,7 @@
|
|||||||
<th class="table-cell-txid" i18n="dashboard.latest-transactions.txid">TXID</th>
|
<th class="table-cell-txid" i18n="dashboard.latest-transactions.txid">TXID</th>
|
||||||
<th class="table-cell-satoshis" i18n="dashboard.latest-transactions.amount">Amount</th>
|
<th class="table-cell-satoshis" i18n="dashboard.latest-transactions.amount">Amount</th>
|
||||||
<th class="table-cell-fiat" *ngIf="(network$ | async) === ''" i18n="dashboard.latest-transactions.USD">USD</th>
|
<th class="table-cell-fiat" *ngIf="(network$ | async) === ''" i18n="dashboard.latest-transactions.USD">USD</th>
|
||||||
<th class="table-cell-fees" i18n="dashboard.latest-transactions.fee">Fee</th>
|
<th class="table-cell-fees" i18n="transaction.fee|Transaction fee">Fee</th>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr *ngFor="let transaction of transactions$ | async; let i = index;">
|
<tr *ngFor="let transaction of transactions$ | async; let i = index;">
|
||||||
|
@ -39,6 +39,7 @@ if (browserWindowEnv.BASE_MODULE && (browserWindowEnv.BASE_MODULE === 'bisq' ||
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'faq',
|
path: 'faq',
|
||||||
|
data: { networks: ['bitcoin'] },
|
||||||
component: DocsComponent
|
component: DocsComponent
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -37,10 +37,12 @@ const routes: Routes = [
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: 'mining/pool/:slug',
|
path: 'mining/pool/:slug',
|
||||||
|
data: { networks: ['bitcoin'] },
|
||||||
component: PoolComponent,
|
component: PoolComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'mining',
|
path: 'mining',
|
||||||
|
data: { networks: ['bitcoin'] },
|
||||||
component: StartComponent,
|
component: StartComponent,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
@ -51,6 +53,7 @@ const routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'mempool-block/:id',
|
path: 'mempool-block/:id',
|
||||||
|
data: { networks: ['bitcoin', 'liquid'] },
|
||||||
component: StartComponent,
|
component: StartComponent,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
@ -61,62 +64,77 @@ const routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'graphs',
|
path: 'graphs',
|
||||||
|
data: { networks: ['bitcoin', 'liquid'] },
|
||||||
component: GraphsComponent,
|
component: GraphsComponent,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: 'mempool',
|
path: 'mempool',
|
||||||
|
data: { networks: ['bitcoin', 'liquid'] },
|
||||||
component: StatisticsComponent,
|
component: StatisticsComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'mining/hashrate-difficulty',
|
path: 'mining/hashrate-difficulty',
|
||||||
|
data: { networks: ['bitcoin'] },
|
||||||
component: HashrateChartComponent,
|
component: HashrateChartComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'mining/pools-dominance',
|
path: 'mining/pools-dominance',
|
||||||
|
data: { networks: ['bitcoin'] },
|
||||||
component: HashrateChartPoolsComponent,
|
component: HashrateChartPoolsComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'mining/pools',
|
path: 'mining/pools',
|
||||||
|
data: { networks: ['bitcoin'] },
|
||||||
component: PoolRankingComponent,
|
component: PoolRankingComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'mining/block-fees',
|
path: 'mining/block-fees',
|
||||||
|
data: { networks: ['bitcoin'] },
|
||||||
component: BlockFeesGraphComponent,
|
component: BlockFeesGraphComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'mining/block-rewards',
|
path: 'mining/block-rewards',
|
||||||
|
data: { networks: ['bitcoin'] },
|
||||||
component: BlockRewardsGraphComponent,
|
component: BlockRewardsGraphComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'mining/block-fee-rates',
|
path: 'mining/block-fee-rates',
|
||||||
|
data: { networks: ['bitcoin'] },
|
||||||
component: BlockFeeRatesGraphComponent,
|
component: BlockFeeRatesGraphComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'mining/block-sizes-weights',
|
path: 'mining/block-sizes-weights',
|
||||||
|
data: { networks: ['bitcoin'] },
|
||||||
component: BlockSizesWeightsGraphComponent,
|
component: BlockSizesWeightsGraphComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'lightning/nodes-networks',
|
path: 'lightning/nodes-networks',
|
||||||
|
data: { networks: ['bitcoin'] },
|
||||||
component: NodesNetworksChartComponent,
|
component: NodesNetworksChartComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'lightning/capacity',
|
path: 'lightning/capacity',
|
||||||
|
data: { networks: ['bitcoin'] },
|
||||||
component: LightningStatisticsChartComponent,
|
component: LightningStatisticsChartComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'lightning/nodes-per-isp',
|
path: 'lightning/nodes-per-isp',
|
||||||
|
data: { networks: ['bitcoin'] },
|
||||||
component: NodesPerISPChartComponent,
|
component: NodesPerISPChartComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'lightning/nodes-per-country',
|
path: 'lightning/nodes-per-country',
|
||||||
|
data: { networks: ['bitcoin'] },
|
||||||
component: NodesPerCountryChartComponent,
|
component: NodesPerCountryChartComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'lightning/nodes-map',
|
path: 'lightning/nodes-map',
|
||||||
|
data: { networks: ['bitcoin'] },
|
||||||
component: NodesMap,
|
component: NodesMap,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'lightning/nodes-channels-map',
|
path: 'lightning/nodes-channels-map',
|
||||||
|
data: { networks: ['bitcoin'] },
|
||||||
component: NodesChannelsMap,
|
component: NodesChannelsMap,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -125,6 +143,7 @@ const routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'mining/block-prediction',
|
path: 'mining/block-prediction',
|
||||||
|
data: { networks: ['bitcoin'] },
|
||||||
component: BlockPredictionGraphComponent,
|
component: BlockPredictionGraphComponent,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -141,6 +160,7 @@ const routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'tv',
|
path: 'tv',
|
||||||
|
data: { networks: ['bitcoin', 'liquid'] },
|
||||||
component: TelevisionComponent
|
component: TelevisionComponent
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<app-clipboard [text]="channel.public_key"></app-clipboard>
|
<app-clipboard [text]="channel.public_key"></app-clipboard>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-right">
|
<div class="box-right">
|
||||||
<div class="second-line">{{ channel.channels }} channels</div>
|
<div class="second-line"><ng-container *ngTemplateOutlet="xChannels; context: {$implicit: channel.channels }"></ng-container></div>
|
||||||
<div class="second-line"><app-amount [satoshis]="channel.capacity" digitsInfo="1.2-2"></app-amount></div>
|
<div class="second-line"><app-amount [satoshis]="channel.capacity" digitsInfo="1.2-2"></app-amount></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -16,7 +16,7 @@
|
|||||||
<table class="table table-borderless table-striped">
|
<table class="table table-borderless table-striped">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td i18n="lightning.fee-rate">Fee rate</td>
|
<td i18n="transaction.fee-rate|Transaction fee rate">Fee rate</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="d-inline-block d-md-none">
|
<span class="d-inline-block d-md-none">
|
||||||
{{ channel.fee_rate !== null ? (channel.fee_rate | amountShortener : 2 : undefined : true) : '-' }} <span class="symbol">ppm {{ channel.fee_rate !== null ? '(' + (channel.fee_rate / 10000 | amountShortener : 2 : undefined : true) + '%)' : '' }}</span>
|
{{ channel.fee_rate !== null ? (channel.fee_rate | amountShortener : 2 : undefined : true) : '-' }} <span class="symbol">ppm {{ channel.fee_rate !== null ? '(' + (channel.fee_rate / 10000 | amountShortener : 2 : undefined : true) + '%)' : '' }}</span>
|
||||||
@ -33,19 +33,24 @@
|
|||||||
<span>
|
<span>
|
||||||
<span *ngIf="channel.base_fee_mtokens !== null">
|
<span *ngIf="channel.base_fee_mtokens !== null">
|
||||||
{{ channel.base_fee_mtokens | amountShortener : 0 }}
|
{{ channel.base_fee_mtokens | amountShortener : 0 }}
|
||||||
<span class="symbol">msats</span>
|
<span class="symbol" i18n="shared.m-sats">mSats</span>
|
||||||
</span>
|
</span>
|
||||||
<span *ngIf="channel.base_fee_mtokens === null">
|
<span *ngIf="channel.base_fee_mtokens === null">
|
||||||
-
|
-
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<span *ngIf="channel.base_fee_mtokens !== null" class="badge" [class]="channel.base_fee_mtokens === 0 ? 'badge-success' : 'badge-danger'"
|
<ng-template [ngIf]="channel.base_fee_mtokens !== null">
|
||||||
i18n-ngbTooltip="lightning.zero-base-fee"
|
<span class="badge badge-success" *ngIf="channel.base_fee_mtokens === 0; else nonZeroBaseFee"
|
||||||
[ngbTooltip]="channel.base_fee_mtokens === 0 ? 'This channel supports zero base fee routing' :
|
i18n-ngbTooltip="lightning.zero-base-fee-tooltip"
|
||||||
'This channel does not support zero base fee routing'"
|
ngbTooltip="This channel supports zero base fee routing"
|
||||||
placement="bottom" i18n="lightning.zerobasefee">
|
placement="bottom" i18n="lightning.zero-base-fee">Zero base fee</span>
|
||||||
{{ channel.base_fee_mtokens === 0 ? 'Zero base fee' : 'Non-zero base fee' }}
|
</ng-template>
|
||||||
</span>
|
<ng-template #nonZeroBaseFee>
|
||||||
|
<span class="badge badge-danger"
|
||||||
|
i18n-ngbTooltip="lightning.non-zero-base-fee-tooltip"
|
||||||
|
ngbTooltip="This channel does not support zero base fee routing"
|
||||||
|
placement="bottom" i18n="lightning.non-zero-base-fee">Non-zero base fee</span>
|
||||||
|
</ng-template>
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -62,7 +67,7 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td i18n="lightning.timelock-detla">Timelock delta</td>
|
<td i18n="lightning.timelock-delta">Timelock delta</td>
|
||||||
<td>
|
<td>
|
||||||
<ng-container *ngTemplateOutlet="blocksPlural; context: {$implicit: channel.cltv_delta ?? '-' }"></ng-container>
|
<ng-container *ngTemplateOutlet="blocksPlural; context: {$implicit: channel.cltv_delta ?? '-' }"></ng-container>
|
||||||
</td>
|
</td>
|
||||||
@ -72,3 +77,4 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ng-template #blocksPlural let-i i18n="shared.blocks">{{ i }} <span class="shared-block">blocks</span></ng-template>
|
<ng-template #blocksPlural let-i i18n="shared.blocks">{{ i }} <span class="shared-block">blocks</span></ng-template>
|
||||||
|
<ng-template #xChannels let-i i18n="lightning.x-channels">{{ i }} channels</ng-template>
|
||||||
|
@ -7,9 +7,9 @@
|
|||||||
<h1 class="title">{{ channel.short_id }}</h1>
|
<h1 class="title">{{ channel.short_id }}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="badges mb-2">
|
<div class="badges mb-2">
|
||||||
<span class="badge rounded-pill badge-secondary" *ngIf="channel.status === 0">Inactive</span>
|
<span class="badge rounded-pill badge-secondary" *ngIf="channel.status === 0" i18n="status.inactive">Inactive</span>
|
||||||
<span class="badge rounded-pill badge-success" *ngIf="channel.status === 1">Active</span>
|
<span class="badge rounded-pill badge-success" *ngIf="channel.status === 1" i18n="status.active">Active</span>
|
||||||
<span class="badge rounded-pill badge-danger" *ngIf="channel.status === 2">Closed</span>
|
<span class="badge rounded-pill badge-danger" *ngIf="channel.status === 2" i18n="status.closed">Closed</span>
|
||||||
|
|
||||||
<app-closing-type [type]="channel.closing_reason" *ngIf="channel.status === 2"></app-closing-type>
|
<app-closing-type [type]="channel.closing_reason" *ngIf="channel.status === 2"></app-closing-type>
|
||||||
</div>
|
</div>
|
||||||
@ -20,20 +20,20 @@
|
|||||||
<table class="table table-borderless table-striped">
|
<table class="table table-borderless table-striped">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td i18n="channel.created">Created</td>
|
<td i18n="lightning.created">Created</td>
|
||||||
<td>{{ channel.created | date:'yyyy-MM-dd HH:mm' }}</td>
|
<td>{{ channel.created | date:'yyyy-MM-dd HH:mm' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td i18n="channel.capacity">Capacity</td>
|
<td i18n="lightning.capacity">Capacity</td>
|
||||||
<td><app-amount [satoshis]="channel.capacity" [noFiat]="true"></app-amount></td>
|
<td><app-amount [satoshis]="channel.capacity" [noFiat]="true"></app-amount></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td i18n="channel.fee-rate">Fee rate</td>
|
<td i18n="transaction.fee-rate|Transaction fee rate">Fee rate</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="dual-cell">
|
<div class="dual-cell">
|
||||||
<span>{{ channel.node_left.fee_rate }} <span class="symbol">ppm</span></span>
|
<span>{{ channel.node_left.fee_rate }} <span class="symbol" i18n="lightning.ppm">ppm</span></span>
|
||||||
<fa-icon class="between-arrow" [icon]="['fas', 'arrow-right-arrow-left']" [fixedWidth]="true"></fa-icon>
|
<fa-icon class="between-arrow" [icon]="['fas', 'arrow-right-arrow-left']" [fixedWidth]="true"></fa-icon>
|
||||||
<span>{{ channel.node_right.fee_rate }} <span class="symbol">ppm</span></span>
|
<span>{{ channel.node_right.fee_rate }} <span class="symbol" i18n="lightning.ppm">ppm</span></span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -8,9 +8,9 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="badges mb-2">
|
<div class="badges mb-2">
|
||||||
<span class="badge rounded-pill badge-secondary" *ngIf="channel.status === 0">Inactive</span>
|
<span class="badge rounded-pill badge-secondary" *ngIf="channel.status === 0" i18n="status.inactive">Inactive</span>
|
||||||
<span class="badge rounded-pill badge-success" *ngIf="channel.status === 1">Active</span>
|
<span class="badge rounded-pill badge-success" *ngIf="channel.status === 1" i18n="status.active">Active</span>
|
||||||
<span class="badge rounded-pill badge-danger" *ngIf="channel.status === 2">Closed</span>
|
<span class="badge rounded-pill badge-danger" *ngIf="channel.status === 2" i18n="status.closed">Closed</span>
|
||||||
<app-closing-type *ngIf="channel.closing_reason" [type]="channel.closing_reason"></app-closing-type>
|
<app-closing-type *ngIf="channel.closing_reason" [type]="channel.closing_reason"></app-closing-type>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -45,7 +45,7 @@
|
|||||||
<table class="table table-borderless table-striped">
|
<table class="table table-borderless table-striped">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td i18n="address.total-received">Capacity</td>
|
<td i18n="lightning.capacity">Capacity</td>
|
||||||
<td><app-sats [satoshis]="channel.capacity"></app-sats><app-fiat [value]="channel.capacity" digitsInfo="1.0-0"></app-fiat></td>
|
<td><app-sats [satoshis]="channel.capacity"></app-sats><app-fiat [value]="channel.capacity" digitsInfo="1.0-0"></app-fiat></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -70,7 +70,7 @@
|
|||||||
<ng-container *ngIf="transactions$ | async as transactions">
|
<ng-container *ngIf="transactions$ | async as transactions">
|
||||||
<ng-template [ngIf]="transactions[0]">
|
<ng-template [ngIf]="transactions[0]">
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<h3>Opening transaction</h3>
|
<h3 i18n="lightning.opening-transaction">Opening transaction</h3>
|
||||||
<button type="button" class="btn btn-outline-info details-button btn-sm" (click)="txList1.toggleDetails()"
|
<button type="button" class="btn btn-outline-info details-button btn-sm" (click)="txList1.toggleDetails()"
|
||||||
i18n="transaction.details|Transaction Details">Details</button>
|
i18n="transaction.details|Transaction Details">Details</button>
|
||||||
</div>
|
</div>
|
||||||
@ -79,7 +79,7 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template [ngIf]="transactions[1]">
|
<ng-template [ngIf]="transactions[1]">
|
||||||
<div class="closing-header d-flex">
|
<div class="closing-header d-flex">
|
||||||
<h3 style="margin: 0;">Closing transaction</h3> <app-closing-type [type]="channel.closing_reason">
|
<h3 style="margin: 0;" i18n="lightning.closing-transaction">Closing transaction</h3> <app-closing-type [type]="channel.closing_reason">
|
||||||
</app-closing-type>
|
</app-closing-type>
|
||||||
<button type="button" class="btn btn-outline-info details-button btn-sm" (click)="txList2.toggleDetails()"
|
<button type="button" class="btn btn-outline-info details-button btn-sm" (click)="txList2.toggleDetails()"
|
||||||
i18n="transaction.details|Transaction Details">Details</button>
|
i18n="transaction.details|Transaction Details">Details</button>
|
||||||
|
@ -34,7 +34,7 @@ export class ChannelComponent implements OnInit {
|
|||||||
return this.lightningApiService.getChannel$(params.get('short_id'))
|
return this.lightningApiService.getChannel$(params.get('short_id'))
|
||||||
.pipe(
|
.pipe(
|
||||||
tap((value) => {
|
tap((value) => {
|
||||||
this.seoService.setTitle(`Channel: ${value.short_id}`);
|
this.seoService.setTitle($localize`Channel: ${value.short_id}`);
|
||||||
}),
|
}),
|
||||||
catchError((err) => {
|
catchError((err) => {
|
||||||
this.error = err;
|
this.error = err;
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
<form [formGroup]="channelStatusForm" class="formRadioGroup">
|
<form [formGroup]="channelStatusForm" class="formRadioGroup">
|
||||||
<div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" formControlName="status">
|
<div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" formControlName="status">
|
||||||
<label ngbButtonLabel class="btn-primary btn-sm">
|
<label ngbButtonLabel class="btn-primary btn-sm">
|
||||||
<input ngbButton type="radio" [value]="'open'" fragment="open" i18n="open">Open
|
<input ngbButton type="radio" [value]="'open'" fragment="open"><span i18n="open">Open</span>
|
||||||
</label>
|
</label>
|
||||||
<label ngbButtonLabel class="btn-primary btn-sm">
|
<label ngbButtonLabel class="btn-primary btn-sm">
|
||||||
<input ngbButton type="radio" [value]="'closed'" fragment="closed" i18n="closed">Closed
|
<input ngbButton type="radio" [value]="'closed'" fragment="closed"><span i18n="closed">Closed</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@ -32,12 +32,12 @@
|
|||||||
|
|
||||||
<ng-template #tableHeader>
|
<ng-template #tableHeader>
|
||||||
<thead>
|
<thead>
|
||||||
<th class="alias text-left" i18n="nodes.alias">Node Alias</th>
|
<th class="alias text-left" i18n="lightning.alias">Alias</th>
|
||||||
<th class="alias text-left d-none d-md-table-cell" i18n="channels.transaction"> </th>
|
<th class="alias text-left d-none d-md-table-cell"> </th>
|
||||||
<th class="alias text-left d-none d-md-table-cell" i18n="status">Status</th>
|
<th class="alias text-left d-none d-md-table-cell" i18n="status">Status</th>
|
||||||
<th *ngIf="status !== 'closed'" class="channels text-left d-none d-md-table-cell" i18n="channels.rate">Fee Rate</th>
|
<th *ngIf="status !== 'closed'" class="channels text-left d-none d-md-table-cell" i18n="transaction.fee-rate|Transaction fee rate">Fee rate</th>
|
||||||
<th *ngIf="status === 'closed'" class="channels text-left d-none d-md-table-cell" i18n="channels.closing_date">Closing date</th>
|
<th *ngIf="status === 'closed'" class="channels text-left d-none d-md-table-cell" i18n="channels.closing_date">Closing date</th>
|
||||||
<th class="capacity text-right d-none d-md-table-cell" i18n="nodes.capacity">Capacity</th>
|
<th class="capacity text-right d-none d-md-table-cell" i18n="lightning.capacity">Capacity</th>
|
||||||
<th class="capacity text-right" i18n="channels.id">Channel ID</th>
|
<th class="capacity text-right" i18n="channels.id">Channel ID</th>
|
||||||
</thead>
|
</thead>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
@ -53,7 +53,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="alias text-left d-none d-md-table-cell">
|
<td class="alias text-left d-none d-md-table-cell">
|
||||||
<div class="second-line">{{ node.channels }} channels</div>
|
<div class="second-line"><ng-container *ngTemplateOutlet="xChannels; context: {$implicit: node.channels }"></ng-container></div>
|
||||||
<div class="second-line">
|
<div class="second-line">
|
||||||
<app-amount *ngIf="node.capacity > 100000000; else smallnode" [satoshis]="node.capacity" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount>
|
<app-amount *ngIf="node.capacity > 100000000; else smallnode" [satoshis]="node.capacity" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount>
|
||||||
<ng-template #smallnode>
|
<ng-template #smallnode>
|
||||||
@ -63,10 +63,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="d-none d-md-table-cell">
|
<td class="d-none d-md-table-cell">
|
||||||
<span class="badge rounded-pill badge-secondary" *ngIf="channel.status === 0" i18n="lightning.inactive">Inactive</span>
|
<span class="badge rounded-pill badge-secondary" *ngIf="channel.status === 0" i18n="status.inactive">Inactive</span>
|
||||||
<span class="badge rounded-pill badge-success" *ngIf="channel.status === 1" i18n="lightning.active">Active</span>
|
<span class="badge rounded-pill badge-success" *ngIf="channel.status === 1" i18n="status.active">Active</span>
|
||||||
<ng-template [ngIf]="channel.status === 2">
|
<ng-template [ngIf]="channel.status === 2">
|
||||||
<span class="badge rounded-pill badge-secondary" *ngIf="!channel.closing_reason; else closingReason" i18n="lightning.closed">Closed</span>
|
<span class="badge rounded-pill badge-secondary" *ngIf="!channel.closing_reason; else closingReason" i18n="status.closed">Closed</span>
|
||||||
<ng-template #closingReason>
|
<ng-template #closingReason>
|
||||||
<app-closing-type [type]="channel.closing_reason"></app-closing-type>
|
<app-closing-type [type]="channel.closing_reason"></app-closing-type>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
@ -117,3 +117,5 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template #xChannels let-i i18n="lightning.x-channels">{{ i }} channels</ng-template>
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
<div class="card-text">
|
<div class="card-text">
|
||||||
<div class="fee-text" [class]="!statistics.previous ? 'no-border' : ''">
|
<div class="fee-text" [class]="!statistics.previous ? 'no-border' : ''">
|
||||||
{{ statistics.latest?.avg_capacity || 0 | number: '1.0-0' }}
|
{{ statistics.latest?.avg_capacity || 0 | number: '1.0-0' }}
|
||||||
<span i18n="shared.sat-vbyte|sat/vB">sats</span>
|
<span i18n="shared.sats">sats</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="fiat" *ngIf="statistics.previous">
|
<span class="fiat" *ngIf="statistics.previous">
|
||||||
<app-change [current]="statistics.latest?.avg_capacity" [previous]="statistics.previous?.avg_capacity"></app-change>
|
<app-change [current]="statistics.latest?.avg_capacity" [previous]="statistics.previous?.avg_capacity"></app-change>
|
||||||
@ -29,7 +29,7 @@
|
|||||||
placement="bottom">
|
placement="bottom">
|
||||||
<div class="fee-text" [class]="!statistics.previous ? 'no-border' : ''">
|
<div class="fee-text" [class]="!statistics.previous ? 'no-border' : ''">
|
||||||
{{ statistics.latest?.avg_fee_rate || 0 | number: '1.0-0' }}
|
{{ statistics.latest?.avg_fee_rate || 0 | number: '1.0-0' }}
|
||||||
<span i18n="shared.sat-vbyte|sat/vB">ppm</span>
|
<span i18n="lightning.ppm">ppm</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="fiat" *ngIf="statistics.previous">
|
<span class="fiat" *ngIf="statistics.previous">
|
||||||
<app-change [current]="statistics.latest?.avg_fee_rate" [previous]="statistics.previous?.avg_fee_rate"></app-change>
|
<app-change [current]="statistics.latest?.avg_fee_rate" [previous]="statistics.previous?.avg_fee_rate"></app-change>
|
||||||
@ -44,7 +44,7 @@
|
|||||||
<div class="card-text">
|
<div class="card-text">
|
||||||
<div class="fee-text" [class]="!statistics.previous ? 'no-border' : ''">
|
<div class="fee-text" [class]="!statistics.previous ? 'no-border' : ''">
|
||||||
{{ statistics.latest?.avg_base_fee_mtokens || 0 | number: '1.0-0' }}
|
{{ statistics.latest?.avg_base_fee_mtokens || 0 | number: '1.0-0' }}
|
||||||
<span i18n="shared.sat-vbyte|sat/vB">msats</span>
|
<span i18n="shared.m-sats">mSats</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="fiat" *ngIf="statistics.previous">
|
<span class="fiat" *ngIf="statistics.previous">
|
||||||
<app-change [current]="statistics.latest?.avg_base_fee_mtokens" [previous]="statistics.previous?.avg_base_fee_mtokens"></app-change>
|
<app-change [current]="statistics.latest?.avg_base_fee_mtokens" [previous]="statistics.previous?.avg_base_fee_mtokens"></app-change>
|
||||||
@ -60,7 +60,7 @@
|
|||||||
<div class="card-text">
|
<div class="card-text">
|
||||||
<div class="fee-text" [class]="!statistics.previous ? 'no-border' : ''">
|
<div class="fee-text" [class]="!statistics.previous ? 'no-border' : ''">
|
||||||
{{ statistics.latest?.med_capacity || 0 | number: '1.0-0' }}
|
{{ statistics.latest?.med_capacity || 0 | number: '1.0-0' }}
|
||||||
<span i18n="shared.sat-vbyte|sat/vB">sats</span>
|
<span i18n="shared.sats">sats</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="fiat" *ngIf="statistics.previous">
|
<span class="fiat" *ngIf="statistics.previous">
|
||||||
<app-change [current]="statistics.latest?.med_capacity" [previous]="statistics.previous?.med_capacity"></app-change>
|
<app-change [current]="statistics.latest?.med_capacity" [previous]="statistics.previous?.med_capacity"></app-change>
|
||||||
@ -75,7 +75,7 @@
|
|||||||
placement="bottom">
|
placement="bottom">
|
||||||
<div class="fee-text" [class]="!statistics.previous ? 'no-border' : ''">
|
<div class="fee-text" [class]="!statistics.previous ? 'no-border' : ''">
|
||||||
{{ statistics.latest?.med_fee_rate || 0 | number: '1.0-0' }}
|
{{ statistics.latest?.med_fee_rate || 0 | number: '1.0-0' }}
|
||||||
<span i18n="shared.sat-vbyte|sat/vB">ppm</span>
|
<span i18n="lightning.ppm">ppm</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="fiat" *ngIf="statistics.previous">
|
<span class="fiat" *ngIf="statistics.previous">
|
||||||
<app-change [current]="statistics.latest?.med_fee_rate" [previous]="statistics.previous?.med_fee_rate"></app-change>
|
<app-change [current]="statistics.latest?.med_fee_rate" [previous]="statistics.previous?.med_fee_rate"></app-change>
|
||||||
@ -90,7 +90,7 @@
|
|||||||
<div class="card-text">
|
<div class="card-text">
|
||||||
<div class="fee-text" [class]="!statistics.previous ? 'no-border' : ''">
|
<div class="fee-text" [class]="!statistics.previous ? 'no-border' : ''">
|
||||||
{{ statistics.latest?.med_base_fee_mtokens || 0 | number: '1.0-0' }}
|
{{ statistics.latest?.med_base_fee_mtokens || 0 | number: '1.0-0' }}
|
||||||
<span i18n="shared.sat-vbyte|sat/vB">msats</span>
|
<span i18n="shared.m-sats">mSats</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span class="fiat" *ngIf="statistics.previous">
|
<span class="fiat" *ngIf="statistics.previous">
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<div class="box preview-box" *ngIf="nodes$ | async as nodes">
|
<div class="box preview-box" *ngIf="nodes$ | async as nodes">
|
||||||
<app-preview-title>
|
<app-preview-title>
|
||||||
<span i18n="lightning.node">Lightning node group</span>
|
<span i18n="lightning.node-group">Lightning node group</span>
|
||||||
</app-preview-title>
|
</app-preview-title>
|
||||||
<div class="row d-flex justify-content-between full-width-row">
|
<div class="row d-flex justify-content-between full-width-row">
|
||||||
<div class="logo-wrapper">
|
<div class="logo-wrapper">
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<div class="container-xl full-height" style="min-height: 335px">
|
<div class="container-xl full-height" style="min-height: 335px">
|
||||||
<h5 class="mb-1" style="color: #ffffff66" i18n="lightning.node">Lightning node group</h5>
|
<h5 class="mb-1" style="color: #ffffff66" i18n="lightning.node-group">Lightning node group</h5>
|
||||||
|
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="logo-container">
|
<div class="logo-container">
|
||||||
|
@ -53,6 +53,10 @@ export class LightningApiService {
|
|||||||
return this.httpClient.get<any>(this.apiBasePath + '/api/v1/lightning/nodes/' + publicKey + '/statistics');
|
return this.httpClient.get<any>(this.apiBasePath + '/api/v1/lightning/nodes/' + publicKey + '/statistics');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getNodeFeeHistogram$(publicKey: string): Observable<any> {
|
||||||
|
return this.httpClient.get<any>(this.apiBasePath + '/api/v1/lightning/nodes/' + publicKey + '/fees/histogram');
|
||||||
|
}
|
||||||
|
|
||||||
getNodesRanking$(): Observable<INodesRanking> {
|
getNodesRanking$(): Observable<INodesRanking> {
|
||||||
return this.httpClient.get<INodesRanking>(this.apiBasePath + '/api/v1/lightning/nodes/rankings');
|
return this.httpClient.get<INodesRanking>(this.apiBasePath + '/api/v1/lightning/nodes/rankings');
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<!-- Network capacity/channels/nodes -->
|
<!-- Network capacity/channels/nodes -->
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="main-title">
|
<div class="main-title">
|
||||||
<span i18n="lightning.statistics-title">Network Statistics</span>
|
<span i18n="lightning.network-statistics-title">Network Statistics</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-wrapper">
|
<div class="card-wrapper">
|
||||||
<div class="card" style="height: 123px">
|
<div class="card" style="height: 123px">
|
||||||
@ -21,7 +21,7 @@
|
|||||||
<!-- Channels stats -->
|
<!-- Channels stats -->
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="main-title">
|
<div class="main-title">
|
||||||
<span i18n="lightning.statistics-title">Channels Statistics</span>
|
<span i18n="lightning.channel-statistics-title">Channels Statistics</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-wrapper">
|
<div class="card-wrapper">
|
||||||
<div class="card" style="height: 123px">
|
<div class="card" style="height: 123px">
|
||||||
@ -46,7 +46,7 @@
|
|||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="card graph-card">
|
<div class="card graph-card">
|
||||||
<div class="card-body pl-2 pr-2 pt-1">
|
<div class="card-body pl-2 pr-2 pt-1">
|
||||||
<h5 class="card-title mt-3" i18n="lightning.network-history">Lightning network history</h5>
|
<h5 class="card-title mt-3" i18n="lightning.network-history">Lightning Network History</h5>
|
||||||
<app-lightning-statistics-chart [widget]=true></app-lightning-statistics-chart>
|
<app-lightning-statistics-chart [widget]=true></app-lightning-statistics-chart>
|
||||||
<app-nodes-networks-chart [widget]=true></app-nodes-networks-chart>
|
<app-nodes-networks-chart [widget]=true></app-nodes-networks-chart>
|
||||||
<div><a [routerLink]="['/graphs/lightning/nodes-networks' | relativeUrl]" i18n="dashboard.view-more">View more »</a></div>
|
<div><a [routerLink]="['/graphs/lightning/nodes-networks' | relativeUrl]" i18n="dashboard.view-more">View more »</a></div>
|
||||||
@ -59,7 +59,7 @@
|
|||||||
<div class="card" style="height: 409px">
|
<div class="card" style="height: 409px">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<a class="title-link" href="" [routerLink]="['/lightning/nodes/rankings/liquidity' | relativeUrl]">
|
<a class="title-link" href="" [routerLink]="['/lightning/nodes/rankings/liquidity' | relativeUrl]">
|
||||||
<h5 class="card-title d-inline" i18n="lightning.liquidity-ranking">Liquidity ranking</h5>
|
<h5 class="card-title d-inline" i18n="lightning.liquidity-ranking">Liquidity Ranking</h5>
|
||||||
<span> </span>
|
<span> </span>
|
||||||
<fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: 'text-top'; font-size: 13px; color: '#4a68b9'"></fa-icon>
|
<fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: 'text-top'; font-size: 13px; color: '#4a68b9'"></fa-icon>
|
||||||
</a>
|
</a>
|
||||||
@ -73,7 +73,7 @@
|
|||||||
<div class="card" style="height: 409px">
|
<div class="card" style="height: 409px">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<a class="title-link" href="" [routerLink]="['/lightning/nodes/rankings/connectivity' | relativeUrl]">
|
<a class="title-link" href="" [routerLink]="['/lightning/nodes/rankings/connectivity' | relativeUrl]">
|
||||||
<h5 class="card-title d-inline" i18n="lightning.connectivity-ranking">Connectivity ranking</h5>
|
<h5 class="card-title d-inline" i18n="lightning.connectivity-ranking">Connectivity Ranking</h5>
|
||||||
<span> </span>
|
<span> </span>
|
||||||
<fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: 'text-top'; font-size: 13px; color: '#4a68b9'"></fa-icon>
|
<fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: 'text-top'; font-size: 13px; color: '#4a68b9'"></fa-icon>
|
||||||
</a>
|
</a>
|
||||||
|
@ -24,7 +24,7 @@ export class LightningDashboardComponent implements OnInit {
|
|||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.seoService.setTitle($localize`Lightning Network`);
|
this.seoService.setTitle($localize`:@@142e923d3b04186ac6ba23387265d22a2fa404e0:Lightning Explorer`);
|
||||||
|
|
||||||
this.nodesRanking$ = this.lightningApiService.getNodesRanking$().pipe(share());
|
this.nodesRanking$ = this.lightningApiService.getNodesRanking$().pipe(share());
|
||||||
this.statistics$ = this.lightningApiService.getLatestStatistics$().pipe(share());
|
this.statistics$ = this.lightningApiService.getLatestStatistics$().pipe(share());
|
||||||
|
@ -15,6 +15,7 @@ import { ChannelBoxComponent } from './channel/channel-box/channel-box.component
|
|||||||
import { ClosingTypeComponent } from './channel/closing-type/closing-type.component';
|
import { ClosingTypeComponent } from './channel/closing-type/closing-type.component';
|
||||||
import { LightningStatisticsChartComponent } from './statistics-chart/lightning-statistics-chart.component';
|
import { LightningStatisticsChartComponent } from './statistics-chart/lightning-statistics-chart.component';
|
||||||
import { NodeStatisticsChartComponent } from './node-statistics-chart/node-statistics-chart.component';
|
import { NodeStatisticsChartComponent } from './node-statistics-chart/node-statistics-chart.component';
|
||||||
|
import { NodeFeeChartComponent } from './node-fee-chart/node-fee-chart.component';
|
||||||
import { GraphsModule } from '../graphs/graphs.module';
|
import { GraphsModule } from '../graphs/graphs.module';
|
||||||
import { NodesNetworksChartComponent } from './nodes-networks-chart/nodes-networks-chart.component';
|
import { NodesNetworksChartComponent } from './nodes-networks-chart/nodes-networks-chart.component';
|
||||||
import { ChannelsStatisticsComponent } from './channels-statistics/channels-statistics.component';
|
import { ChannelsStatisticsComponent } from './channels-statistics/channels-statistics.component';
|
||||||
@ -38,6 +39,7 @@ import { GroupComponent } from './group/group.component';
|
|||||||
NodesListComponent,
|
NodesListComponent,
|
||||||
NodeStatisticsComponent,
|
NodeStatisticsComponent,
|
||||||
NodeStatisticsChartComponent,
|
NodeStatisticsChartComponent,
|
||||||
|
NodeFeeChartComponent,
|
||||||
NodeComponent,
|
NodeComponent,
|
||||||
ChannelsListComponent,
|
ChannelsListComponent,
|
||||||
ChannelComponent,
|
ChannelComponent,
|
||||||
@ -73,6 +75,7 @@ import { GroupComponent } from './group/group.component';
|
|||||||
NodesListComponent,
|
NodesListComponent,
|
||||||
NodeStatisticsComponent,
|
NodeStatisticsComponent,
|
||||||
NodeStatisticsChartComponent,
|
NodeStatisticsChartComponent,
|
||||||
|
NodeFeeChartComponent,
|
||||||
NodeComponent,
|
NodeComponent,
|
||||||
ChannelsListComponent,
|
ChannelsListComponent,
|
||||||
ChannelComponent,
|
ChannelComponent,
|
||||||
|
@ -21,10 +21,12 @@ const routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'node/:public_key',
|
path: 'node/:public_key',
|
||||||
|
data: { networkSpecific: true },
|
||||||
component: NodeComponent,
|
component: NodeComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'channel/:short_id',
|
path: 'channel/:short_id',
|
||||||
|
data: { networkSpecific: true },
|
||||||
component: ChannelComponent,
|
component: ChannelComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
<div class="full-container">
|
||||||
|
<h2 i18n="lightning.node-fee-distribution">Fee distribution</h2>
|
||||||
|
<div class="chart" echarts [initOpts]="chartInitOptions" [options]="chartOptions" (chartInit)="onChartInit($event)"></div>
|
||||||
|
<div class="text-center loadingGraphs" *ngIf="isLoading">
|
||||||
|
<div class="spinner-border text-light"></div>d
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,5 @@
|
|||||||
|
.full-container {
|
||||||
|
margin-top: 25px;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
@ -0,0 +1,265 @@
|
|||||||
|
import { Component, Inject, Input, LOCALE_ID, OnInit, HostBinding } from '@angular/core';
|
||||||
|
import { EChartsOption } from 'echarts';
|
||||||
|
import { switchMap } from 'rxjs/operators';
|
||||||
|
import { download } from '../../shared/graphs.utils';
|
||||||
|
import { LightningApiService } from '../lightning-api.service';
|
||||||
|
import { ActivatedRoute, ParamMap } from '@angular/router';
|
||||||
|
import { AmountShortenerPipe } from '../../shared/pipes/amount-shortener.pipe';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-node-fee-chart',
|
||||||
|
templateUrl: './node-fee-chart.component.html',
|
||||||
|
styleUrls: ['./node-fee-chart.component.scss'],
|
||||||
|
styles: [`
|
||||||
|
.loadingGraphs {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: calc(50% - 15px);
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
`],
|
||||||
|
})
|
||||||
|
export class NodeFeeChartComponent implements OnInit {
|
||||||
|
chartOptions: EChartsOption = {};
|
||||||
|
chartInitOptions = {
|
||||||
|
renderer: 'svg',
|
||||||
|
};
|
||||||
|
|
||||||
|
@HostBinding('attr.dir') dir = 'ltr';
|
||||||
|
|
||||||
|
isLoading = true;
|
||||||
|
chartInstance: any = undefined;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject(LOCALE_ID) public locale: string,
|
||||||
|
private lightningApiService: LightningApiService,
|
||||||
|
private activatedRoute: ActivatedRoute,
|
||||||
|
private amountShortenerPipe: AmountShortenerPipe,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
|
||||||
|
this.activatedRoute.paramMap
|
||||||
|
.pipe(
|
||||||
|
switchMap((params: ParamMap) => {
|
||||||
|
this.isLoading = true;
|
||||||
|
return this.lightningApiService.getNodeFeeHistogram$(params.get('public_key'));
|
||||||
|
}),
|
||||||
|
).subscribe((data) => {
|
||||||
|
if (data && data.incoming && data.outgoing) {
|
||||||
|
const outgoingHistogram = this.bucketsToHistogram(data.outgoing);
|
||||||
|
const incomingHistogram = this.bucketsToHistogram(data.incoming);
|
||||||
|
this.prepareChartOptions(outgoingHistogram, incomingHistogram);
|
||||||
|
}
|
||||||
|
this.isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bucketsToHistogram(buckets): { label: string, count: number, capacity: number}[] {
|
||||||
|
const histogram = [];
|
||||||
|
let increment = 1;
|
||||||
|
let lower = -increment;
|
||||||
|
let upper = 0;
|
||||||
|
|
||||||
|
let nullBucket;
|
||||||
|
if (buckets.length && buckets[0] && buckets[0].bucket == null) {
|
||||||
|
nullBucket = buckets.shift();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (upper <= 5000) {
|
||||||
|
let bucket;
|
||||||
|
if (buckets.length && buckets[0] && upper >= Number(buckets[0].bucket)) {
|
||||||
|
bucket = buckets.shift();
|
||||||
|
}
|
||||||
|
histogram.push({
|
||||||
|
label: upper === 0 ? '0 ppm' : `${lower} - ${upper} ppm`,
|
||||||
|
count: Number(bucket?.count || 0) + (upper === 0 ? Number(nullBucket?.count || 0) : 0),
|
||||||
|
capacity: Number(bucket?.capacity || 0) + (upper === 0 ? Number(nullBucket?.capacity || 0) : 0),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (upper >= increment * 10) {
|
||||||
|
increment *= 10;
|
||||||
|
lower = increment;
|
||||||
|
upper = increment + increment;
|
||||||
|
} else {
|
||||||
|
lower += increment;
|
||||||
|
upper += increment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const rest = buckets.reduce((acc, bucket) => {
|
||||||
|
acc.count += Number(bucket.count);
|
||||||
|
acc.capacity += Number(bucket.capacity);
|
||||||
|
return acc;
|
||||||
|
}, { count: 0, capacity: 0 });
|
||||||
|
histogram.push({
|
||||||
|
label: `5000+ ppm`,
|
||||||
|
count: rest.count,
|
||||||
|
capacity: rest.capacity,
|
||||||
|
});
|
||||||
|
return histogram;
|
||||||
|
}
|
||||||
|
|
||||||
|
prepareChartOptions(outgoingData, incomingData): void {
|
||||||
|
let title: object;
|
||||||
|
if (outgoingData.length === 0) {
|
||||||
|
title = {
|
||||||
|
textStyle: {
|
||||||
|
color: 'grey',
|
||||||
|
fontSize: 15
|
||||||
|
},
|
||||||
|
text: $localize`No data to display yet. Try again later.`,
|
||||||
|
left: 'center',
|
||||||
|
top: 'center'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
this.chartOptions = {
|
||||||
|
title: outgoingData.length === 0 ? title : undefined,
|
||||||
|
animation: false,
|
||||||
|
grid: {
|
||||||
|
top: 30,
|
||||||
|
bottom: 20,
|
||||||
|
right: 20,
|
||||||
|
left: 65,
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
show: !this.isMobile(),
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'line'
|
||||||
|
},
|
||||||
|
backgroundColor: 'rgba(17, 19, 31, 1)',
|
||||||
|
borderRadius: 4,
|
||||||
|
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
||||||
|
textStyle: {
|
||||||
|
color: '#b1b1b1',
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
borderColor: '#000',
|
||||||
|
formatter: (ticks): string => {
|
||||||
|
return `
|
||||||
|
<b style="color: white; margin-left: 2px">${ticks[0].data.label}</b><br>
|
||||||
|
<br>
|
||||||
|
<b style="color: white; margin-left: 2px">${ticks[0].marker} Outgoing</b><br>
|
||||||
|
<span>Capacity: ${this.amountShortenerPipe.transform(ticks[0].data.capacity, 2, undefined, true)} sats</span><br>
|
||||||
|
<span>Channels: ${ticks[0].data.count}</span><br>
|
||||||
|
<br>
|
||||||
|
<b style="color: white; margin-left: 2px">${ticks[1].marker} Incoming</b><br>
|
||||||
|
<span>Capacity: ${this.amountShortenerPipe.transform(ticks[1].data.capacity, 2, undefined, true)} sats</span><br>
|
||||||
|
<span>Channels: ${ticks[1].data.count}</span><br>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xAxis: outgoingData.length === 0 ? undefined : {
|
||||||
|
type: 'category',
|
||||||
|
axisLine: { onZero: true },
|
||||||
|
axisLabel: {
|
||||||
|
align: 'center',
|
||||||
|
fontSize: 11,
|
||||||
|
lineHeight: 12,
|
||||||
|
hideOverlap: true,
|
||||||
|
padding: [0, 5],
|
||||||
|
},
|
||||||
|
data: outgoingData.map(bucket => bucket.label)
|
||||||
|
},
|
||||||
|
legend: outgoingData.length === 0 ? undefined : {
|
||||||
|
padding: 10,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
name: 'Outgoing Fees',
|
||||||
|
inactiveColor: 'rgb(110, 112, 121)',
|
||||||
|
textStyle: {
|
||||||
|
color: 'white',
|
||||||
|
},
|
||||||
|
icon: 'roundRect',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Incoming Fees',
|
||||||
|
inactiveColor: 'rgb(110, 112, 121)',
|
||||||
|
textStyle: {
|
||||||
|
color: 'white',
|
||||||
|
},
|
||||||
|
icon: 'roundRect',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
yAxis: outgoingData.length === 0 ? undefined : [
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
axisLabel: {
|
||||||
|
color: 'rgb(110, 112, 121)',
|
||||||
|
formatter: (val) => {
|
||||||
|
return `${this.amountShortenerPipe.transform(Math.abs(val), 2, undefined, true)} sats`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
lineStyle: {
|
||||||
|
type: 'dotted',
|
||||||
|
color: '#ffffff66',
|
||||||
|
opacity: 0.25,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
series: outgoingData.length === 0 ? undefined : [
|
||||||
|
{
|
||||||
|
zlevel: 0,
|
||||||
|
name: 'Outgoing Fees',
|
||||||
|
data: outgoingData.map(bucket => ({
|
||||||
|
value: bucket.capacity,
|
||||||
|
label: bucket.label,
|
||||||
|
capacity: bucket.capacity,
|
||||||
|
count: bucket.count,
|
||||||
|
})),
|
||||||
|
type: 'bar',
|
||||||
|
barWidth: '90%',
|
||||||
|
barMaxWidth: 50,
|
||||||
|
stack: 'fees',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
zlevel: 0,
|
||||||
|
name: 'Incoming Fees',
|
||||||
|
data: incomingData.map(bucket => ({
|
||||||
|
value: -bucket.capacity,
|
||||||
|
label: bucket.label,
|
||||||
|
capacity: bucket.capacity,
|
||||||
|
count: bucket.count,
|
||||||
|
})),
|
||||||
|
type: 'bar',
|
||||||
|
barWidth: '90%',
|
||||||
|
barMaxWidth: 50,
|
||||||
|
stack: 'fees',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onChartInit(ec) {
|
||||||
|
if (this.chartInstance !== undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.chartInstance = ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
isMobile() {
|
||||||
|
return (window.innerWidth <= 767.98);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveChart() {
|
||||||
|
// @ts-ignore
|
||||||
|
const prevBottom = this.chartOptions.grid.bottom;
|
||||||
|
// @ts-ignore
|
||||||
|
this.chartOptions.grid.bottom = 40;
|
||||||
|
this.chartOptions.backgroundColor = '#11131f';
|
||||||
|
this.chartInstance.setOption(this.chartOptions);
|
||||||
|
download(this.chartInstance.getDataURL({
|
||||||
|
pixelRatio: 2,
|
||||||
|
}), `node-fee-chart.svg`);
|
||||||
|
// @ts-ignore
|
||||||
|
this.chartOptions.grid.bottom = prevBottom;
|
||||||
|
this.chartOptions.backgroundColor = 'none';
|
||||||
|
this.chartInstance.setOption(this.chartOptions);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
<div class="box preview-box" *ngIf="(node$ | async) as node">
|
<div class="box preview-box" *ngIf="(node$ | async) as node">
|
||||||
<app-preview-title>
|
<app-preview-title>
|
||||||
<span i18n="lightning.node">lightning node</span>
|
<span i18n="lightning.node">Lightning node</span>
|
||||||
</app-preview-title>
|
</app-preview-title>
|
||||||
<div class="row d-flex justify-content-between full-width-row">
|
<div class="row d-flex justify-content-between full-width-row">
|
||||||
<h1 class="title"></h1>
|
<h1 class="title"></h1>
|
||||||
@ -29,13 +29,13 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td i18n="lightning.active-channels-avg">Average size</td>
|
<td i18n="lightning.avg-size">Average size</td>
|
||||||
<td>
|
<td>
|
||||||
<app-amount [satoshis]="node.avgCapacity" [noFiat]="true"></app-amount>
|
<app-amount [satoshis]="node.avgCapacity" [noFiat]="true"></app-amount>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr *ngIf="node.city">
|
<tr *ngIf="node.city">
|
||||||
<td i18n="location">Location</td>
|
<td i18n="lightning.location">Location</td>
|
||||||
<td>
|
<td>
|
||||||
<span>{{ node.city.en }}</span>
|
<span>{{ node.city.en }}</span>
|
||||||
</td>
|
</td>
|
||||||
@ -47,7 +47,7 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr *ngIf="!node.city && !node.country">
|
<tr *ngIf="!node.city && !node.country">
|
||||||
<td i18n="location">Location</td>
|
<td i18n="lightning.location">Location</td>
|
||||||
<td>
|
<td>
|
||||||
<span>unknown</span>
|
<span>unknown</span>
|
||||||
</td>
|
</td>
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
|
|
||||||
<div *ngIf="error" class="d-flex flex-column justify-content-around align-items-center mt-5 w-100" style="min-height: 100px">
|
<div *ngIf="error" class="d-flex flex-column justify-content-around align-items-center mt-5 w-100" style="min-height: 100px">
|
||||||
<span i18n="lightning.node-not-found">No node found for public key "{{ node.public_key | shortenString : 12}}"</span>
|
<span i18n="lightning.node-not-found">No node found for public key "{{ node.public_key | shortenString : 12}}"</span>
|
||||||
<a [routerLink]="['/lightning' | relativeUrl]" i18n="lightning.back-to-lightning-dashboard">Back to the lightning dashboard</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="box" *ngIf="!error">
|
<div class="box" *ngIf="!error">
|
||||||
@ -45,7 +44,7 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td i18n="location" class="text-truncate">Location</td>
|
<td i18n="lightning.location" class="text-truncate">Location</td>
|
||||||
<td *ngIf="node.geolocation">
|
<td *ngIf="node.geolocation">
|
||||||
<app-geolocation [data]="node.geolocation" [type]="'node'"></app-geolocation>
|
<app-geolocation [data]="node.geolocation" [type]="'node'"></app-geolocation>
|
||||||
</td>
|
</td>
|
||||||
@ -61,19 +60,19 @@
|
|||||||
<table class="table table-borderless table-striped table-fixed">
|
<table class="table table-borderless table-striped table-fixed">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td i18n="address.total-received" class="text-truncate label">First seen</td>
|
<td i18n="transaction.first-seen|Transaction first seen" class="text-truncate label">First seen</td>
|
||||||
<td>
|
<td>
|
||||||
<app-timestamp [unixTime]="node.first_seen"></app-timestamp>
|
<app-timestamp [unixTime]="node.first_seen"></app-timestamp>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td i18n="address.total-sent" class="text-truncate label">Last update</td>
|
<td class="text-truncate label" i18n="lightning.last_update">Last update</td>
|
||||||
<td>
|
<td>
|
||||||
<app-timestamp [unixTime]="node.updated_at"></app-timestamp>
|
<app-timestamp [unixTime]="node.updated_at"></app-timestamp>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td i18n="address.balance" class="text-truncate label">Color</td>
|
<td i18n="lightning.color" class="text-truncate label">Color</td>
|
||||||
<td>
|
<td>
|
||||||
<div [ngStyle]="{'color': node.color}">{{ node.color }}</div>
|
<div [ngStyle]="{'color': node.color}">{{ node.color }}</div>
|
||||||
</td>
|
</td>
|
||||||
@ -141,6 +140,8 @@
|
|||||||
|
|
||||||
<app-node-channels style="display:block;margin-bottom: 40px" [publicKey]="node.public_key"></app-node-channels>
|
<app-node-channels style="display:block;margin-bottom: 40px" [publicKey]="node.public_key"></app-node-channels>
|
||||||
|
|
||||||
|
<app-node-fee-chart style="display:block;margin-bottom: 40px"></app-node-fee-chart>
|
||||||
|
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<h2 *ngIf="channelsListStatus === 'open'">
|
<h2 *ngIf="channelsListStatus === 'open'">
|
||||||
<span i18n="lightning.open-channels">Open channels</span>
|
<span i18n="lightning.open-channels">Open channels</span>
|
||||||
|
@ -39,7 +39,7 @@ export class NodeComponent implements OnInit {
|
|||||||
return this.lightningApiService.getNode$(params.get('public_key'));
|
return this.lightningApiService.getNode$(params.get('public_key'));
|
||||||
}),
|
}),
|
||||||
map((node) => {
|
map((node) => {
|
||||||
this.seoService.setTitle(`Node: ${node.alias}`);
|
this.seoService.setTitle($localize`Node: ${node.alias}`);
|
||||||
|
|
||||||
const socketsObject = [];
|
const socketsObject = [];
|
||||||
for (const socket of node.sockets.split(',')) {
|
for (const socket of node.sockets.split(',')) {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<div *ngIf="chartOptions" [class]="'full-container ' + style + (fitContainer ? ' fit-container' : '')">
|
<div *ngIf="chartOptions" [class]="'full-container ' + style + (fitContainer ? ' fit-container' : '')">
|
||||||
<div *ngIf="style === 'graph'" class="card-header">
|
<div *ngIf="style === 'graph'" class="card-header">
|
||||||
<div class="d-flex d-md-block align-items-baseline" style="margin-bottom: -5px">
|
<div class="d-flex d-md-block align-items-baseline" style="margin-bottom: -5px">
|
||||||
<span i18n="lightning.nodes-channels-world-map">Lightning nodes channels world map</span>
|
<span i18n="lightning.nodes-channels-world-map">Lightning Nodes Channels World Map</span>
|
||||||
</div>
|
</div>
|
||||||
<small style="color: #ffffff66" i18n="lightning.tor-nodes-excluded">(Tor nodes excluded)</small>
|
<small style="color: #ffffff66" i18n="lightning.tor-nodes-excluded">(Tor nodes excluded)</small>
|
||||||
</div>
|
</div>
|
||||||
|
@ -66,7 +66,7 @@ export class NodesChannelsMap implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.style === 'graph') {
|
if (this.style === 'graph') {
|
||||||
this.seoService.setTitle($localize`Lightning nodes channels world map`);
|
this.seoService.setTitle($localize`Lightning Nodes Channels World Map`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (['nodepage', 'channelpage'].includes(this.style)) {
|
if (['nodepage', 'channelpage'].includes(this.style)) {
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
<table class="table table-borderless">
|
<table class="table table-borderless">
|
||||||
<thead>
|
<thead>
|
||||||
<th class="alias text-left" i18n="nodes.alias">Alias</th>
|
<th class="alias text-left" i18n="nodes.alias">Alias</th>
|
||||||
<th class="capacity text-right" [class]="show" i18n="node.capacity">Capacity</th>
|
<th class="capacity text-right" [class]="show" i18n="lightning.capacity">Capacity</th>
|
||||||
<th class="channels text-right" [class]="show" i18n="node.channels">Channels</th>
|
<th class="channels text-right" [class]="show" i18n="lightning.channels">Channels</th>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody *ngIf="nodes$ | async as nodes; else skeleton">
|
<tbody *ngIf="nodes$ | async as nodes; else skeleton">
|
||||||
<tr *ngFor="let node of nodes; let i = index;">
|
<tr *ngFor="let node of nodes; let i = index;">
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<div *ngIf="!widget" class="card-header">
|
<div *ngIf="!widget" class="card-header">
|
||||||
<div class="d-flex d-md-block align-items-baseline" style="margin-bottom: -5px">
|
<div class="d-flex d-md-block align-items-baseline" style="margin-bottom: -5px">
|
||||||
<span i18n="lightning.nodes-world-map">Lightning nodes world map</span>
|
<span i18n="lightning.nodes-world-map">Lightning Nodes World Map</span>
|
||||||
</div>
|
</div>
|
||||||
<small style="color: #ffffff66" i18n="lightning.tor-nodes-excluded">(Tor nodes excluded)</small>
|
<small style="color: #ffffff66" i18n="lightning.tor-nodes-excluded">(Tor nodes excluded)</small>
|
||||||
</div>
|
</div>
|
||||||
|
@ -47,7 +47,7 @@ export class NodesMap implements OnInit, OnChanges {
|
|||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
if (!this.widget) {
|
if (!this.widget) {
|
||||||
this.seoService.setTitle($localize`Lightning nodes world map`);
|
this.seoService.setTitle($localize`:@@af8560ca50882114be16c951650f83bca73161a7:Lightning Nodes World Map`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.inputNodes$) {
|
if (!this.inputNodes$) {
|
||||||
@ -141,7 +141,7 @@ export class NodesMap implements OnInit, OnChanges {
|
|||||||
color: 'grey',
|
color: 'grey',
|
||||||
fontSize: 15
|
fontSize: 15
|
||||||
},
|
},
|
||||||
text: $localize`No data to display yet`,
|
text: $localize`No data to display yet. Try again later.`,
|
||||||
left: 'center',
|
left: 'center',
|
||||||
top: 'center'
|
top: 'center'
|
||||||
};
|
};
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<div class="card-header mb-0 mb-md-4" [style]="widget ? 'display:none' : ''">
|
<div class="card-header mb-0 mb-md-4" [style]="widget ? 'display:none' : ''">
|
||||||
<div class="d-flex d-md-block align-items-baseline">
|
<div class="d-flex d-md-block align-items-baseline">
|
||||||
<span i18n="lightning.nodes-networks">Lightning nodes per network</span>
|
<span i18n="lightning.nodes-networks">Lightning Nodes Per Network</span>
|
||||||
<button class="btn p-0 pl-2" style="margin: 0 0 4px 0px" (click)="onSaveChart()">
|
<button class="btn p-0 pl-2" style="margin: 0 0 4px 0px" (click)="onSaveChart()">
|
||||||
<fa-icon [icon]="['fas', 'download']" [fixedWidth]="true"></fa-icon>
|
<fa-icon [icon]="['fas', 'download']" [fixedWidth]="true"></fa-icon>
|
||||||
</button>
|
</button>
|
||||||
|
@ -64,7 +64,7 @@ export class NodesNetworksChartComponent implements OnInit {
|
|||||||
if (this.widget) {
|
if (this.widget) {
|
||||||
this.miningWindowPreference = '3y';
|
this.miningWindowPreference = '3y';
|
||||||
} else {
|
} else {
|
||||||
this.seoService.setTitle($localize`Lightning nodes per network`);
|
this.seoService.setTitle($localize`:@@b420668a91f8ebaf6e6409c4ba87f1d45961d2bd:Lightning Nodes Per Network`);
|
||||||
this.miningWindowPreference = this.miningService.getDefaultTimespan('all');
|
this.miningWindowPreference = this.miningService.getDefaultTimespan('all');
|
||||||
}
|
}
|
||||||
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
||||||
@ -128,7 +128,7 @@ export class NodesNetworksChartComponent implements OnInit {
|
|||||||
color: 'grey',
|
color: 'grey',
|
||||||
fontSize: 11
|
fontSize: 11
|
||||||
},
|
},
|
||||||
text: $localize`Nodes per network`,
|
text: $localize`:@@b420668a91f8ebaf6e6409c4ba87f1d45961d2bd:Lightning Nodes Per Network`,
|
||||||
left: 'center',
|
left: 'center',
|
||||||
top: 11,
|
top: 11,
|
||||||
zlevel: 10,
|
zlevel: 10,
|
||||||
@ -139,7 +139,7 @@ export class NodesNetworksChartComponent implements OnInit {
|
|||||||
{
|
{
|
||||||
zlevel: 1,
|
zlevel: 1,
|
||||||
yAxisIndex: 0,
|
yAxisIndex: 0,
|
||||||
name: $localize`Unknown`,
|
name: $localize`:@@e5d8bb389c702588877f039d72178f219453a72d:Unknown`,
|
||||||
showSymbol: false,
|
showSymbol: false,
|
||||||
symbol: 'none',
|
symbol: 'none',
|
||||||
data: data.unannounced_nodes,
|
data: data.unannounced_nodes,
|
||||||
@ -308,7 +308,7 @@ export class NodesNetworksChartComponent implements OnInit {
|
|||||||
icon: 'roundRect',
|
icon: 'roundRect',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: $localize`Unknown`,
|
name: $localize`:@@e5d8bb389c702588877f039d72178f219453a72d:Unknown`,
|
||||||
inactiveColor: 'rgb(110, 112, 121)',
|
inactiveColor: 'rgb(110, 112, 121)',
|
||||||
textStyle: {
|
textStyle: {
|
||||||
color: 'white',
|
color: 'white',
|
||||||
@ -320,7 +320,7 @@ export class NodesNetworksChartComponent implements OnInit {
|
|||||||
'$localize`Reachable on Darknet Only`': true,
|
'$localize`Reachable on Darknet Only`': true,
|
||||||
'$localize`Reachable on Clearnet Only`': true,
|
'$localize`Reachable on Clearnet Only`': true,
|
||||||
'$localize`Reachable on Clearnet and Darknet`': true,
|
'$localize`Reachable on Clearnet and Darknet`': true,
|
||||||
'$localize`Unknown`': true,
|
'$localize`:@@e5d8bb389c702588877f039d72178f219453a72d:Unknown`': true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
yAxis: data.tor_nodes.length === 0 ? undefined : [
|
yAxis: data.tor_nodes.length === 0 ? undefined : [
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<div class="d-flex d-md-block align-items-baseline" style="margin-bottom: -5px">
|
<div class="d-flex d-md-block align-items-baseline" style="margin-bottom: -5px">
|
||||||
<span i18n="lightning.nodes-per-country">Lightning nodes per country</span>
|
<span i18n="lightning.nodes-per-country">Lightning Nodes Per Country</span>
|
||||||
<button class="btn p-0 pl-2" style="margin: 0 0 4px 0px" (click)="onSaveChart()">
|
<button class="btn p-0 pl-2" style="margin: 0 0 4px 0px" (click)="onSaveChart()">
|
||||||
<fa-icon [icon]="['fas', 'download']" [fixedWidth]="true"></fa-icon>
|
<fa-icon [icon]="['fas', 'download']" [fixedWidth]="true"></fa-icon>
|
||||||
</button>
|
</button>
|
||||||
|
@ -43,7 +43,7 @@ export class NodesPerCountryChartComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.seoService.setTitle($localize`Lightning nodes per country`);
|
this.seoService.setTitle($localize`:@@9d3ad4c6623870d96b65fb7a708fed6ce7c20044:Lightning Nodes Per Country`);
|
||||||
|
|
||||||
this.nodesPerCountryObservable$ = this.apiService.getNodesPerCountry$()
|
this.nodesPerCountryObservable$ = this.apiService.getNodesPerCountry$()
|
||||||
.pipe(
|
.pipe(
|
||||||
@ -100,7 +100,7 @@ export class NodesPerCountryChartComponent implements OnInit {
|
|||||||
borderColor: '#000',
|
borderColor: '#000',
|
||||||
formatter: () => {
|
formatter: () => {
|
||||||
return `<b style="color: white">${country.name.en} (${country.share}%)</b><br>` +
|
return `<b style="color: white">${country.name.en} (${country.share}%)</b><br>` +
|
||||||
$localize`${country.count.toString()} nodes<br>` +
|
$localize`${country.count.toString()} nodes` + `<br>` +
|
||||||
$localize`${this.amountShortenerPipe.transform(country.capacity / 100000000, 2)} BTC capacity`
|
$localize`${this.amountShortenerPipe.transform(country.capacity / 100000000, 2)} BTC capacity`
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<div class="container-xl full-height" style="min-height: 335px">
|
<div class="container-xl full-height" style="min-height: 335px">
|
||||||
<h1 i18n="lightning.nodes-in-country">
|
<h1>
|
||||||
<span>Lightning nodes in {{ country?.name }}</span>
|
<span i18n="lightning.nodes-in-country">Lightning nodes in {{ country?.name }}</span>
|
||||||
<span style="font-size: 50px; vertical-align:sub;"> {{ country?.flag }}</span>
|
<span style="font-size: 50px; vertical-align:sub;"> {{ country?.flag }}</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
@ -58,7 +58,7 @@
|
|||||||
|
|
||||||
<thead>
|
<thead>
|
||||||
<th class="alias text-left" i18n="lightning.alias">Alias</th>
|
<th class="alias text-left" i18n="lightning.alias">Alias</th>
|
||||||
<th class="timestamp-first text-left" i18n="lightning.first_seen">First seen</th>
|
<th class="timestamp-first text-left" i18n="transaction.first-seen|Transaction first seen">First seen</th>
|
||||||
<th class="timestamp-update text-left" i18n="lightning.last_update">Last update</th>
|
<th class="timestamp-update text-left" i18n="lightning.last_update">Last update</th>
|
||||||
<th class="capacity text-right" i18n="lightning.capacity">Capacity</th>
|
<th class="capacity text-right" i18n="lightning.capacity">Capacity</th>
|
||||||
<th class="channels text-right" i18n="lightning.channels">Channels</th>
|
<th class="channels text-right" i18n="lightning.channels">Channels</th>
|
||||||
|
@ -3,21 +3,21 @@
|
|||||||
<div *ngIf="widget">
|
<div *ngIf="widget">
|
||||||
<div class="pool-distribution" *ngIf="(nodesPerAsObservable$ | async) as stats; else loadingReward">
|
<div class="pool-distribution" *ngIf="(nodesPerAsObservable$ | async) as stats; else loadingReward">
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<h5 class="card-title d-inline-block" i18n="lightning.clearnet-capacity">Clearnet capacity</h5>
|
<h5 class="card-title d-inline-block" i18n="lightning.clearnet-capacity">Clearnet Capacity</h5>
|
||||||
<p class="card-text" i18n-ngbTooltip="lightning.clearnet-capacity-desc"
|
<p class="card-text" i18n-ngbTooltip="lightning.clearnet-capacity-desc"
|
||||||
ngbTooltip="How much liquidity is running on nodes advertising at least one clearnet IP address" placement="bottom">
|
ngbTooltip="How much liquidity is running on nodes advertising at least one clearnet IP address" placement="bottom">
|
||||||
<app-amount [satoshis]="stats.clearnetCapacity" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount>
|
<app-amount [satoshis]="stats.clearnetCapacity" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<h5 class="card-title d-inline-block" i18n="lightning.unknown-capacity">Unknown capacity</h5>
|
<h5 class="card-title d-inline-block" i18n="lightning.unknown-capacity">Unknown Capacity</h5>
|
||||||
<p class="card-text" i18n-ngbTooltip="lightning.unknown-capacity-desc"
|
<p class="card-text" i18n-ngbTooltip="lightning.unknown-capacity-desc"
|
||||||
ngbTooltip="How much liquidity is running on nodes which ISP was not identifiable" placement="bottom">
|
ngbTooltip="How much liquidity is running on nodes which ISP was not identifiable" placement="bottom">
|
||||||
<app-amount [satoshis]="stats.unknownCapacity" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount>
|
<app-amount [satoshis]="stats.unknownCapacity" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<h5 class="card-title d-inline-block" i18n="lightning.tor-capacity">Tor capacity</h5>
|
<h5 class="card-title d-inline-block" i18n="lightning.tor-capacity">Tor Capacity</h5>
|
||||||
<p class="card-text" i18n-ngbTooltip="lightning.tor-capacity-desc"
|
<p class="card-text" i18n-ngbTooltip="lightning.tor-capacity-desc"
|
||||||
ngbTooltip="How much liquidity is running on nodes advertising only Tor addresses" placement="bottom">
|
ngbTooltip="How much liquidity is running on nodes advertising only Tor addresses" placement="bottom">
|
||||||
<app-amount [satoshis]="stats.torCapacity" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount>
|
<app-amount [satoshis]="stats.torCapacity" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount>
|
||||||
@ -33,8 +33,8 @@
|
|||||||
<fa-icon [icon]="['fas', 'download']" [fixedWidth]="true"></fa-icon>
|
<fa-icon [icon]="['fas', 'download']" [fixedWidth]="true"></fa-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<small class="d-block" style="color: #ffffff66; min-height: 25px" i18n="lightning.tor-nodes-excluded">
|
<small class="d-block" style="color: #ffffff66; min-height: 25px" >
|
||||||
<span>(Tor nodes excluded)</span>
|
<span i18n="lightning.tor-nodes-excluded">(Tor nodes excluded)</span>
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -80,19 +80,19 @@
|
|||||||
<ng-template #loadingReward>
|
<ng-template #loadingReward>
|
||||||
<div class="pool-distribution">
|
<div class="pool-distribution">
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<h5 class="card-title d-inline-block" i18n="lightning.clearnet-capacity">Clearnet capacity</h5>
|
<h5 class="card-title d-inline-block" i18n="lightning.clearnet-capacity">Clearnet Capacity</h5>
|
||||||
<p class="card-text">
|
<p class="card-text">
|
||||||
<span class="skeleton-loader skeleton-loader-big"></span>
|
<span class="skeleton-loader skeleton-loader-big"></span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<h5 class="card-title d-inline-block" i18n="lightning.unknown-capacity">Unknown capacity</h5>
|
<h5 class="card-title d-inline-block" i18n="lightning.unknown-capacity">Unknown Capacity</h5>
|
||||||
<p class="card-text">
|
<p class="card-text">
|
||||||
<span class="skeleton-loader skeleton-loader-big"></span>
|
<span class="skeleton-loader skeleton-loader-big"></span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<h5 class="card-title d-inline-block" i18n="lightning.tor-capacity">Tor capacity</h5>
|
<h5 class="card-title d-inline-block" i18n="lightning.tor-capacity">Tor Capacity</h5>
|
||||||
<p class="card-text">
|
<p class="card-text">
|
||||||
<span class="skeleton-loader skeleton-loader-big"></span>
|
<span class="skeleton-loader skeleton-loader-big"></span>
|
||||||
</p>
|
</p>
|
||||||
|
@ -48,7 +48,7 @@ export class NodesPerISPChartComponent implements OnInit {
|
|||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
if (!this.widget) {
|
if (!this.widget) {
|
||||||
this.seoService.setTitle($localize`Lightning nodes per ISP`);
|
this.seoService.setTitle($localize`:@@8573a1576789bd2c4faeaed23037c4917812c6cf:Lightning Nodes Per ISP`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.nodesPerAsObservable$ = combineLatest([
|
this.nodesPerAsObservable$ = combineLatest([
|
||||||
@ -154,7 +154,7 @@ export class NodesPerISPChartComponent implements OnInit {
|
|||||||
borderColor: '#000',
|
borderColor: '#000',
|
||||||
formatter: () => {
|
formatter: () => {
|
||||||
return `<b style="color: white">${isp[1]} (${this.sortBy === 'capacity' ? isp[7] : isp[6]}%)</b><br>` +
|
return `<b style="color: white">${isp[1]} (${this.sortBy === 'capacity' ? isp[7] : isp[6]}%)</b><br>` +
|
||||||
$localize`${isp[4].toString()} nodes<br>` +
|
$localize`${isp[4].toString()} nodes` + `<br>` +
|
||||||
$localize`${this.amountShortenerPipe.transform(isp[2] / 100000000, 2)} BTC`
|
$localize`${this.amountShortenerPipe.transform(isp[2] / 100000000, 2)} BTC`
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
@ -186,7 +186,7 @@ export class NodesPerISPChartComponent implements OnInit {
|
|||||||
borderColor: '#000',
|
borderColor: '#000',
|
||||||
formatter: () => {
|
formatter: () => {
|
||||||
return `<b style="color: white">Other (${totalShareOther.toFixed(2)}%)</b><br>` +
|
return `<b style="color: white">Other (${totalShareOther.toFixed(2)}%)</b><br>` +
|
||||||
$localize`${nodeCountOther.toString()} nodes<br>` +
|
$localize`${nodeCountOther.toString()} nodes` + `<br>` +
|
||||||
$localize`${this.amountShortenerPipe.transform(capacityOther / 100000000, 2)} BTC`;
|
$localize`${this.amountShortenerPipe.transform(capacityOther / 100000000, 2)} BTC`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<div class="box preview-box" *ngIf="(nodes$ | async) as ispNodes">
|
<div class="box preview-box" *ngIf="(nodes$ | async) as ispNodes">
|
||||||
<app-preview-title>
|
<app-preview-title>
|
||||||
<span i18n="lightning.node">lightning ISP</span>
|
<span i18n="lightning.node-isp">Lightning ISP</span>
|
||||||
</app-preview-title>
|
</app-preview-title>
|
||||||
<div class="row d-flex justify-content-between full-width-row">
|
<div class="row d-flex justify-content-between full-width-row">
|
||||||
<div class="title-wrapper">
|
<div class="title-wrapper">
|
||||||
|
@ -55,7 +55,7 @@
|
|||||||
|
|
||||||
<thead>
|
<thead>
|
||||||
<th class="alias text-left" i18n="lightning.alias">Alias</th>
|
<th class="alias text-left" i18n="lightning.alias">Alias</th>
|
||||||
<th class="timestamp-first text-left" i18n="lightning.first_seen">First seen</th>
|
<th class="timestamp-first text-left" i18n="transaction.first-seen|Transaction first seen">First seen</th>
|
||||||
<th class="timestamp-update text-left" i18n="lightning.last_update">Last update</th>
|
<th class="timestamp-update text-left" i18n="lightning.last_update">Last update</th>
|
||||||
<th class="capacity text-right" i18n="lightning.capacity">Capacity</th>
|
<th class="capacity text-right" i18n="lightning.capacity">Capacity</th>
|
||||||
<th class="channels text-right" i18n="lightning.channels">Channels</th>
|
<th class="channels text-right" i18n="lightning.channels">Channels</th>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<div [class]="!widget ? 'container-xl full-height' : ''">
|
<div [class]="!widget ? 'container-xl full-height' : ''">
|
||||||
<h1 *ngIf="!widget" class="float-left" i18n="lightning.top-100-oldest-nodes">
|
<h1 *ngIf="!widget" class="float-left">
|
||||||
<span>Top 100 oldest lightning nodes</span>
|
<span i18n="lightning.top-100-oldest-nodes">Top 100 oldest lightning nodes</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div [class]="widget ? 'widget' : 'full'">
|
<div [class]="widget ? 'widget' : 'full'">
|
||||||
@ -8,7 +8,7 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<th class="rank"></th>
|
<th class="rank"></th>
|
||||||
<th class="alias text-left" i18n="nodes.alias">Alias</th>
|
<th class="alias text-left" i18n="nodes.alias">Alias</th>
|
||||||
<th class="timestamp-first text-right" i18n="lightning.first_seen">First seen</th>
|
<th class="timestamp-first text-right" i18n="transaction.first-seen|Transaction first seen">First seen</th>
|
||||||
<th *ngIf="!widget" class="capacity text-right" i18n="node.liquidity">Liquidity</th>
|
<th *ngIf="!widget" class="capacity text-right" i18n="node.liquidity">Liquidity</th>
|
||||||
<th *ngIf="!widget" class="channels text-right" i18n="lightning.channels">Channels</th>
|
<th *ngIf="!widget" class="channels text-right" i18n="lightning.channels">Channels</th>
|
||||||
<th *ngIf="!widget" class="timestamp-update text-left" i18n="lightning.last_update">Last update</th>
|
<th *ngIf="!widget" class="timestamp-update text-left" i18n="lightning.last_update">Last update</th>
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
<th class="alias text-left" i18n="nodes.alias">Alias</th>
|
<th class="alias text-left" i18n="nodes.alias">Alias</th>
|
||||||
<th class="capacity text-right" i18n="node.liquidity">Liquidity</th>
|
<th class="capacity text-right" i18n="node.liquidity">Liquidity</th>
|
||||||
<th *ngIf="!widget" class="channels text-right" i18n="lightning.channels">Channels</th>
|
<th *ngIf="!widget" class="channels text-right" i18n="lightning.channels">Channels</th>
|
||||||
<th *ngIf="!widget" class="timestamp-first text-left" i18n="lightning.first_seen">First seen</th>
|
<th *ngIf="!widget" class="timestamp-first text-left" i18n="transaction.first-seen|Transaction first seen">First seen</th>
|
||||||
<th *ngIf="!widget" class="timestamp-update text-left" i18n="lightning.last_update">Last update</th>
|
<th *ngIf="!widget" class="timestamp-update text-left" i18n="lightning.last_update">Last update</th>
|
||||||
<th *ngIf="!widget" class="location text-right" i18n="lightning.location">Location</th>
|
<th *ngIf="!widget" class="location text-right" i18n="lightning.location">Location</th>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -26,7 +26,7 @@ export class TopNodesPerCapacity implements OnInit {
|
|||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
if (!this.widget) {
|
if (!this.widget) {
|
||||||
this.seoService.setTitle($localize`Liquidity Ranking`);
|
this.seoService.setTitle($localize`:@@2d9883d230a47fbbb2ec969e32a186597ea27405:Liquidity Ranking`);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 1; i <= (this.widget ? (isMobile() ? 8 : 7) : 100); ++i) {
|
for (let i = 1; i <= (this.widget ? (isMobile() ? 8 : 7) : 100); ++i) {
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
<th class="alias text-left" i18n="nodes.alias">Alias</th>
|
<th class="alias text-left" i18n="nodes.alias">Alias</th>
|
||||||
<th class="channels text-right" i18n="node.channels">Channels</th>
|
<th class="channels text-right" i18n="node.channels">Channels</th>
|
||||||
<th *ngIf="!widget" class="capacity text-right" i18n="lightning.liquidity">Liquidity</th>
|
<th *ngIf="!widget" class="capacity text-right" i18n="lightning.liquidity">Liquidity</th>
|
||||||
<th *ngIf="!widget" class="timestamp-first text-left" i18n="lightning.first_seen">First seen</th>
|
<th *ngIf="!widget" class="timestamp-first text-left" i18n="transaction.first-seen|Transaction first seen">First seen</th>
|
||||||
<th *ngIf="!widget" class="timestamp-update text-left" i18n="lightning.last_update">Last update</th>
|
<th *ngIf="!widget" class="timestamp-update text-left" i18n="lightning.last_update">Last update</th>
|
||||||
<th *ngIf="!widget" class="location text-right" i18n="lightning.location">Location</th>
|
<th *ngIf="!widget" class="location text-right" i18n="lightning.location">Location</th>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
||||||
import { map, Observable } from 'rxjs';
|
import { map, Observable } from 'rxjs';
|
||||||
import { INodesRanking, ITopNodesPerChannels } from '../../../interfaces/node-api.interface';
|
import { INodesRanking, ITopNodesPerChannels } from '../../../interfaces/node-api.interface';
|
||||||
import { SeoService } from '../../../services/seo.service';
|
|
||||||
import { isMobile } from '../../../shared/common.utils';
|
import { isMobile } from '../../../shared/common.utils';
|
||||||
import { GeolocationData } from '../../../shared/components/geolocation/geolocation.component';
|
import { GeolocationData } from '../../../shared/components/geolocation/geolocation.component';
|
||||||
import { LightningApiService } from '../../lightning-api.service';
|
import { LightningApiService } from '../../lightning-api.service';
|
||||||
@ -21,14 +20,9 @@ export class TopNodesPerChannels implements OnInit {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private apiService: LightningApiService,
|
private apiService: LightningApiService,
|
||||||
private seoService: SeoService
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
if (!this.widget) {
|
|
||||||
this.seoService.setTitle($localize`Connectivity Ranking`);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 1; i <= (this.widget ? (isMobile() ? 8 : 7) : 100); ++i) {
|
for (let i = 1; i <= (this.widget ? (isMobile() ? 8 : 7) : 100); ++i) {
|
||||||
this.skeletonRows.push(i);
|
this.skeletonRows.push(i);
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<a class="title-link" href="" [routerLink]="['/lightning/nodes/rankings/liquidity' | relativeUrl]">
|
<a class="title-link" href="" [routerLink]="['/lightning/nodes/rankings/liquidity' | relativeUrl]">
|
||||||
<h5 class="card-title d-inline" i18n="lightning.liquidity-ranking">Liquidity ranking</h5>
|
<h5 class="card-title d-inline" i18n="lightning.liquidity-ranking">Liquidity Ranking</h5>
|
||||||
<span> </span>
|
<span> </span>
|
||||||
<fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true"
|
<fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true"
|
||||||
style="vertical-align: 'text-top'; font-size: 13px; color: '#4a68b9'"></fa-icon>
|
style="vertical-align: 'text-top'; font-size: 13px; color: '#4a68b9'"></fa-icon>
|
||||||
@ -19,7 +19,7 @@
|
|||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<a class="title-link" href="" [routerLink]="['/lightning/nodes/rankings/connectivity' | relativeUrl]">
|
<a class="title-link" href="" [routerLink]="['/lightning/nodes/rankings/connectivity' | relativeUrl]">
|
||||||
<h5 class="card-title d-inline" i18n="lightning.connectivity-ranking">Connectivity ranking</h5>
|
<h5 class="card-title d-inline" i18n="lightning.connectivity-ranking">Connectivity Ranking</h5>
|
||||||
<span> </span>
|
<span> </span>
|
||||||
<fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true"
|
<fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true"
|
||||||
style="vertical-align: 'text-top'; font-size: 13px; color: '#4a68b9'"></fa-icon>
|
style="vertical-align: 'text-top'; font-size: 13px; color: '#4a68b9'"></fa-icon>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<div class="card-header mb-0 mb-md-4" [style]="widget ? 'display:none' : ''">
|
<div class="card-header mb-0 mb-md-4" [style]="widget ? 'display:none' : ''">
|
||||||
<div class="d-flex d-md-block align-items-baseline">
|
<div class="d-flex d-md-block align-items-baseline">
|
||||||
<span i18n="mining.channels-and-capacity">Channels & Capacity</span>
|
<span i18n="lightning.network-capacity">Lightning Network Capacity</span>
|
||||||
<button class="btn p-0 pl-2" style="margin: 0 0 4px 0px" (click)="onSaveChart()">
|
<button class="btn p-0 pl-2" style="margin: 0 0 4px 0px" (click)="onSaveChart()">
|
||||||
<fa-icon [icon]="['fas', 'download']" [fixedWidth]="true"></fa-icon>
|
<fa-icon [icon]="['fas', 'download']" [fixedWidth]="true"></fa-icon>
|
||||||
</button>
|
</button>
|
||||||
@ -49,9 +49,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="widget && (capacityObservable$ | async) as stats">
|
<div *ngIf="widget && (capacityObservable$ | async) as stats">
|
||||||
<div *ngIf="stats.days === 0" class="indexing-message d-flex" i18n="lightning.indexing-in-progress">
|
<div *ngIf="stats.days === 0" class="indexing-message d-flex" i18n="lightning.indexing-in-progress">Indexing in progress</div>
|
||||||
Indexing in progress
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
@ -63,7 +63,7 @@ export class LightningStatisticsChartComponent implements OnInit {
|
|||||||
if (this.widget) {
|
if (this.widget) {
|
||||||
this.miningWindowPreference = '3y';
|
this.miningWindowPreference = '3y';
|
||||||
} else {
|
} else {
|
||||||
this.seoService.setTitle($localize`Channels and Capacity`);
|
this.seoService.setTitle($localize`:@@ea8db27e6db64f8b940711948c001a1100e5fe9f:Lightning Network Capacity`);
|
||||||
this.miningWindowPreference = this.miningService.getDefaultTimespan('all');
|
this.miningWindowPreference = this.miningService.getDefaultTimespan('all');
|
||||||
}
|
}
|
||||||
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
||||||
@ -119,7 +119,7 @@ export class LightningStatisticsChartComponent implements OnInit {
|
|||||||
color: 'grey',
|
color: 'grey',
|
||||||
fontSize: 11
|
fontSize: 11
|
||||||
},
|
},
|
||||||
text: $localize`Channels & Capacity`,
|
text: $localize`:@@ea8db27e6db64f8b940711948c001a1100e5fe9f:Lightning Network Capacity`,
|
||||||
left: 'center',
|
left: 'center',
|
||||||
top: 11,
|
top: 11,
|
||||||
zlevel: 10,
|
zlevel: 10,
|
||||||
@ -191,7 +191,7 @@ export class LightningStatisticsChartComponent implements OnInit {
|
|||||||
padding: 10,
|
padding: 10,
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
name: 'Channels',
|
name: $localize`:@@807cf11e6ac1cde912496f764c176bdfdd6b7e19:Channels`,
|
||||||
inactiveColor: 'rgb(110, 112, 121)',
|
inactiveColor: 'rgb(110, 112, 121)',
|
||||||
textStyle: {
|
textStyle: {
|
||||||
color: 'white',
|
color: 'white',
|
||||||
@ -199,7 +199,7 @@ export class LightningStatisticsChartComponent implements OnInit {
|
|||||||
icon: 'roundRect',
|
icon: 'roundRect',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Capacity',
|
name: $localize`:@@ce9dfdc6dccb28dc75a78c704e09dc18fb02dcfa:Capacity`,
|
||||||
inactiveColor: 'rgb(110, 112, 121)',
|
inactiveColor: 'rgb(110, 112, 121)',
|
||||||
textStyle: {
|
textStyle: {
|
||||||
color: 'white',
|
color: 'white',
|
||||||
@ -279,7 +279,7 @@ export class LightningStatisticsChartComponent implements OnInit {
|
|||||||
{
|
{
|
||||||
zlevel: 0,
|
zlevel: 0,
|
||||||
yAxisIndex: 1,
|
yAxisIndex: 1,
|
||||||
name: $localize`Capacity`,
|
name: $localize`:@@ce9dfdc6dccb28dc75a78c704e09dc18fb02dcfa:Capacity`,
|
||||||
showSymbol: false,
|
showSymbol: false,
|
||||||
symbol: 'none',
|
symbol: 'none',
|
||||||
stack: 'Total',
|
stack: 'Total',
|
||||||
@ -341,7 +341,7 @@ export class LightningStatisticsChartComponent implements OnInit {
|
|||||||
this.chartInstance.setOption(this.chartOptions);
|
this.chartInstance.setOption(this.chartOptions);
|
||||||
download(this.chartInstance.getDataURL({
|
download(this.chartInstance.getDataURL({
|
||||||
pixelRatio: 2,
|
pixelRatio: 2,
|
||||||
}), `block-sizes-weights-${this.timespan}-${Math.round(now.getTime() / 1000)}.svg`);
|
}), `lightning-network-capacity-${this.timespan}-${Math.round(now.getTime() / 1000)}.svg`);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.chartOptions.grid.bottom = prevBottom;
|
this.chartOptions.grid.bottom = prevBottom;
|
||||||
this.chartOptions.backgroundColor = 'none';
|
this.chartOptions.backgroundColor = 'none';
|
||||||
|
90
frontend/src/app/services/navigation.service.ts
Normal file
90
frontend/src/app/services/navigation.service.ts
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Router, ActivatedRoute, NavigationEnd, ActivatedRouteSnapshot } from '@angular/router';
|
||||||
|
import { BehaviorSubject } from 'rxjs';
|
||||||
|
import { filter, map } from 'rxjs/operators';
|
||||||
|
import { StateService } from './state.service';
|
||||||
|
|
||||||
|
const networkModules = {
|
||||||
|
bitcoin: {
|
||||||
|
subnets: [
|
||||||
|
{ name: 'mainnet', path: '' },
|
||||||
|
{ name: 'testnet', path: '/testnet' },
|
||||||
|
{ name: 'signet', path: '/signet' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
liquid: {
|
||||||
|
subnets: [
|
||||||
|
{ name: 'liquid', path: '' },
|
||||||
|
{ name: 'liquidtestnet', path: '/testnet' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
bisq: {
|
||||||
|
subnets: [
|
||||||
|
{ name: 'bisq', path: '' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const networks = Object.keys(networkModules);
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class NavigationService {
|
||||||
|
subnetPaths = new BehaviorSubject<Record<string,string>>({});
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private stateService: StateService,
|
||||||
|
private router: Router,
|
||||||
|
) {
|
||||||
|
this.router.events.pipe(
|
||||||
|
filter(event => event instanceof NavigationEnd),
|
||||||
|
map(() => this.router.routerState.snapshot.root),
|
||||||
|
).subscribe((state) => {
|
||||||
|
this.updateSubnetPaths(state);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each network (bitcoin/liquid/bisq), find and save the longest url path compatible with the current route
|
||||||
|
updateSubnetPaths(root: ActivatedRouteSnapshot): void {
|
||||||
|
let path = '';
|
||||||
|
const networkPaths = {};
|
||||||
|
let route = root;
|
||||||
|
// traverse the router state tree until all network paths are set, or we reach the end of the tree
|
||||||
|
while (!networks.reduce((acc, network) => acc && !!networkPaths[network], true) && route) {
|
||||||
|
// 'networkSpecific' paths may correspond to valid routes on other networks, but aren't directly compatible
|
||||||
|
// (e.g. we shouldn't link a mainnet transaction page to the same txid on testnet or liquid)
|
||||||
|
if (route.data?.networkSpecific) {
|
||||||
|
networks.forEach(network => {
|
||||||
|
if (networkPaths[network] == null) {
|
||||||
|
networkPaths[network] = path;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// null or empty networks list is shorthand for "compatible with every network"
|
||||||
|
if (route.data?.networks?.length) {
|
||||||
|
// if the list is non-empty, only those networks are compatible
|
||||||
|
networks.forEach(network => {
|
||||||
|
if (!route.data.networks.includes(network)) {
|
||||||
|
if (networkPaths[network] == null) {
|
||||||
|
networkPaths[network] = path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (route.url?.length) {
|
||||||
|
path = [path, ...route.url.map(segment => segment.path).filter(path => {
|
||||||
|
return path.length && !['testnet', 'signet'].includes(path);
|
||||||
|
})].join('/');
|
||||||
|
}
|
||||||
|
route = route.firstChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
const subnetPaths = {};
|
||||||
|
Object.entries(networkModules).forEach(([key, network]) => {
|
||||||
|
network.subnets.forEach(subnet => {
|
||||||
|
subnetPaths[subnet.name] = subnet.path + (networkPaths[key] != null ? networkPaths[key] : path);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.subnetPaths.next(subnetPaths);
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user