Liquidity Ads List Display Incomplete
Liquidity Ads List Display Incompletepull/1032/head
parent
47011011d9
commit
346e414181
@ -1,10 +1,11 @@
|
||||
import exprs from 'express';
|
||||
const { Router } = exprs;
|
||||
import { isAuthenticated } from '../../utils/authCheck.js';
|
||||
import { getRoute, listNode, listChannel, feeRates } from '../../controllers/cln/network.js';
|
||||
import { getRoute, listNode, listChannel, feeRates, listNodes } from '../../controllers/cln/network.js';
|
||||
const router = Router();
|
||||
router.get('/getRoute/:destPubkey/:amount', isAuthenticated, getRoute);
|
||||
router.get('/listNode/:id', isAuthenticated, listNode);
|
||||
router.get('/listChannel/:channelShortId', isAuthenticated, listChannel);
|
||||
router.get('/feeRates/:feeRateStyle', isAuthenticated, feeRates);
|
||||
router.get('/listNodes', isAuthenticated, listNodes);
|
||||
export default router;
|
||||
|
@ -0,0 +1,127 @@
|
||||
<div fxLayout="row" fxLayoutAlign="start center" class="page-title-container">
|
||||
<fa-icon [icon]="faWater" class="page-title-img mr-1"></fa-icon>
|
||||
<span class="page-title">Liquidity Ads</span>
|
||||
</div>
|
||||
<div fxLayout="column" class="padding-gap-x">
|
||||
<mat-card>
|
||||
<mat-card-content class="padding-gap-large">
|
||||
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch">
|
||||
<form fxLayout="column" fxLayoutAlign="space-between stretch" fxLayout.gt-sm="row wrap" #formAsk="ngForm">
|
||||
<div fxFlex="100" fxLayout="row" class="alert alert-warn">
|
||||
<fa-icon [icon]="faExclamationTriangle" class="mr-1 alert-icon"></fa-icon>
|
||||
<span>Ads should be suplemented with additional research of the nodes, before buying liquidity.</span>
|
||||
</div>
|
||||
<div fxLayout="column" fxLayout.gt-sm="row wrap" fxFlex="100" fxLayoutAlign.gt-sm="space-between center" fxLayoutAlign="start start" class="page-sub-title-container mt-1">
|
||||
<div fxFlex="30">
|
||||
<span class="page-title">
|
||||
Liquidity Ask
|
||||
<mat-icon matTooltip="Tooltip for Liquidity Ask" matTooltipPosition="above" class="info-icon info-icon-primary">info_outline</mat-icon>
|
||||
</span>
|
||||
</div>
|
||||
<mat-form-field fxFlex="34">
|
||||
<input autoFocus matInput placeholder="Channel Amount (Sats)" name="channelAmount" [(ngModel)]="channelAmount" tabindex="1" type="number" step="1000" required>
|
||||
<mat-error *ngIf="!channelAmount">Channel amount is required.</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex="34">
|
||||
<input matInput placeholder="Channel Opening Fee Rate (Sats/vByte)" name="channelOpeningFeeRate" [(ngModel)]="channelOpeningFeeRate" type="number" step="1" tabindex="2" required>
|
||||
<mat-error *ngIf="!channelOpeningFeeRate">Channel opening fee rate is required.</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxLayout="row" class="my-1">
|
||||
<button class="mr-1" mat-stroked-button color="primary" tabindex="3" type="reset" (click)="onReset()">Clear</button>
|
||||
<button mat-flat-button color="primary" (click)="onRecalculate()" tabindex="4" type="submit">Recalculate</button>
|
||||
</div>
|
||||
</form>
|
||||
<mat-divider [inset]="true" class="my-2"></mat-divider>
|
||||
<form fxLayout="column" fxLayoutAlign="space-between stretch" fxLayout.gt-sm="row wrap" #formFilter="ngForm">
|
||||
<div fxLayout="column" fxLayout.gt-sm="row wrap" fxFlex="100" fxLayoutAlign.gt-sm="space-between center" fxLayoutAlign="start start" class="page-sub-title-container mt-1">
|
||||
<div fxFlex="30">
|
||||
<span class="page-title">
|
||||
Nodes Advertising Liquidity
|
||||
<mat-icon matTooltip="Tooltip for Nodes Advertising Liquidity" matTooltipPosition="above" class="info-icon info-icon-primary">info_outline</mat-icon>
|
||||
</span>
|
||||
</div>
|
||||
<mat-form-field fxFlex="34">
|
||||
<input matInput placeholder="Node Capacity (Sats)" name="nodeCapacity" [(ngModel)]="nodeCapacity" tabindex="5" type="number" step="1000" required>
|
||||
<mat-error *ngIf="!nodeCapacity">Node capacity is required.</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex="34">
|
||||
<input matInput placeholder="Channel Count" name="channelCount" [(ngModel)]="channelCount" type="number" step="1" tabindex="6" required>
|
||||
<mat-error *ngIf="!channelCount">Channel count is required.</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxLayout="row" class="my-1">
|
||||
<button class="mr-1" mat-stroked-button color="primary" tabindex="7" type="reset" (click)="onFilterReset()">Clear</button>
|
||||
<button mat-flat-button color="primary" (click)="onFilter()" tabindex="8" type="submit">Filter</button>
|
||||
</div>
|
||||
</form>
|
||||
<div [perfectScrollbar] fxLayout="column" fxLayoutAlign="start center" fxFlex="100" class="table-container">
|
||||
<mat-progress-bar *ngIf="apiCallStatus.status === apiCallStatusEnum.INITIATED" mode="indeterminate"></mat-progress-bar>
|
||||
<table mat-table #table [dataSource]="liquidityNodes" matSort [ngClass]="{'overflow-auto error-border': errorMessage !== '','overflow-auto': true}">
|
||||
<ng-container matColumnDef="alias">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Alias </th>
|
||||
<td mat-cell *matCellDef="let lqNode" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '40rem'}">
|
||||
{{lqNode?.alias}}
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="capacity">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Capacity </th>
|
||||
<td mat-cell *matCellDef="let lqNode"><span fxLayoutAlign="end center">
|
||||
{{lqNode?.option_will_fund?.lease_fee_basis | number:'1.0-0'}} </span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="numChannels">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Channels </th>
|
||||
<td mat-cell *matCellDef="let lqNode"><span fxLayoutAlign="end center">
|
||||
{{lqNode?.option_will_fund?.lease_fee_basis | number:'1.0-0'}} </span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="leaseFeeBasis">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Lease Fee </th>
|
||||
<td mat-cell *matCellDef="let lqNode"><span fxLayoutAlign="end center">
|
||||
{{lqNode?.option_will_fund?.lease_fee_basis | number:'1.0-0'}} </span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="routingFee">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Routing Fee </th>
|
||||
<td mat-cell *matCellDef="let lqNode"><span fxLayoutAlign="end center">
|
||||
{{lqNode?.option_will_fund?.lease_fee_basis | number:'1.0-0'}} </span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="channelOpenFee">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Channel Open Fee </th>
|
||||
<td mat-cell *matCellDef="let lqNode"><span fxLayoutAlign="end center">
|
||||
{{lqNode?.option_will_fund?.lease_fee_basis | number:'1.0-0'}} </span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef class="px-3">
|
||||
<div class="bordered-box table-actions-select">
|
||||
<mat-select placeholder="Actions" tabindex="1" class="mr-0">
|
||||
<mat-select-trigger></mat-select-trigger>
|
||||
<mat-option (click)="onDownloadCSV()">Download CSV</mat-option>
|
||||
</mat-select>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let lqNode" fxLayoutAlign="end center" class="px-3">
|
||||
<div class="bordered-box table-actions-select" fxLayoutAlign="center center">
|
||||
<mat-select placeholder="Actions" tabindex="1" class="mr-0">
|
||||
<mat-select-trigger></mat-select-trigger>
|
||||
<mat-option (click)="onNodeClick(lqNode)">View Info</mat-option>
|
||||
<mat-option (click)="onOpenChannel(lqNode)">Open Channel</mat-option>
|
||||
</mat-select>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="no_lqNode">
|
||||
<td mat-footer-cell *matFooterCellDef colspan="4">
|
||||
<p *ngIf="(!liquidityNodes?.data || liquidityNodes?.data?.length<1) && apiCallStatus.status === apiCallStatusEnum.COMPLETED">No node with liquidity.</p>
|
||||
<p *ngIf="(!liquidityNodes?.data || liquidityNodes?.data?.length<1) && apiCallStatus.status === apiCallStatusEnum.INITIATED">Getting nodes with liquidity...</p>
|
||||
<p *ngIf="(!liquidityNodes?.data || liquidityNodes?.data?.length<1) && apiCallStatus.status === apiCallStatusEnum.ERROR">{{errorMessage}}</p>
|
||||
</td>
|
||||
</ng-container>
|
||||
<tr mat-footer-row *matFooterRowDef="['no_lqNode']" [ngClass]="{'display-none': liquidityNodes?.data && liquidityNodes?.data?.length>0}"></tr>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
</table>
|
||||
</div>
|
||||
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
@ -0,0 +1,10 @@
|
||||
.mat-column-alias {
|
||||
flex: 1 1 20%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.mat-column-actions {
|
||||
min-height: 4.8rem;
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
|
||||
import { DataService } from '../../shared/services/data.service';
|
||||
import { CommonService } from '../../shared/services/common.service';
|
||||
import { mockDataService } from '../../shared/test-helpers/mock-services';
|
||||
|
||||
import { CLNLiquidityAdsComponent } from './liquidity-ads.component';
|
||||
|
||||
describe('CLNLiquidityAdsComponent', () => {
|
||||
let component: CLNLiquidityAdsComponent;
|
||||
let fixture: ComponentFixture<CLNLiquidityAdsComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [CLNLiquidityAdsComponent],
|
||||
imports: [
|
||||
BrowserAnimationsModule,
|
||||
SharedModule
|
||||
],
|
||||
providers: [
|
||||
CommonService,
|
||||
{ provide: DataService, useClass: mockDataService }
|
||||
]
|
||||
}).
|
||||
compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CLNLiquidityAdsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,128 @@
|
||||
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { MatSort } from '@angular/material/sort';
|
||||
import { MatPaginator, MatPaginatorIntl } from '@angular/material/paginator';
|
||||
import { faWater, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
import { DataService } from '../../shared/services/data.service';
|
||||
import { LoggerService } from '../../shared/services/logger.service';
|
||||
import { CommonService } from '../../shared/services/common.service';
|
||||
import { APICallStatusEnum, getPaginatorLabel, PAGE_SIZE, PAGE_SIZE_OPTIONS, ScreenSizeEnum } from '../../shared/services/consts-enums-functions';
|
||||
import { LookupNode } from '../../shared/models/clnModels';
|
||||
import { ApiCallStatusPayload } from '../../shared/models/apiCallsPayload';
|
||||
|
||||
@Component({
|
||||
selector: 'rtl-cln-liquidity-ads',
|
||||
templateUrl: './liquidity-ads.component.html',
|
||||
styleUrls: ['./liquidity-ads.component.scss'],
|
||||
providers: [
|
||||
{ provide: MatPaginatorIntl, useValue: getPaginatorLabel('Liquidity Ads') }
|
||||
]
|
||||
})
|
||||
export class CLNLiquidityAdsComponent implements OnInit, OnDestroy {
|
||||
|
||||
@ViewChild(MatSort, { static: false }) sort: MatSort | undefined;
|
||||
@ViewChild(MatPaginator, { static: false }) paginator: MatPaginator | undefined;
|
||||
public displayedColumns: any[] = [];
|
||||
public faWater = faWater;
|
||||
public faExclamationTriangle = faExclamationTriangle;
|
||||
public channelAmount = 0;
|
||||
public channelOpeningFeeRate = 0;
|
||||
public nodeCapacity = 0;
|
||||
public channelCount = 0;
|
||||
public liquidityNodesData: LookupNode[] = [];
|
||||
public liquidityNodes: any;
|
||||
public flgSticky = false;
|
||||
public pageSize = PAGE_SIZE;
|
||||
public pageSizeOptions = PAGE_SIZE_OPTIONS;
|
||||
public screenSize = '';
|
||||
public screenSizeEnum = ScreenSizeEnum;
|
||||
public errorMessage = '';
|
||||
public apiCallStatus: ApiCallStatusPayload = { status: APICallStatusEnum.INITIATED };
|
||||
public apiCallStatusEnum = APICallStatusEnum;
|
||||
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
|
||||
|
||||
constructor(private logger: LoggerService, private dataService: DataService, private commonService: CommonService) {
|
||||
this.screenSize = this.commonService.getScreenSize();
|
||||
if (this.screenSize === ScreenSizeEnum.XS) {
|
||||
this.flgSticky = false;
|
||||
this.displayedColumns = ['alias', 'capacity', 'actions'];
|
||||
} else if (this.screenSize === ScreenSizeEnum.SM) {
|
||||
this.flgSticky = false;
|
||||
this.displayedColumns = ['alias', 'capacity', 'numChannels', 'leaseFeeBasis', 'routingFee', 'channelOpenFee', 'actions'];
|
||||
} else if (this.screenSize === ScreenSizeEnum.MD) {
|
||||
this.flgSticky = false;
|
||||
this.displayedColumns = ['alias', 'capacity', 'numChannels', 'leaseFeeBasis', 'routingFee', 'channelOpenFee', 'actions'];
|
||||
} else {
|
||||
this.flgSticky = true;
|
||||
this.displayedColumns = ['alias', 'capacity', 'numChannels', 'leaseFeeBasis', 'routingFee', 'channelOpenFee', 'actions'];
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.dataService.listNetworkNodes('?liquidity_ads=yes').pipe(takeUntil(this.unSubs[0])).subscribe({
|
||||
next: (res: any) => {
|
||||
this.logger.info('Received Liquidity Ads Enabled Nodes: ' + JSON.stringify(res));
|
||||
this.apiCallStatus.status = APICallStatusEnum.COMPLETED;
|
||||
this.liquidityNodesData = res;
|
||||
this.loadLiqNodesTable(this.liquidityNodesData);
|
||||
}, error: (err) => {
|
||||
this.logger.error('Liquidity Ads Nodes Error: ' + JSON.stringify(err));
|
||||
this.apiCallStatus.status = APICallStatusEnum.ERROR;
|
||||
this.errorMessage = JSON.stringify(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onRecalculate() {
|
||||
|
||||
}
|
||||
|
||||
onFilter() {
|
||||
this.logger.info(this.nodeCapacity);
|
||||
this.logger.info(this.channelCount);
|
||||
// this.liquidityNodes.filter = this.nodeCapacity + ' ' + this.channelCount;
|
||||
}
|
||||
|
||||
loadLiqNodesTable(liqNodes: LookupNode[]) {
|
||||
this.liquidityNodes = new MatTableDataSource<LookupNode>([...liqNodes]);
|
||||
this.liquidityNodes.sortingDataAccessor = (data: any, sortHeaderId: string) => ((data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null);
|
||||
this.liquidityNodes.sort = this.sort;
|
||||
this.liquidityNodes.filterPredicate = (node: LookupNode, fltr: string) => JSON.stringify(node).toLowerCase().includes(fltr);
|
||||
this.liquidityNodes.paginator = this.paginator;
|
||||
this.onFilter();
|
||||
}
|
||||
|
||||
onOpenChannel(lqNode: LookupNode) {
|
||||
}
|
||||
|
||||
onNodeClick(lqNode: LookupNode) {
|
||||
|
||||
}
|
||||
|
||||
onDownloadCSV() {
|
||||
if (this.liquidityNodes.data && this.liquidityNodes.data.length > 0) {
|
||||
this.commonService.downloadFile(this.liquidityNodes.data, 'LiquidityNodes');
|
||||
}
|
||||
}
|
||||
|
||||
onReset() {
|
||||
this.channelAmount = 0;
|
||||
this.channelOpeningFeeRate = 0;
|
||||
}
|
||||
|
||||
onFilterReset() {
|
||||
this.nodeCapacity = 0;
|
||||
this.channelCount = 0;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.unSubs.forEach((completeSub) => {
|
||||
completeSub.next(null);
|
||||
completeSub.complete();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue