Merge branch 'master' into master
This commit is contained in:
		
						commit
						e63096239e
					
				@ -31,6 +31,7 @@
 | 
			
		||||
    "prefer-const": 1,
 | 
			
		||||
    "prefer-rest-params": 1,
 | 
			
		||||
    "quotes": [1, "single", { "allowTemplateLiterals": true }],
 | 
			
		||||
    "semi": 1
 | 
			
		||||
    "semi": 1,
 | 
			
		||||
    "eqeqeq": 1
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -434,12 +434,14 @@ class NodesApi {
 | 
			
		||||
        SELECT nodes.public_key, CAST(COALESCE(nodes.capacity, 0) as INT) as capacity, CAST(COALESCE(nodes.channels, 0) as INT) as channels,
 | 
			
		||||
          nodes.alias, UNIX_TIMESTAMP(nodes.first_seen) as first_seen, UNIX_TIMESTAMP(nodes.updated_at) as updated_at,
 | 
			
		||||
          geo_names_city.names as city, geo_names_country.names as country,
 | 
			
		||||
          geo_names_iso.names as iso_code, geo_names_subdivision.names as subdivision
 | 
			
		||||
          geo_names_iso.names as iso_code, geo_names_subdivision.names as subdivision,
 | 
			
		||||
          nodes.longitude, nodes.latitude, nodes.as_number, geo_names_isp.names as isp
 | 
			
		||||
        FROM nodes
 | 
			
		||||
        LEFT JOIN geo_names geo_names_country ON geo_names_country.id = nodes.country_id AND geo_names_country.type = 'country'
 | 
			
		||||
        LEFT JOIN geo_names geo_names_city ON geo_names_city.id = nodes.city_id AND geo_names_city.type = 'city'
 | 
			
		||||
        LEFT JOIN geo_names geo_names_iso ON geo_names_iso.id = nodes.country_id AND geo_names_iso.type = 'country_iso_code'
 | 
			
		||||
        LEFT JOIN geo_names geo_names_subdivision on geo_names_subdivision.id = nodes.subdivision_id AND geo_names_subdivision.type = 'division'
 | 
			
		||||
        LEFT JOIN geo_names geo_names_isp on geo_names_isp.id = nodes.as_number AND geo_names_isp.type = 'as_organization'
 | 
			
		||||
        WHERE geo_names_country.id = ?
 | 
			
		||||
        ORDER BY capacity DESC
 | 
			
		||||
      `;
 | 
			
		||||
@ -449,6 +451,7 @@ class NodesApi {
 | 
			
		||||
        rows[i].country = JSON.parse(rows[i].country);
 | 
			
		||||
        rows[i].city = JSON.parse(rows[i].city);
 | 
			
		||||
        rows[i].subdivision = JSON.parse(rows[i].subdivision);
 | 
			
		||||
        rows[i].isp = JSON.parse(rows[i].isp);
 | 
			
		||||
      }
 | 
			
		||||
      return rows;
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
@ -463,7 +466,8 @@ class NodesApi {
 | 
			
		||||
        SELECT nodes.public_key, CAST(COALESCE(nodes.capacity, 0) as INT) as capacity, CAST(COALESCE(nodes.channels, 0) as INT) as channels,
 | 
			
		||||
          nodes.alias, UNIX_TIMESTAMP(nodes.first_seen) as first_seen, UNIX_TIMESTAMP(nodes.updated_at) as updated_at,
 | 
			
		||||
          geo_names_city.names as city, geo_names_country.names as country,
 | 
			
		||||
          geo_names_iso.names as iso_code, geo_names_subdivision.names as subdivision
 | 
			
		||||
          geo_names_iso.names as iso_code, geo_names_subdivision.names as subdivision,
 | 
			
		||||
          nodes.longitude, nodes.latitude
 | 
			
		||||
        FROM nodes
 | 
			
		||||
        LEFT JOIN geo_names geo_names_country ON geo_names_country.id = nodes.country_id AND geo_names_country.type = 'country'
 | 
			
		||||
        LEFT JOIN geo_names geo_names_city ON geo_names_city.id = nodes.city_id AND geo_names_city.type = 'city'
 | 
			
		||||
 | 
			
		||||
@ -124,7 +124,7 @@ async function buildIncompleteChannel(clChannel: any): Promise<ILightningApi.Cha
 | 
			
		||||
 */
 | 
			
		||||
function convertPolicy(clChannel: any): ILightningApi.RoutingPolicy {
 | 
			
		||||
  return {
 | 
			
		||||
    time_lock_delta: 0, // TODO
 | 
			
		||||
    time_lock_delta: clChannel.delay,
 | 
			
		||||
    min_htlc: clChannel.htlc_minimum_msat.slice(0, -4),
 | 
			
		||||
    max_htlc_msat: clChannel.htlc_maximum_msat.slice(0, -4),
 | 
			
		||||
    fee_base_msat: clChannel.base_fee_millisatoshi,
 | 
			
		||||
 | 
			
		||||
@ -132,8 +132,8 @@ sed -i "s!__MEMPOOL_USER_AGENT__!${__MEMPOOL_USER_AGENT__}!g" mempool-config.jso
 | 
			
		||||
sed -i "s/__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__/${__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__}/g" mempool-config.json
 | 
			
		||||
sed -i "s/__MEMPOOL_INDEXING_BLOCKS_AMOUNT__/${__MEMPOOL_INDEXING_BLOCKS_AMOUNT__}/g" mempool-config.json
 | 
			
		||||
sed -i "s/__MEMPOOL_AUTOMATIC_BLOCK_REINDEXING__/${__MEMPOOL_AUTOMATIC_BLOCK_REINDEXING__}/g" mempool-config.json
 | 
			
		||||
sed -i "s!__MEMPOOL_POOLS_JSON_URL__!${__MEMPOOL_POOLS_JSON_URL__}/g" mempool-config.json
 | 
			
		||||
sed -i "s!__MEMPOOL_POOLS_JSON_TREE_URL__!${__MEMPOOL_POOLS_JSON_TREE_URL__}/g" mempool-config.json
 | 
			
		||||
sed -i "s!__MEMPOOL_POOLS_JSON_URL__!${__MEMPOOL_POOLS_JSON_URL__}!g" mempool-config.json
 | 
			
		||||
sed -i "s!__MEMPOOL_POOLS_JSON_TREE_URL__!${__MEMPOOL_POOLS_JSON_TREE_URL__}!g" mempool-config.json
 | 
			
		||||
 | 
			
		||||
sed -i "s/__CORE_RPC_HOST__/${__CORE_RPC_HOST__}/g" mempool-config.json
 | 
			
		||||
sed -i "s/__CORE_RPC_PORT__/${__CORE_RPC_PORT__}/g" mempool-config.json
 | 
			
		||||
 | 
			
		||||
@ -32,6 +32,7 @@
 | 
			
		||||
    "prefer-const": 1,
 | 
			
		||||
    "prefer-rest-params": 1,
 | 
			
		||||
    "quotes": [1, "single", { "allowTemplateLiterals": true }],
 | 
			
		||||
    "semi": 1
 | 
			
		||||
    "semi": 1,
 | 
			
		||||
    "eqeqeq": 1
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -170,6 +170,10 @@
 | 
			
		||||
          },
 | 
			
		||||
          "configurations": {
 | 
			
		||||
            "production": {
 | 
			
		||||
              "assets": [
 | 
			
		||||
                "src/favicon.ico",
 | 
			
		||||
                "src/robots.txt"
 | 
			
		||||
              ],
 | 
			
		||||
              "fileReplacements": [
 | 
			
		||||
                {
 | 
			
		||||
                  "replace": "src/environments/environment.ts",
 | 
			
		||||
 | 
			
		||||
@ -34,7 +34,7 @@
 | 
			
		||||
    "start:local-staging": "npm run generate-config && npm run sync-assets-dev && npm run ng -- serve -c local-staging",
 | 
			
		||||
    "start:mixed": "npm run generate-config && npm run sync-assets-dev && npm run ng -- serve -c mixed",
 | 
			
		||||
    "build": "npm run generate-config && npm run ng -- build --configuration production --localize && npm run sync-assets && npm run build-mempool.js",
 | 
			
		||||
    "sync-assets": "node sync-assets.js && rsync -av ./dist/mempool/browser/en-US/resources ./dist/mempool/browser/resources",
 | 
			
		||||
    "sync-assets": "rsync -av ./src/resources ./dist/mempool/browser && node sync-assets.js",
 | 
			
		||||
    "sync-assets-dev": "node sync-assets.js dev",
 | 
			
		||||
    "generate-config": "node generate-config.js",
 | 
			
		||||
    "build-mempool.js": "npm run build-mempool-js && npm run build-mempool-liquid-js && npm run build-mempool-bisq-js",
 | 
			
		||||
 | 
			
		||||
@ -187,8 +187,8 @@
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div class="selfhosted-integrations-sponsor">
 | 
			
		||||
    <h3 i18n="about.self-hosted-integrations">Self-Hosted Integrations</h3>
 | 
			
		||||
  <div class="community-integrations-sponsor">
 | 
			
		||||
    <h3 i18n="about.community-integrations">Community Integrations</h3>
 | 
			
		||||
    <div class="wrapper">
 | 
			
		||||
      <a href="https://github.com/getumbrel/umbrel" target="_blank" title="Umbrel">
 | 
			
		||||
        <img class="image" src="/resources/profile/umbrel.png" />
 | 
			
		||||
@ -218,18 +218,24 @@
 | 
			
		||||
        <img class="image" src="/resources/profile/start9.png" />
 | 
			
		||||
        <span>EmbassyOS</span>
 | 
			
		||||
      </a>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div class="community-integrations-sponsor">
 | 
			
		||||
    <h3 i18n="about.wallet-integrations">Wallet Integrations</h3>
 | 
			
		||||
    <div class="wrapper">
 | 
			
		||||
      <a href="https://github.com/btcpayserver/btcpayserver" target="_blank" title="BTCPay Server">
 | 
			
		||||
        <img class="image" src="/resources/profile/btcpayserver.svg" />
 | 
			
		||||
        <span>BTCPay</span>
 | 
			
		||||
      </a>
 | 
			
		||||
      <a href="https://github.com/bisq-network/bisq" target="_blank" title="Bisq">
 | 
			
		||||
        <img class="image" src="/resources/profile/bisq_network.png" />
 | 
			
		||||
        <span>Bisq</span>
 | 
			
		||||
      </a>
 | 
			
		||||
      <a href="https://github.com/BlueWallet/BlueWallet" target="_blank" title="BlueWallet">
 | 
			
		||||
        <img class="image" src="/resources/profile/bluewallet.png" />
 | 
			
		||||
        <span>BlueWallet</span>
 | 
			
		||||
      </a>
 | 
			
		||||
      <a href="https://github.com/muun/apollo" target="_blank" title="Muun Wallet">
 | 
			
		||||
        <img class="image" src="/resources/profile/muun.png" />
 | 
			
		||||
        <span>Muun</span>
 | 
			
		||||
      </a>
 | 
			
		||||
      <a href="https://github.com/spesmilo/electrum" target="_blank" title="Electrum Wallet">
 | 
			
		||||
        <img class="image" src="/resources/profile/electrum.jpg" />
 | 
			
		||||
        <img class="image" src="/resources/profile/electrum.png" />
 | 
			
		||||
        <span>Electrum</span>
 | 
			
		||||
      </a>
 | 
			
		||||
      <a href="https://github.com/cryptoadvance/specter-desktop" target="_blank" title="Specter Wallet">
 | 
			
		||||
@ -244,18 +250,14 @@
 | 
			
		||||
        <img class="image" src="/resources/profile/phoenix.jpg" />
 | 
			
		||||
        <span>Phoenix</span>
 | 
			
		||||
      </a>
 | 
			
		||||
      <a href="https://github.com/lnbits/lnbits-legend" target="_blank" title="LNbits">
 | 
			
		||||
        <img class="image" src="/resources/profile/lnbits.svg" />
 | 
			
		||||
        <span>LNBits</span>
 | 
			
		||||
      </a>
 | 
			
		||||
      <a href="https://github.com/layer2tech/mercury-wallet" target="_blank" title="Mercury Wallet">
 | 
			
		||||
        <img class="image" src="/resources/profile/mercury.svg" />
 | 
			
		||||
        <span>Mercury</span>
 | 
			
		||||
      </a>
 | 
			
		||||
      <a href="https://github.com/muun/apollo" target="_blank" title="Muun Wallet">
 | 
			
		||||
        <img class="image" src="/resources/profile/muun.png" />
 | 
			
		||||
        <span>Muun</span>
 | 
			
		||||
      </a>
 | 
			
		||||
      <a href="https://github.com/BlueWallet/BlueWallet" target="_blank" title="BlueWallet">
 | 
			
		||||
        <img class="image" src="/resources/profile/bluewallet.png" />
 | 
			
		||||
        <span>BlueWallet</span>
 | 
			
		||||
      </a>
 | 
			
		||||
      <a href="https://github.com/hsjoberg/blixt-wallet" target="_blank" title="Blixt Wallet">
 | 
			
		||||
        <img class="image" src="/resources/profile/blixt.png" />
 | 
			
		||||
        <span>Blixt</span>
 | 
			
		||||
 | 
			
		||||
@ -43,7 +43,6 @@
 | 
			
		||||
  .alliances,
 | 
			
		||||
  .enterprise-sponsor,
 | 
			
		||||
  .community-integrations-sponsor,
 | 
			
		||||
  .selfhosted-integrations-sponsor,
 | 
			
		||||
  .maintainers {
 | 
			
		||||
    margin-top: 68px;
 | 
			
		||||
    margin-bottom: 68px;
 | 
			
		||||
@ -117,7 +116,6 @@
 | 
			
		||||
  .community-sponsor,
 | 
			
		||||
  .project-translators,
 | 
			
		||||
  .community-integrations-sponsor,
 | 
			
		||||
  .selfhosted-integrations-sponsor,
 | 
			
		||||
  .maintainers {
 | 
			
		||||
    .wrapper {
 | 
			
		||||
      display: inline-block;
 | 
			
		||||
@ -193,6 +191,6 @@
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.community-integrations-sponsor {
 | 
			
		||||
  max-width: 830px;
 | 
			
		||||
  max-width: 970px;
 | 
			
		||||
  margin: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,7 @@
 | 
			
		||||
<div class="box preview-box" *ngIf="address && !error">
 | 
			
		||||
  <h2 class="preview-header" i18n="shared.address">Address</h2>
 | 
			
		||||
  <app-preview-title>
 | 
			
		||||
    <span i18n="shared.address">Address</span>
 | 
			
		||||
  </app-preview-title>
 | 
			
		||||
  <div class="row">
 | 
			
		||||
    <div class="col-md">
 | 
			
		||||
      <div class="row d-flex justify-content-between">
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
<div class="block-overview-graph">
 | 
			
		||||
  <canvas class="block-overview-canvas" [class.clickable]="!!hoverTx" #blockCanvas></canvas>
 | 
			
		||||
  <div class="loader-wrapper" [class.hidden]="!isLoading">
 | 
			
		||||
  <div class="loader-wrapper" [class.hidden]="!isLoading || disableSpinner">
 | 
			
		||||
    <div class="spinner-border ml-3 loading" role="status"></div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy {
 | 
			
		||||
  @Input() blockLimit: number;
 | 
			
		||||
  @Input() orientation = 'left';
 | 
			
		||||
  @Input() flip = true;
 | 
			
		||||
  @Input() disableSpinner = false;
 | 
			
		||||
  @Output() txClickEvent = new EventEmitter<TransactionStripped>();
 | 
			
		||||
  @Output() readyEvent = new EventEmitter();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,7 @@
 | 
			
		||||
<div class="box preview-box" *ngIf="!error">
 | 
			
		||||
  <h2 class="preview-header" i18n="shared.block-title">Block</h2>
 | 
			
		||||
  <app-preview-title>
 | 
			
		||||
    <span i18n="shared.block-title">Block</span>
 | 
			
		||||
  </app-preview-title>
 | 
			
		||||
  <div class="row">
 | 
			
		||||
    <div class="col-sm">
 | 
			
		||||
      <div class="row d-flex justify-content-between">
 | 
			
		||||
@ -10,7 +12,7 @@
 | 
			
		||||
          </h1>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <a class="subtitle truncated" [routerLink]="['/block/' | relativeUrl, blockHash]"><span class="first">{{blockHash.slice(0,-4)}}</span><span class="last-four">{{blockHash.slice(-4)}}</span></a>
 | 
			
		||||
      <a class="subtitle truncated" [routerLink]="['/block/' | relativeUrl, blockHash]" *ngIf="blockHash"><span class="first">{{blockHash.slice(0,-4)}}</span><span class="last-four">{{blockHash.slice(-4)}}</span></a>
 | 
			
		||||
      <table class="table table-borderless table-striped">
 | 
			
		||||
        <tbody>
 | 
			
		||||
          <!-- <tr>
 | 
			
		||||
@ -70,6 +72,7 @@
 | 
			
		||||
        [blockLimit]="stateService.blockVSize"
 | 
			
		||||
        [orientation]="'top'"
 | 
			
		||||
        [flip]="false"
 | 
			
		||||
        [disableSpinner]="true"
 | 
			
		||||
        (readyEvent)="onGraphReady()"
 | 
			
		||||
      ></app-block-overview-graph>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
@ -10,8 +10,8 @@
 | 
			
		||||
      <span *ngSwitchCase="'signet'" class="network signet"><app-svg-images name="signet" width="35" height="35" viewBox="0 0 65 65" style="width: 40px; height: 48px;" class="mainnet mr-1"></app-svg-images> Signet</span>
 | 
			
		||||
      <span *ngSwitchCase="'testnet'" class="network testnet"><app-svg-images name="testnet" width="35" height="35" viewBox="0 0 65 65" style="width: 40px; height: 48px;" class="mainnet mr-1"></app-svg-images> Testnet</span>
 | 
			
		||||
      <span *ngSwitchCase="'bisq'" class="network bisq"><app-svg-images name="bisq" width="35" height="35" viewBox="0 0 75 75" style="width: 40px; height: 48px;" class="mainnet mr-1"></app-svg-images> Bisq</span>
 | 
			
		||||
      <span *ngSwitchCase="'liquid'" class="network liquid"><app-svg-images name="liquid" width="35" height="35" viewBox="0 0 125 125" style="width: 40px; height: 48px;" class="mainnet mr-1"></app-svg-images> Liquid</span>
 | 
			
		||||
      <span *ngSwitchCase="'liquidtestnet'" class="network liquidtestnet"><app-svg-images name="liquidtestnet" width="35" height="35" viewBox="0 0 125 125" style="width: 40px; height: 48px;" class="mainnet mr-1"></app-svg-images> Liquid Testnet</span>
 | 
			
		||||
      <span *ngSwitchCase="'liquid'" class="network liquid"><app-svg-images name="liquid" width="35" height="35" viewBox="0 0 125 125" style="width: 40px; height: 48px;" class="mainnet mr-1"></app-svg-images> Mainnet</span>
 | 
			
		||||
      <span *ngSwitchCase="'liquidtestnet'" class="network liquidtestnet"><app-svg-images name="liquidtestnet" width="35" height="35" viewBox="0 0 125 125" style="width: 40px; height: 48px;" class="mainnet mr-1"></app-svg-images> Testnet</span>
 | 
			
		||||
      <span *ngSwitchDefault class="network mainnet"><app-svg-images name="bitcoin" width="35" height="35" viewBox="0 0 65 65" style="width: 40px; height: 48px;" class="mainnet mr-1"></app-svg-images> Mainnet</span>
 | 
			
		||||
    </div>
 | 
			
		||||
  </header>
 | 
			
		||||
 | 
			
		||||
@ -47,6 +47,7 @@
 | 
			
		||||
    z-index: 101;
 | 
			
		||||
    line-height: 80px;
 | 
			
		||||
    text-transform: capitalize;
 | 
			
		||||
    font-size: 2.4rem;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::ng-deep .title {
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,11 @@
 | 
			
		||||
<h2 class="preview-header">
 | 
			
		||||
  <ng-container *ngIf="{ val: network$ | async } as network">
 | 
			
		||||
    <ng-container [ngSwitch]="network.val">
 | 
			
		||||
      <span *ngSwitchCase="'bisq'">Bisq </span>
 | 
			
		||||
      <span *ngSwitchCase="'liquid'">Liquid </span>
 | 
			
		||||
      <span *ngSwitchCase="'liquidtestnet'">Liquid </span>
 | 
			
		||||
      <span *ngSwitchDefault>Bitcoin </span>
 | 
			
		||||
    </ng-container>
 | 
			
		||||
  </ng-container>
 | 
			
		||||
  <ng-content></ng-content>
 | 
			
		||||
</h2>
 | 
			
		||||
@ -0,0 +1,20 @@
 | 
			
		||||
import { Component, OnInit } from '@angular/core';
 | 
			
		||||
import { StateService } from '../../services/state.service';
 | 
			
		||||
import { Observable, merge, of } from 'rxjs';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-preview-title',
 | 
			
		||||
  templateUrl: './preview-title.component.html',
 | 
			
		||||
  styleUrls: [],
 | 
			
		||||
})
 | 
			
		||||
export class PreviewTitleComponent implements OnInit {
 | 
			
		||||
  network$: Observable<string>;
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    public stateService: StateService,
 | 
			
		||||
  ) { }
 | 
			
		||||
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
    this.network$ = merge(of(''), this.stateService.networkChanged$);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,5 +1,7 @@
 | 
			
		||||
<div class="box preview-box" *ngIf="tx && !error">
 | 
			
		||||
  <h2 class="preview-header" i18n="shared.transaction">Transaction</h2>
 | 
			
		||||
  <app-preview-title>
 | 
			
		||||
    <span i18n="shared.transaction">Transaction</span>
 | 
			
		||||
  </app-preview-title>
 | 
			
		||||
  <div class="row d-flex justify-content-between full-width-row">
 | 
			
		||||
    <div class="title-wrapper">
 | 
			
		||||
      <h1 class="title truncated"><span class="first">{{txId.slice(0,-4)}}</span><span class="last-four">{{txId.slice(-4)}}</span></h1>
 | 
			
		||||
 | 
			
		||||
@ -87,29 +87,37 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
 | 
			
		||||
        // assume confidential inputs/outputs have the same average value as the known ones
 | 
			
		||||
        const adjustedTotalInput = totalInput + ((totalInput / knownInputCount) * confidentialInputCount);
 | 
			
		||||
        const adjustedTotalOutput = totalOutput + ((totalOutput / knownOutputCount) * confidentialOutputCount);
 | 
			
		||||
        return Math.max(adjustedTotalInput, adjustedTotalOutput) || 1;
 | 
			
		||||
        return Math.max(adjustedTotalInput, adjustedTotalOutput);
 | 
			
		||||
      } else {
 | 
			
		||||
        // otherwise knowing the actual total of one side suffices
 | 
			
		||||
        return Math.max(totalInput, totalOutput) || 1;
 | 
			
		||||
        return Math.max(totalInput, totalOutput);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  initLines(side: 'in' | 'out', xputs: { type: string, value: number | void }[], total: number, maxVisibleStrands: number): SvgLine[] {
 | 
			
		||||
    const lines = [];
 | 
			
		||||
    let unknownCount = 0;
 | 
			
		||||
    let unknownTotal = total == null ? this.combinedWeight : total;
 | 
			
		||||
    xputs.forEach(put => {
 | 
			
		||||
      if (put.value == null) {
 | 
			
		||||
        unknownCount++;
 | 
			
		||||
      } else {
 | 
			
		||||
        unknownTotal -= put.value as number;
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    const unknownShare = unknownTotal / unknownCount;
 | 
			
		||||
    if (!total) {
 | 
			
		||||
      const weights = xputs.map((put): number => this.combinedWeight / xputs.length);
 | 
			
		||||
      return this.linesFromWeights(side, xputs, weights, maxVisibleStrands);
 | 
			
		||||
    } else {
 | 
			
		||||
      let unknownCount = 0;
 | 
			
		||||
      let unknownTotal = total;
 | 
			
		||||
      xputs.forEach(put => {
 | 
			
		||||
        if (put.value == null) {
 | 
			
		||||
          unknownCount++;
 | 
			
		||||
        } else {
 | 
			
		||||
          unknownTotal -= put.value as number;
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
      const unknownShare = unknownTotal / unknownCount;
 | 
			
		||||
      // conceptual weights
 | 
			
		||||
      const weights = xputs.map((put): number => this.combinedWeight * (put.value == null ? unknownShare : put.value as number) / total);
 | 
			
		||||
      return this.linesFromWeights(side, xputs, weights, maxVisibleStrands);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
    // conceptual weights
 | 
			
		||||
    const weights = xputs.map((put): number => this.combinedWeight * (put.value == null ? unknownShare : put.value as number) / total);
 | 
			
		||||
  linesFromWeights(side: 'in' | 'out', xputs: { type: string, value: number | void }[], weights: number[], maxVisibleStrands: number) {
 | 
			
		||||
    const lines = [];
 | 
			
		||||
    // actual displayed line thicknesses
 | 
			
		||||
    const minWeights = weights.map((w) => Math.max(this.minWeight - 1, w) + 1);
 | 
			
		||||
    const visibleStrands = Math.min(maxVisibleStrands, xputs.length);
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,7 @@
 | 
			
		||||
<div class="box preview-box" *ngIf="(channel$ | async) as channel">
 | 
			
		||||
  <h2 class="preview-header" i18n="lightning.channel">lightning channel</h2>
 | 
			
		||||
  <app-preview-title>
 | 
			
		||||
    <span i18n="lightning.channel">lightning channel</span>
 | 
			
		||||
  </app-preview-title>
 | 
			
		||||
  <div class="row d-flex justify-content-between full-width-row">
 | 
			
		||||
    <div class="title-wrapper">
 | 
			
		||||
      <h1 class="title">{{ channel.short_id }}</h1>
 | 
			
		||||
@ -49,7 +51,7 @@
 | 
			
		||||
      </table>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="col-md map-col">
 | 
			
		||||
      <app-nodes-channels-map *ngIf="!error" [style]="'channelpage'" [channel]="channelGeo" [fitContainer]="true" [placeholder]="true" (readyEvent)="onMapReady()"></app-nodes-channels-map>
 | 
			
		||||
      <app-nodes-channels-map *ngIf="!error" [style]="'channelpage'" [channel]="channelGeo" [fitContainer]="true" [placeholder]="true" [disableSpinner]="true" (readyEvent)="onMapReady()"></app-nodes-channels-map>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="row d-flex justify-content-between full-width-row nodes">
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,8 @@
 | 
			
		||||
 | 
			
		||||
  <div class="clearfix"></div>
 | 
			
		||||
 | 
			
		||||
  <app-nodes-channels-map *ngIf="!error && (channelGeo$ | async) as channelGeo" [style]="'channelpage'" [channel]="channelGeo"></app-nodes-channels-map>
 | 
			
		||||
  <app-nodes-channels-map *ngIf="!error && (channelGeo$ | async) as channelGeo" [style]="'channelpage'"
 | 
			
		||||
    [channel]="channelGeo"></app-nodes-channels-map>
 | 
			
		||||
 | 
			
		||||
  <div class="box">
 | 
			
		||||
 | 
			
		||||
@ -51,38 +52,42 @@
 | 
			
		||||
          </table>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <br>
 | 
			
		||||
 | 
			
		||||
  <div class="row row-cols-1 row-cols-md-2">
 | 
			
		||||
    <div class="col">
 | 
			
		||||
      <app-channel-box [channel]="channel.node_left"></app-channel-box>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <div class="row row-cols-1 row-cols-md-2">
 | 
			
		||||
      <div class="col">
 | 
			
		||||
        <app-channel-box [channel]="channel.node_left"></app-channel-box>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="col">
 | 
			
		||||
        <app-channel-box [channel]="channel.node_right"></app-channel-box>
 | 
			
		||||
      </div>
 | 
			
		||||
    <div class="col">
 | 
			
		||||
      <app-channel-box [channel]="channel.node_right"></app-channel-box>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
    <br>
 | 
			
		||||
  <br>
 | 
			
		||||
 | 
			
		||||
    <ng-container *ngIf="transactions$ | async as transactions">
 | 
			
		||||
      <ng-template [ngIf]="transactions[0]">
 | 
			
		||||
        <div class="d-flex">
 | 
			
		||||
          <h3>Opening transaction</h3>
 | 
			
		||||
          <button type="button" class="btn btn-outline-info details-button btn-sm" (click)="txList1.toggleDetails()" i18n="transaction.details|Transaction Details">Details</button>
 | 
			
		||||
        </div>
 | 
			
		||||
        <app-transactions-list #txList1 [transactions]="[transactions[0]]" [showConfirmations]="true" [rowLimit]="5"></app-transactions-list>
 | 
			
		||||
      </ng-template>
 | 
			
		||||
      <ng-template [ngIf]="transactions[1]">
 | 
			
		||||
        <div class="closing-header d-flex">
 | 
			
		||||
          <h3 style="margin: 0;">Closing transaction</h3>  <app-closing-type [type]="channel.closing_reason"></app-closing-type>
 | 
			
		||||
          <button type="button" class="btn btn-outline-info details-button btn-sm" (click)="txList2.toggleDetails()" i18n="transaction.details|Transaction Details">Details</button>
 | 
			
		||||
        </div>
 | 
			
		||||
        <app-transactions-list #txList2 [transactions]="[transactions[1]]" [showConfirmations]="true" [rowLimit]="5"></app-transactions-list>
 | 
			
		||||
      </ng-template>
 | 
			
		||||
    </ng-container>
 | 
			
		||||
  <ng-container *ngIf="transactions$ | async as transactions">
 | 
			
		||||
    <ng-template [ngIf]="transactions[0]">
 | 
			
		||||
      <div class="d-flex">
 | 
			
		||||
        <h3>Opening transaction</h3>
 | 
			
		||||
        <button type="button" class="btn btn-outline-info details-button btn-sm" (click)="txList1.toggleDetails()"
 | 
			
		||||
          i18n="transaction.details|Transaction Details">Details</button>
 | 
			
		||||
      </div>
 | 
			
		||||
      <app-transactions-list #txList1 [transactions]="[transactions[0]]" [showConfirmations]="true" [rowLimit]="5">
 | 
			
		||||
      </app-transactions-list>
 | 
			
		||||
    </ng-template>
 | 
			
		||||
    <ng-template [ngIf]="transactions[1]">
 | 
			
		||||
      <div class="closing-header d-flex">
 | 
			
		||||
        <h3 style="margin: 0;">Closing transaction</h3>  <app-closing-type [type]="channel.closing_reason">
 | 
			
		||||
        </app-closing-type>
 | 
			
		||||
        <button type="button" class="btn btn-outline-info details-button btn-sm" (click)="txList2.toggleDetails()"
 | 
			
		||||
          i18n="transaction.details|Transaction Details">Details</button>
 | 
			
		||||
      </div>
 | 
			
		||||
      <app-transactions-list #txList2 [transactions]="[transactions[1]]" [showConfirmations]="true" [rowLimit]="5">
 | 
			
		||||
      </app-transactions-list>
 | 
			
		||||
    </ng-template>
 | 
			
		||||
  </ng-container>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -21,7 +21,7 @@ export class LightningDashboardComponent implements OnInit {
 | 
			
		||||
  ) { }
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    this.seoService.setTitle($localize`Lightning Dashboard`);
 | 
			
		||||
    this.seoService.setTitle($localize`Lightning Network`);
 | 
			
		||||
 | 
			
		||||
    this.nodesRanking$ = this.lightningApiService.getNodesRanking$().pipe(share());
 | 
			
		||||
    this.statistics$ = this.lightningApiService.getLatestStatistics$().pipe(share());
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,7 @@
 | 
			
		||||
<div class="box preview-box" *ngIf="(node$ | async) as node">
 | 
			
		||||
  <h2 class="preview-header" i18n="lightning.node">lightning node</h2>
 | 
			
		||||
  <app-preview-title>
 | 
			
		||||
    <span i18n="lightning.node">lightning node</span>
 | 
			
		||||
  </app-preview-title>
 | 
			
		||||
  <div class="row d-flex justify-content-between full-width-row">
 | 
			
		||||
    <h1 class="title"></h1>
 | 
			
		||||
    <div class="title-wrapper">
 | 
			
		||||
@ -54,7 +56,7 @@
 | 
			
		||||
      </table>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="col-md map-col">
 | 
			
		||||
      <app-nodes-channels-map *ngIf="!error" [style]="'nodepage'" [publicKey]="node.public_key" [fitContainer]="true" [placeholder]="true" [hasLocation]="!!node.as_number" (readyEvent)="onMapReady()"></app-nodes-channels-map>
 | 
			
		||||
      <app-nodes-channels-map *ngIf="!error" [style]="'nodepage'" [publicKey]="node.public_key" [fitContainer]="true" [placeholder]="true" [hasLocation]="!!node.as_number" [disableSpinner]="true" (readyEvent)="onMapReady()"></app-nodes-channels-map>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
@ -44,11 +44,14 @@
 | 
			
		||||
                <app-fiat [value]="node.avgCapacity" digitsInfo="1.0-0"></app-fiat>
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr *ngIf="node.geolocation">
 | 
			
		||||
            <tr>
 | 
			
		||||
              <td i18n="location" class="text-truncate">Location</td>
 | 
			
		||||
              <td>
 | 
			
		||||
              <td *ngIf="node.geolocation">
 | 
			
		||||
                <app-geolocation [data]="node.geolocation" [type]="'node'"></app-geolocation>
 | 
			
		||||
              </td>
 | 
			
		||||
              <td *ngIf="!node.geolocation">
 | 
			
		||||
                <span i18n="unknown">Unknown</span>
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
          </tbody>
 | 
			
		||||
        </table>
 | 
			
		||||
@ -75,13 +78,16 @@
 | 
			
		||||
                <div [ngStyle]="{'color': node.color}">{{ node.color }}</div>
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr *ngIf="node.country">
 | 
			
		||||
            <tr>
 | 
			
		||||
              <td i18n="isp" class="text-truncate label">ISP</td>
 | 
			
		||||
              <td>
 | 
			
		||||
              <td *ngIf="node.as_number">
 | 
			
		||||
                <a class="d-block text-wrap" [routerLink]="['/lightning/nodes/isp' | relativeUrl, node.as_number]">
 | 
			
		||||
                  {{ node.as_organization }} [ASN {{node.as_number}}]
 | 
			
		||||
                </a>                
 | 
			
		||||
              </td>
 | 
			
		||||
              <td *ngIf="!node.as_number">
 | 
			
		||||
                <span class="badge badge-success" placement="bottom" i18n="tor">Exclusively on Tor</span>
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
          </tbody>
 | 
			
		||||
        </table>
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,7 @@
 | 
			
		||||
      <div *ngIf="!chartOptions && style === 'nodepage'" style="padding-top: 30px"></div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="text-center loading-spinner" [class]="style" *ngIf="isLoading">
 | 
			
		||||
    <div class="text-center loading-spinner" [class]="style" *ngIf="isLoading && !disableSpinner">
 | 
			
		||||
      <div class="spinner-border text-light"></div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </ng-container>
 | 
			
		||||
 | 
			
		||||
@ -23,6 +23,7 @@ export class NodesChannelsMap implements OnInit {
 | 
			
		||||
  @Input() fitContainer = false;
 | 
			
		||||
  @Input() hasLocation = true;
 | 
			
		||||
  @Input() placeholder = false;
 | 
			
		||||
  @Input() disableSpinner = false;
 | 
			
		||||
  @Output() readyEvent = new EventEmitter();
 | 
			
		||||
 | 
			
		||||
  channelsObservable: Observable<any>; 
 | 
			
		||||
 | 
			
		||||
@ -1,13 +1,13 @@
 | 
			
		||||
<div class="full-container">
 | 
			
		||||
<div class="full-container" [class]="widget ? 'widget' : ''">
 | 
			
		||||
 | 
			
		||||
  <div class="card-header">
 | 
			
		||||
  <div *ngIf="!widget" class="card-header">
 | 
			
		||||
    <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>
 | 
			
		||||
    </div>
 | 
			
		||||
    <small style="color: #ffffff66" i18n="lightning.tor-nodes-excluded">(Tor nodes excluded)</small>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div *ngIf="observable$ | async" class="chart" echarts [initOpts]="chartInitOptions" [options]="chartOptions"
 | 
			
		||||
  <div *ngIf="observable$ | async" class="chart" [class]="widget ? 'widget' : ''" echarts [initOpts]="chartInitOptions" [options]="chartOptions"
 | 
			
		||||
    (chartInit)="onChartInit($event)">
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,11 @@
 | 
			
		||||
    padding-bottom: 100px;
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
.full-container.widget {
 | 
			
		||||
  min-height: 240px;
 | 
			
		||||
  height: 240px;
 | 
			
		||||
  padding: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.chart {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
@ -38,3 +43,6 @@
 | 
			
		||||
    padding-bottom: 55px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
.chart.widget {
 | 
			
		||||
  padding: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
import { ChangeDetectionStrategy, Component, Inject, LOCALE_ID, NgZone, OnDestroy, OnInit } from '@angular/core';
 | 
			
		||||
import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, NgZone, OnDestroy, OnInit } from '@angular/core';
 | 
			
		||||
import { SeoService } from 'src/app/services/seo.service';
 | 
			
		||||
import { ApiService } from 'src/app/services/api.service';
 | 
			
		||||
import { Observable, tap, zip } from 'rxjs';
 | 
			
		||||
@ -18,6 +18,10 @@ import { getFlagEmoji } from 'src/app/shared/common.utils';
 | 
			
		||||
  changeDetection: ChangeDetectionStrategy.OnPush,
 | 
			
		||||
})
 | 
			
		||||
export class NodesMap implements OnInit {
 | 
			
		||||
  @Input() widget: boolean = false;
 | 
			
		||||
  @Input() nodes: any[] | undefined = undefined;
 | 
			
		||||
  @Input() type: 'none' | 'isp' | 'country' = 'none';
 | 
			
		||||
  
 | 
			
		||||
  observable$: Observable<any>;
 | 
			
		||||
 | 
			
		||||
  chartInstance = undefined;
 | 
			
		||||
@ -43,13 +47,48 @@ export class NodesMap implements OnInit {
 | 
			
		||||
 | 
			
		||||
    this.observable$ = zip(
 | 
			
		||||
      this.assetsService.getWorldMapJson$,
 | 
			
		||||
      this.apiService.getWorldNodes$()
 | 
			
		||||
      this.nodes ? [this.nodes] : this.apiService.getWorldNodes$()
 | 
			
		||||
    ).pipe(tap((data) => {
 | 
			
		||||
      registerMap('world', data[0]);
 | 
			
		||||
 | 
			
		||||
      let maxLiquidity = data[1].maxLiquidity;
 | 
			
		||||
      let inputNodes: any[] = data[1].nodes;
 | 
			
		||||
      let mapCenter: number[] = [0, 5];
 | 
			
		||||
      if (this.type === 'country') {
 | 
			
		||||
        mapCenter = [0, 0];
 | 
			
		||||
      } else if (this.type === 'isp') {
 | 
			
		||||
        mapCenter = [0, 10];
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      let mapZoom = 1.3;
 | 
			
		||||
      if (!inputNodes) {
 | 
			
		||||
        inputNodes = [];
 | 
			
		||||
        for (const node of data[1]) {
 | 
			
		||||
          if (this.type === 'country') {
 | 
			
		||||
            mapCenter[0] += node.longitude;
 | 
			
		||||
            mapCenter[1] += node.latitude;
 | 
			
		||||
          }
 | 
			
		||||
          inputNodes.push([
 | 
			
		||||
            node.longitude,
 | 
			
		||||
            node.latitude,
 | 
			
		||||
            node.public_key,
 | 
			
		||||
            node.alias,
 | 
			
		||||
            node.capacity,
 | 
			
		||||
            node.channels,
 | 
			
		||||
            node.country,
 | 
			
		||||
            node.iso_code,
 | 
			
		||||
          ]);
 | 
			
		||||
          maxLiquidity = Math.max(maxLiquidity ?? 0, node.capacity);
 | 
			
		||||
        }
 | 
			
		||||
        if (this.type === 'country') {
 | 
			
		||||
          mapCenter[0] /= data[1].length;
 | 
			
		||||
          mapCenter[1] /= data[1].length;
 | 
			
		||||
          mapZoom = 6;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const nodes: any[] = [];
 | 
			
		||||
      console.log(data[1].nodes[0]);
 | 
			
		||||
      for (const node of data[1].nodes) {
 | 
			
		||||
      for (const node of inputNodes) {
 | 
			
		||||
        // We add a bit of noise so nodes at the same location are not all
 | 
			
		||||
        // on top of each other
 | 
			
		||||
        const random = Math.random() * 2 * Math.PI;
 | 
			
		||||
@ -66,11 +105,12 @@ export class NodesMap implements OnInit {
 | 
			
		||||
        ]);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.prepareChartOptions(nodes, data[1].maxLiquidity);
 | 
			
		||||
      maxLiquidity = Math.max(1, maxLiquidity);
 | 
			
		||||
      this.prepareChartOptions(nodes, maxLiquidity, mapCenter, mapZoom);
 | 
			
		||||
    }));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  prepareChartOptions(nodes, maxLiquidity) {
 | 
			
		||||
  prepareChartOptions(nodes, maxLiquidity, mapCenter, mapZoom) {
 | 
			
		||||
    let title: object;
 | 
			
		||||
    if (nodes.length === 0) {
 | 
			
		||||
      title = {
 | 
			
		||||
@ -91,8 +131,8 @@ export class NodesMap implements OnInit {
 | 
			
		||||
      geo: {
 | 
			
		||||
        animation: false,
 | 
			
		||||
        silent: true,
 | 
			
		||||
        center: [0, 5],
 | 
			
		||||
        zoom: 1.3,
 | 
			
		||||
        center: mapCenter,
 | 
			
		||||
        zoom: mapZoom,
 | 
			
		||||
        tooltip: {
 | 
			
		||||
          show: false
 | 
			
		||||
        },
 | 
			
		||||
@ -122,10 +162,13 @@ export class NodesMap implements OnInit {
 | 
			
		||||
            return 10 * Math.pow(params[2] / maxLiquidity, 0.2) + 3;
 | 
			
		||||
          },
 | 
			
		||||
          tooltip: {
 | 
			
		||||
            position: function(point, params, dom, rect, size) {
 | 
			
		||||
              return point;
 | 
			
		||||
            },
 | 
			
		||||
            trigger: 'item',
 | 
			
		||||
            show: true,
 | 
			
		||||
            backgroundColor: 'rgba(17, 19, 31, 1)',
 | 
			
		||||
            borderRadius: 4,
 | 
			
		||||
            borderRadius: 0,
 | 
			
		||||
            shadowColor: 'rgba(0, 0, 0, 0.5)',
 | 
			
		||||
            textStyle: {
 | 
			
		||||
              color: '#b1b1b1',
 | 
			
		||||
@ -155,7 +198,6 @@ export class NodesMap implements OnInit {
 | 
			
		||||
            borderColor: 'black',
 | 
			
		||||
            borderWidth: 0,
 | 
			
		||||
          },
 | 
			
		||||
          blendMode: 'lighter',
 | 
			
		||||
          zlevel: 2,
 | 
			
		||||
        },
 | 
			
		||||
      ]
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,58 @@
 | 
			
		||||
<div class="container-xl full-height" style="min-height: 335px">
 | 
			
		||||
  <h1 class="float-left" i18n="lightning.nodes-in-country">
 | 
			
		||||
  <h1 i18n="lightning.nodes-in-country">
 | 
			
		||||
    <span>Lightning nodes in {{ country?.name }}</span>
 | 
			
		||||
    <span style="font-size: 50px; vertical-align:sub;"> {{ country?.flag }}</span>
 | 
			
		||||
  </h1>
 | 
			
		||||
 | 
			
		||||
  <div class="box">
 | 
			
		||||
    <div class="row" *ngIf="nodes$ | async as countryNodes">
 | 
			
		||||
      <div class="col-12 col-md-6">
 | 
			
		||||
        <table class="table table-borderless table-striped">
 | 
			
		||||
          <tbody>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <td i18n="lightning.node-count">Nodes</td>
 | 
			
		||||
              <td>{{ countryNodes.nodes.length }}</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <td i18n="lightning.liquidity">Liquidity</td>
 | 
			
		||||
              <td>
 | 
			
		||||
                <app-amount *ngIf="countryNodes.sumLiquidity > 100000000; else smallnode" [satoshis]="countryNodes.sumLiquidity" [digitsInfo]="'1.2-2'" [noFiat]="false"></app-amount>
 | 
			
		||||
                <ng-template #smallnode>
 | 
			
		||||
                  {{ countryNodes.sumLiquidity | amountShortener: 1 }}
 | 
			
		||||
                  <span class="sats" i18n="shared.sats">sats</span>
 | 
			
		||||
                </ng-template>
 | 
			
		||||
                <span class="d-none d-md-inline-block"> </span>
 | 
			
		||||
                <span class="d-block d-md-none"></span>
 | 
			
		||||
                <app-fiat [value]="countryNodes.sumLiquidity" digitsInfo="1.0-0"></app-fiat>
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <td i18n="lightning.channels">Channels</td>
 | 
			
		||||
              <td>{{ countryNodes.sumChannels }}</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <td i18n="lightning.isp-count">ISP Count</td>
 | 
			
		||||
              <td>{{ countryNodes.ispCount }}</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <td i18n="lightning.top-isp">Top ISP</td>
 | 
			
		||||
              <td class="text-truncate">
 | 
			
		||||
                <a class="d-block text-wrap" [routerLink]="['/lightning/nodes/isp' | relativeUrl, countryNodes.topIsp.id]">
 | 
			
		||||
                  {{ countryNodes.topIsp.name }} [ASN {{ countryNodes.topIsp.id }}]
 | 
			
		||||
                </a>
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
          </tbody>
 | 
			
		||||
        </table>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="col-12 col-md-6 p-3 p-md-0 pr-md-3">
 | 
			
		||||
        <div style="background-color: #181b2d">
 | 
			
		||||
          <app-nodes-map [widget]="true" [nodes]="countryNodes.nodes" type="country"></app-nodes-map>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div style="min-height: 295px">
 | 
			
		||||
    <table class="table table-borderless">
 | 
			
		||||
      
 | 
			
		||||
@ -15,9 +64,8 @@
 | 
			
		||||
        <th class="channels text-right" i18n="lightning.channels">Channels</th>
 | 
			
		||||
        <th class="city text-right" i18n="lightning.location">Location</th>
 | 
			
		||||
      </thead>
 | 
			
		||||
      
 | 
			
		||||
      <tbody *ngIf="nodes$ | async as nodes; else skeleton">
 | 
			
		||||
        <tr *ngFor="let node of nodes; let i= index; trackBy: trackByPublicKey">
 | 
			
		||||
      <tbody *ngIf="nodes$ | async as countryNodes; else skeleton">
 | 
			
		||||
        <tr *ngFor="let node of countryNodes.nodes; let i= index; trackBy: trackByPublicKey">
 | 
			
		||||
          <td class="alias text-left text-truncate">
 | 
			
		||||
            <a [routerLink]="['/lightning/node/' | relativeUrl, node.public_key]">{{ node.alias }}</a>
 | 
			
		||||
          </td>
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
 | 
			
		||||
import { ActivatedRoute } from '@angular/router';
 | 
			
		||||
import { map, Observable } from 'rxjs';
 | 
			
		||||
import { map, Observable, share } from 'rxjs';
 | 
			
		||||
import { ApiService } from 'src/app/services/api.service';
 | 
			
		||||
import { SeoService } from 'src/app/services/seo.service';
 | 
			
		||||
import { getFlagEmoji } from 'src/app/shared/common.utils';
 | 
			
		||||
@ -32,6 +32,8 @@ export class NodesPerCountry implements OnInit {
 | 
			
		||||
    this.nodes$ = this.apiService.getNodeForCountry$(this.route.snapshot.params.country)
 | 
			
		||||
      .pipe(
 | 
			
		||||
        map(response => {
 | 
			
		||||
          this.seoService.setTitle($localize`Lightning nodes in ${response.country.en}`);
 | 
			
		||||
 | 
			
		||||
          this.country = {
 | 
			
		||||
            name: response.country.en,
 | 
			
		||||
            flag: getFlagEmoji(this.route.snapshot.params.country)
 | 
			
		||||
@ -46,13 +48,49 @@ export class NodesPerCountry implements OnInit {
 | 
			
		||||
            };
 | 
			
		||||
          }
 | 
			
		||||
          
 | 
			
		||||
          this.seoService.setTitle($localize`Lightning nodes in ${this.country.name}`);
 | 
			
		||||
          return response.nodes;
 | 
			
		||||
        })
 | 
			
		||||
          const sumLiquidity = response.nodes.reduce((partialSum, a) => partialSum + a.capacity, 0);
 | 
			
		||||
          const sumChannels = response.nodes.reduce((partialSum, a) => partialSum + a.channels, 0);
 | 
			
		||||
          const isps = {};
 | 
			
		||||
          const topIsp = {
 | 
			
		||||
            count: 0,
 | 
			
		||||
            id: '',
 | 
			
		||||
            name: '',
 | 
			
		||||
          };
 | 
			
		||||
          for (const node of response.nodes) {
 | 
			
		||||
            if (!node.isp) {
 | 
			
		||||
              continue;
 | 
			
		||||
            }
 | 
			
		||||
            if (!isps[node.isp]) {
 | 
			
		||||
              isps[node.isp] = {
 | 
			
		||||
                count: 0,
 | 
			
		||||
                asns: [],
 | 
			
		||||
              };
 | 
			
		||||
            }
 | 
			
		||||
            if (isps[node.isp].asns.indexOf(node.as_number) === -1) {
 | 
			
		||||
              isps[node.isp].asns.push(node.as_number);
 | 
			
		||||
            }
 | 
			
		||||
            isps[node.isp].count++;
 | 
			
		||||
            
 | 
			
		||||
            if (isps[node.isp].count > topIsp.count) {
 | 
			
		||||
              topIsp.count = isps[node.isp].count;
 | 
			
		||||
              topIsp.id = isps[node.isp].asns.join(',');
 | 
			
		||||
              topIsp.name = node.isp;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          
 | 
			
		||||
          return {
 | 
			
		||||
            nodes: response.nodes,
 | 
			
		||||
            sumLiquidity: sumLiquidity,
 | 
			
		||||
            sumChannels: sumChannels,
 | 
			
		||||
            topIsp: topIsp,
 | 
			
		||||
            ispCount: Object.keys(isps).length
 | 
			
		||||
          };
 | 
			
		||||
        }),
 | 
			
		||||
        share()
 | 
			
		||||
      );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  trackByPublicKey(index: number, node: any) {
 | 
			
		||||
  trackByPublicKey(index: number, node: any): string {
 | 
			
		||||
    return node.public_key;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -10,14 +10,14 @@
 | 
			
		||||
        </p>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="item">
 | 
			
		||||
        <h5 class="card-title d-inline-block">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"
 | 
			
		||||
        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>
 | 
			
		||||
        </p>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="item">
 | 
			
		||||
        <h5 class="card-title d-inline-block">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"
 | 
			
		||||
        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>
 | 
			
		||||
@ -80,19 +80,19 @@
 | 
			
		||||
<ng-template #loadingReward>
 | 
			
		||||
  <div class="pool-distribution">
 | 
			
		||||
    <div class="item">
 | 
			
		||||
      <h5 class="card-title" i18n="lightning.tagged-isp">Tagged ISPs</h5>
 | 
			
		||||
      <h5 class="card-title d-inline-block" i18n="lightning.clearnet-capacity">Clearnet capacity</h5>
 | 
			
		||||
      <p class="card-text">
 | 
			
		||||
        <span class="skeleton-loader skeleton-loader-big"></span>
 | 
			
		||||
      </p>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="item">
 | 
			
		||||
      <h5 class="card-title" i18n="lightning.tagged-capacity">Tagged capacity</h5>
 | 
			
		||||
      <h5 class="card-title d-inline-block" i18n="lightning.unknown-capacity">Unknown capacity</h5>
 | 
			
		||||
      <p class="card-text">
 | 
			
		||||
        <span class="skeleton-loader skeleton-loader-big"></span>
 | 
			
		||||
      </p>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="item">
 | 
			
		||||
      <h5 class="card-title" i18n="lightning.tagged-nodes">Tagged nodes</h5>
 | 
			
		||||
      <h5 class="card-title d-inline-block" i18n="lightning.tor-capacity">Tor capacity</h5>
 | 
			
		||||
      <p class="card-text">
 | 
			
		||||
        <span class="skeleton-loader skeleton-loader-big"></span>
 | 
			
		||||
      </p>
 | 
			
		||||
 | 
			
		||||
@ -134,9 +134,6 @@ export class NodesPerISPChartComponent implements OnInit {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      data.push({
 | 
			
		||||
        itemStyle: {
 | 
			
		||||
          color: isp[0] === null ? '#7D4698' : undefined,
 | 
			
		||||
        },
 | 
			
		||||
        value: this.sortBy === 'capacity' ? isp[7] : isp[6],
 | 
			
		||||
        name: isp[1].replace('&', '') + (isMobile() || this.widget ? `` : ` (${this.sortBy === 'capacity' ? isp[7] : isp[6]}%)`),
 | 
			
		||||
        label: {
 | 
			
		||||
@ -206,7 +203,7 @@ export class NodesPerISPChartComponent implements OnInit {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.chartOptions = {
 | 
			
		||||
      color: chartColors.slice(3),
 | 
			
		||||
      color: chartColors.filter((color) => color != '#5E35B1'), // Remove color that looks like Tor
 | 
			
		||||
      tooltip: {
 | 
			
		||||
        trigger: 'item',
 | 
			
		||||
        textStyle: {
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,54 @@
 | 
			
		||||
<div class="container-xl full-height" style="min-height: 335px">
 | 
			
		||||
  <h1 class="float-left" i18n="lightning.nodes-for-isp">Lightning nodes on ISP: {{ isp?.name }} [AS {{isp?.id}}]</h1>
 | 
			
		||||
  <h1 i18n="lightning.nodes-for-isp">Lightning nodes on ISP: {{ isp?.name }}</h1>
 | 
			
		||||
 | 
			
		||||
  <div class="box">
 | 
			
		||||
    <div class="row" *ngIf="nodes$ | async as ispNodes">
 | 
			
		||||
      <div class="col-12 col-md-6">
 | 
			
		||||
        <table class="table table-borderless table-striped">
 | 
			
		||||
          <tbody>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <td i18n="lightning.asn">ASN</td>
 | 
			
		||||
              <td>{{ isp?.id }}</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <td i18n="lightning.node-count">Nodes</td>
 | 
			
		||||
              <td>{{ ispNodes.nodes.length }}</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <td i18n="lightning.liquidity">Liquidity</td>
 | 
			
		||||
              <td>
 | 
			
		||||
                <app-amount *ngIf="ispNodes.sumLiquidity > 100000000; else smallnode" [satoshis]="ispNodes.sumLiquidity" [digitsInfo]="'1.2-2'" [noFiat]="false"></app-amount>
 | 
			
		||||
                <ng-template #smallnode>
 | 
			
		||||
                  {{ ispNodes.sumLiquidity | amountShortener: 1 }}
 | 
			
		||||
                  <span class="sats" i18n="shared.sats">sats</span>
 | 
			
		||||
                </ng-template>
 | 
			
		||||
                <span class="d-none d-md-inline-block"> </span>
 | 
			
		||||
                <span class="d-block d-md-none"></span>
 | 
			
		||||
                <app-fiat [value]="ispNodes.sumLiquidity" digitsInfo="1.0-0"></app-fiat>
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <td i18n="lightning.channels">Channels</td>
 | 
			
		||||
              <td>{{ ispNodes.sumChannels }}</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <td i18n="lightning.top-country">Top country</td>
 | 
			
		||||
              <td class="text-truncate">
 | 
			
		||||
                <a class="d-block text-wrap" [routerLink]="['/lightning/nodes/country' | relativeUrl, ispNodes.topCountry.iso]">
 | 
			
		||||
                  <span class="">{{ ispNodes.topCountry.country }} {{ ispNodes.topCountry.flag }}</span>
 | 
			
		||||
                </a>
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
          </tbody>
 | 
			
		||||
        </table>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="col-12 col-md-6 p-3 p-md-0 pr-md-3">
 | 
			
		||||
        <div style="background-color: #181b2d">
 | 
			
		||||
          <app-nodes-map [widget]="true" [nodes]="ispNodes.nodes" type="isp"></app-nodes-map>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div style="min-height: 295px">
 | 
			
		||||
    <table class="table table-borderless">
 | 
			
		||||
@ -12,9 +61,8 @@
 | 
			
		||||
        <th class="channels text-right" i18n="lightning.channels">Channels</th>
 | 
			
		||||
        <th class="city text-right" i18n="lightning.location">Location</th>
 | 
			
		||||
      </thead>
 | 
			
		||||
 | 
			
		||||
      <tbody *ngIf="nodes$ | async as nodes; else skeleton">
 | 
			
		||||
        <tr *ngFor="let node of nodes; let i= index; trackBy: trackByPublicKey">
 | 
			
		||||
      <tbody *ngIf="nodes$ | async as ispNodes; else skeleton">
 | 
			
		||||
        <tr *ngFor="let node of ispNodes.nodes; let i= index; trackBy: trackByPublicKey">
 | 
			
		||||
          <td class="alias text-left text-truncate">
 | 
			
		||||
            <a [routerLink]="['/lightning/node/' | relativeUrl, node.public_key]">{{ node.alias }}</a>
 | 
			
		||||
          </td>
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,9 @@
 | 
			
		||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
 | 
			
		||||
import { ActivatedRoute } from '@angular/router';
 | 
			
		||||
import { map, Observable } from 'rxjs';
 | 
			
		||||
import { map, Observable, share } from 'rxjs';
 | 
			
		||||
import { ApiService } from 'src/app/services/api.service';
 | 
			
		||||
import { SeoService } from 'src/app/services/seo.service';
 | 
			
		||||
import { getFlagEmoji } from 'src/app/shared/common.utils';
 | 
			
		||||
import { GeolocationData } from 'src/app/shared/components/geolocation/geolocation.component';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
@ -33,7 +34,7 @@ export class NodesPerISP implements OnInit {
 | 
			
		||||
        map(response => {
 | 
			
		||||
          this.isp = {
 | 
			
		||||
            name: response.isp,
 | 
			
		||||
            id: this.route.snapshot.params.isp
 | 
			
		||||
            id: this.route.snapshot.params.isp.split(',').join(', ')
 | 
			
		||||
          };
 | 
			
		||||
          this.seoService.setTitle($localize`Lightning nodes on ISP: ${response.isp} [AS${this.route.snapshot.params.isp}]`);
 | 
			
		||||
 | 
			
		||||
@ -46,12 +47,40 @@ export class NodesPerISP implements OnInit {
 | 
			
		||||
            };
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          return response.nodes;
 | 
			
		||||
        })
 | 
			
		||||
          const sumLiquidity = response.nodes.reduce((partialSum, a) => partialSum + a.capacity, 0);
 | 
			
		||||
          const sumChannels = response.nodes.reduce((partialSum, a) => partialSum + a.channels, 0);
 | 
			
		||||
          const countries = {};
 | 
			
		||||
          const topCountry = {
 | 
			
		||||
            count: 0,
 | 
			
		||||
            country: '',
 | 
			
		||||
            iso: '',
 | 
			
		||||
            flag: '',
 | 
			
		||||
          };
 | 
			
		||||
          for (const node of response.nodes) {
 | 
			
		||||
            if (!node.geolocation.iso) {
 | 
			
		||||
              continue;
 | 
			
		||||
            }
 | 
			
		||||
            countries[node.geolocation.iso] = countries[node.geolocation.iso] ?? 0 + 1;
 | 
			
		||||
            if (countries[node.geolocation.iso] > topCountry.count) {
 | 
			
		||||
              topCountry.count = countries[node.geolocation.iso];
 | 
			
		||||
              topCountry.country = node.geolocation.country;
 | 
			
		||||
              topCountry.iso = node.geolocation.iso;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          topCountry.flag = getFlagEmoji(topCountry.iso);
 | 
			
		||||
          
 | 
			
		||||
          return {
 | 
			
		||||
            nodes: response.nodes,
 | 
			
		||||
            sumLiquidity: sumLiquidity,
 | 
			
		||||
            sumChannels: sumChannels,
 | 
			
		||||
            topCountry: topCountry,
 | 
			
		||||
          };
 | 
			
		||||
        }),
 | 
			
		||||
        share()
 | 
			
		||||
      );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  trackByPublicKey(index: number, node: any) {
 | 
			
		||||
  trackByPublicKey(index: number, node: any): string {
 | 
			
		||||
    return node.public_key;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,7 @@ import { faFilter, faAngleDown, faAngleUp, faAngleRight, faAngleLeft, faBolt, fa
 | 
			
		||||
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
 | 
			
		||||
import { MasterPageComponent } from '../components/master-page/master-page.component';
 | 
			
		||||
import { MasterPagePreviewComponent } from '../components/master-page-preview/master-page-preview.component';
 | 
			
		||||
import { PreviewTitleComponent } from '../components/master-page-preview/preview-title.component';
 | 
			
		||||
import { BisqMasterPageComponent } from '../components/bisq-master-page/bisq-master-page.component';
 | 
			
		||||
import { LiquidMasterPageComponent } from '../components/liquid-master-page/liquid-master-page.component';
 | 
			
		||||
import { AboutComponent } from '../components/about/about.component';
 | 
			
		||||
@ -117,6 +118,7 @@ import { GeolocationComponent } from '../shared/components/geolocation/geolocati
 | 
			
		||||
    AboutComponent,
 | 
			
		||||
    MasterPageComponent,
 | 
			
		||||
    MasterPagePreviewComponent,
 | 
			
		||||
    PreviewTitleComponent,
 | 
			
		||||
    BisqMasterPageComponent,
 | 
			
		||||
    LiquidMasterPageComponent,
 | 
			
		||||
    StartComponent,
 | 
			
		||||
@ -267,6 +269,7 @@ import { GeolocationComponent } from '../shared/components/geolocation/geolocati
 | 
			
		||||
    TimestampComponent,
 | 
			
		||||
    ToggleComponent,
 | 
			
		||||
    GeolocationComponent,
 | 
			
		||||
    PreviewTitleComponent,
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class SharedModule {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								frontend/src/resources/profile/btcpayserver.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								frontend/src/resources/profile/btcpayserver.svg
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 105.46 188.47"><defs><style>.cls-1{fill:#cedc21;}.cls-2{fill:#51b13e;}.cls-3{fill:#1e7a44;}.cls-4{fill:#fff;}</style></defs><title>BTCPayServer</title><path class="cls-1" d="M117.24,247.32a11.06,11.06,0,0,1-11-11.06V69.91a11.06,11.06,0,1,1,22.11,0V236.26A11.06,11.06,0,0,1,117.24,247.32Z" transform="translate(-106.19 -58.85)"/><path class="cls-2" d="M117.25,247.32a11.06,11.06,0,0,1-4.75-21l66.66-31.64L110.69,144.2a11.05,11.05,0,1,1,13.11-17.8l83.35,61.41a11,11,0,0,1-1.82,18.88L122,246.25A10.94,10.94,0,0,1,117.25,247.32Z" transform="translate(-106.19 -58.85)"/><path class="cls-1" d="M117.25,181.93a11.05,11.05,0,0,1-6.56-20l68.47-50.45L112.5,79.89a11.05,11.05,0,0,1,9.48-20l83.35,39.56a11.05,11.05,0,0,1,1.82,18.89L123.8,179.78A11,11,0,0,1,117.25,181.93Z" transform="translate(-106.19 -58.85)"/><polygon class="cls-3" points="22.11 70.86 22.11 117.61 53.82 94.25 22.11 70.86"/><rect class="cls-4" y="51.26" width="22.11" height="53.89"/><path class="cls-1" d="M128.3,69.91a11.06,11.06,0,1,0-22.11,0V209H128.3Z" transform="translate(-106.19 -58.85)"/></svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 1.1 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 19 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								frontend/src/resources/profile/electrum.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								frontend/src/resources/profile/electrum.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 170 KiB  | 
							
								
								
									
										1
									
								
								frontend/src/resources/profile/lnbits.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								frontend/src/resources/profile/lnbits.svg
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><defs><path id="a" d="M33.2619 148.1667h154.2143v68.7917H33.2619z"/></defs><g fill="#1f2234" aria-label="LNbits" font-family="sans-serif" font-size=".3095" font-weight="400" letter-spacing=".0031" style="line-height:1.25;white-space:pre;shape-inside:url(#a)" transform="matrix(72.4607 0 0 72.4607 -2399.2814 -10741.3589)"><g transform="matrix(.00244 0 0 .00244 33.0708 148.1594)"><circle cx="101.2976" cy="116.4167" r="84.6667" fill="#673ab7" fill-rule="evenodd"/><path fill="#eee" d="M79.1105 71.9667v49.0613h13.3803v40.141l31.2208-53.5213h-17.8404l17.8404-35.681z"/></g><g fill="#eee" font-family="roboto"/></g></svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 680 B  | 
@ -4,7 +4,7 @@ var fs = require('fs');
 | 
			
		||||
const CONFIG_FILE_NAME = 'mempool-frontend-config.json';
 | 
			
		||||
let configContent = {};
 | 
			
		||||
 | 
			
		||||
var PATH = 'dist/mempool/browser/en-US/resources/';
 | 
			
		||||
var PATH = 'dist/mempool/browser/resources/';
 | 
			
		||||
if (process.argv[2] && process.argv[2] === 'dev') {
 | 
			
		||||
  PATH = 'src/resources/';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,7 @@
 | 
			
		||||
		expires 10m;
 | 
			
		||||
	}
 | 
			
		||||
	location /resources {
 | 
			
		||||
		try_files /$lang/$uri /$lang/$uri/ $uri $uri/ /en-US/$uri @index-redirect;
 | 
			
		||||
		try_files $uri @index-redirect;
 | 
			
		||||
		expires 1h;
 | 
			
		||||
	}
 | 
			
		||||
	location @index-redirect {
 | 
			
		||||
@ -27,10 +27,6 @@
 | 
			
		||||
 | 
			
		||||
	# location block using regex are matched in order
 | 
			
		||||
 | 
			
		||||
	# used to rewrite resources from /<lang>/ to /en-US/
 | 
			
		||||
	location ~ ^/(ar|bg|bs|ca|cs|da|de|et|el|es|eo|eu|fa|fr|gl|ko|hr|id|it|he|ka|lv|lt|hu|mk|ms|nl|ja|nb|nn|pl|pt|pt-BR|ro|ru|sk|sl|sr|sh|fi|sv|th|tr|uk|vi|zh|hi)/resources/ {
 | 
			
		||||
		rewrite ^/[a-zA-Z-]*/resources/(.*) /en-US/resources/$1;
 | 
			
		||||
	}
 | 
			
		||||
	# used for cookie override
 | 
			
		||||
	location ~ ^/(ar|bg|bs|ca|cs|da|de|et|el|es|eo|eu|fa|fr|gl|ko|hr|id|it|he|ka|lv|lt|hu|mk|ms|nl|ja|nb|nn|pl|pt|pt-BR|ro|ru|sk|sl|sr|sh|fi|sv|th|tr|uk|vi|zh|hi)/ {
 | 
			
		||||
		try_files $uri $uri/ /$1/index.html =404;
 | 
			
		||||
 | 
			
		||||
@ -5,5 +5,5 @@
 | 
			
		||||
37 13 * * * sleep 30 ; /mempool/mempool.space/backup >/dev/null 2>&1 &
 | 
			
		||||
 | 
			
		||||
# hourly liquid asset update
 | 
			
		||||
6 * * * * cd $HOME/liquid/frontend && npm run sync-assets && rsync -av $HOME/liquid/frontend/dist/mempool/browser/en-US/resources/assets* $HOME/public_html/liquid/en-US/resources/ >/dev/null 2>&1
 | 
			
		||||
6 * * * * cd $HOME/liquid/frontend && npm run sync-assets && rsync -av $HOME/liquid/frontend/dist/mempool/browser/resources/assets* $HOME/public_html/liquid/resources/ >/dev/null 2>&1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -58,12 +58,6 @@ location = / {
 | 
			
		||||
	expires 5m;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# used to rewrite resources from /<lang>/ to /en-US/
 | 
			
		||||
# cache /resources/** for 1 week since they don't change often
 | 
			
		||||
location ~ ^/[a-z][a-z]/resources/(.*) {
 | 
			
		||||
	try_files $uri /en-US/resources/$1 =404;
 | 
			
		||||
	expires 1w;
 | 
			
		||||
}
 | 
			
		||||
# cache /<lang>/main.f40e91d908a068a2.js forever since they never change
 | 
			
		||||
location ~ ^/([a-z][a-z])/(.+\..+\.(js|css)) {
 | 
			
		||||
	try_files $uri =404;
 | 
			
		||||
@ -84,7 +78,7 @@ location ~ ^/([a-z][a-z])/ {
 | 
			
		||||
 | 
			
		||||
# cache /resources/** for 1 week since they don't change often
 | 
			
		||||
location /resources {
 | 
			
		||||
	try_files $uri /en-US/$uri /en-US/index.html;
 | 
			
		||||
	try_files $uri /en-US/index.html;
 | 
			
		||||
	expires 1w;
 | 
			
		||||
}
 | 
			
		||||
# cache /main.f40e91d908a068a2.js forever since they never change
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,7 @@
 | 
			
		||||
  "MEMPOOL": {
 | 
			
		||||
    "HTTP_HOST": "http://127.0.0.1",
 | 
			
		||||
    "HTTP_PORT": 83,
 | 
			
		||||
    "NETWORK": "bitcoin"
 | 
			
		||||
    "NETWORK": "liquid"
 | 
			
		||||
  },
 | 
			
		||||
  "PUPPETEER": {
 | 
			
		||||
    "CLUSTER_SIZE": 8,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user