Merge pull request #5117 from mempool/natsoni/pools-search

Add mining pools to search results
This commit is contained in:
softsimon 2024-05-31 21:16:46 +07:00 committed by GitHub
commit 11cfb8a783
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 56 additions and 6 deletions

View File

@ -22,6 +22,7 @@ export class SearchFormComponent implements OnInit {
env: Env;
network = '';
assets: object = {};
pools: object[] = [];
isSearching = false;
isTypeaheading$ = new BehaviorSubject<boolean>(false);
typeAhead$: Observable<any>;
@ -118,7 +119,8 @@ export class SearchFormComponent implements OnInit {
if (!text.length) {
return of([
[],
{ nodes: [], channels: [] }
{ nodes: [], channels: [] },
this.pools
]);
}
this.isTypeaheading$.next(true);
@ -126,6 +128,7 @@ export class SearchFormComponent implements OnInit {
return zip(
this.electrsApiService.getAddressesByPrefix$(text).pipe(catchError(() => of([]))),
[{ nodes: [], channels: [] }],
this.getMiningPools()
);
}
return zip(
@ -134,6 +137,7 @@ export class SearchFormComponent implements OnInit {
nodes: [],
channels: [],
}))),
this.getMiningPools()
);
}),
map((result: any[]) => {
@ -153,11 +157,14 @@ export class SearchFormComponent implements OnInit {
{
nodes: [],
channels: [],
}
},
this.pools
]))
]
).pipe(
map((latestData) => {
this.pools = latestData[1][2] || [];
let searchText = latestData[0];
if (!searchText.length) {
return {
@ -171,6 +178,7 @@ export class SearchFormComponent implements OnInit {
nodes: [],
channels: [],
liquidAsset: [],
pools: []
};
}
@ -189,6 +197,7 @@ export class SearchFormComponent implements OnInit {
const matchesAddress = !matchesTxId && this.regexAddress.test(searchText);
const otherNetworks = findOtherNetworks(searchText, this.network as any || 'mainnet', this.env);
const liquidAsset = this.assets ? (this.assets[searchText] || []) : [];
const pools = this.pools.filter(pool => pool["name"].toLowerCase().includes(searchText.toLowerCase())).slice(0, 10);
if (matchesDateTime && searchText.indexOf('/') !== -1) {
searchText = searchText.replace(/\//g, '-');
@ -208,6 +217,7 @@ export class SearchFormComponent implements OnInit {
nodes: lightningResults.nodes,
channels: lightningResults.channels,
liquidAsset: liquidAsset,
pools: pools
};
})
);
@ -239,6 +249,8 @@ export class SearchFormComponent implements OnInit {
});
this.isSearching = false;
}
} else if (result.slug) {
this.navigate('/mining/pool/', result.slug);
}
}
@ -304,4 +316,29 @@ export class SearchFormComponent implements OnInit {
this.isSearching = false;
}
}
getMiningPools(): Observable<any> {
return this.pools.length ? of(this.pools) : combineLatest([
this.apiService.listPools$(undefined),
this.apiService.listPools$('1y')
]).pipe(
map(([poolsResponse, activePoolsResponse]) => {
const activePoolSlugs = new Set(activePoolsResponse.body.pools.map(pool => pool.slug));
return poolsResponse.body.map(pool => ({
name: pool.name,
slug: pool.slug,
active: activePoolSlugs.has(pool.slug)
}))
// Sort: active pools first, then alphabetically
.sort((a, b) => {
if (a.active && !b.active) return -1;
if (!a.active && b.active) return 1;
return a.slug < b.slug ? -1 : 1;
});
}),
catchError(() => of([]))
);
}
}

View File

@ -1,4 +1,4 @@
<div class="dropdown-menu show" *ngIf="results" [hidden]="!results.hashQuickMatch && !results.otherNetworks.length && !results.addresses.length && !results.nodes.length && !results.channels.length && !results.liquidAsset.length">
<div class="dropdown-menu show" *ngIf="results" [hidden]="!results.hashQuickMatch && !results.otherNetworks.length && !results.addresses.length && !results.nodes.length && !results.channels.length && !results.liquidAsset.length && !results.pools.length">
<ng-template [ngIf]="results.blockHeight">
<div class="card-title" i18n="search.bitcoin-block-height">{{ networkName }} Block Height</div>
<button (click)="clickItem(0)" [class.active]="0 === activeIdx" type="button" role="option" class="dropdown-item">
@ -67,6 +67,14 @@
</button>
</ng-template>
</ng-template>
<ng-template [ngIf]="results.pools.length">
<div class="card-title" i18n="search.mining-pools">Mining Pools</div>
<ng-template ngFor [ngForOf]="results.pools" let-pool let-i="index">
<button (click)="clickItem(results.hashQuickMatch + results.otherNetworks.length + results.addresses.length + results.nodes.length + results.channels.length + i)" [class.active]="results.hashQuickMatch + results.otherNetworks.length + results.addresses.length + results.nodes.length + results.channels.length + i === activeIdx" [class.inactive]="!pool.active" type="button" role="option" class="dropdown-item">
<ngb-highlight [result]="pool.name" [term]="results.searchText"></ngb-highlight>
</button>
</ng-template>
</ng-template>
<ng-template [ngIf]="results.liquidAsset.length">
<div class="card-title" i18n="search.liquid-asset">Liquid Asset</div>
<button (click)="clickItem(0)" [class.active]="0 === activeIdx" type="button" role="option" class="dropdown-item">

View File

@ -22,3 +22,7 @@
.inactive {
opacity: 0.2;
}
.active {
background-color: var(--active-bg);
}

View File

@ -27,7 +27,7 @@ export class SearchResultsComponent implements OnChanges {
ngOnChanges() {
this.activeIdx = 0;
if (this.results) {
this.resultsFlattened = [...(this.results.hashQuickMatch ? [this.results.searchText] : []), ...this.results.otherNetworks, ...this.results.addresses, ...this.results.nodes, ...this.results.channels];
this.resultsFlattened = [...(this.results.hashQuickMatch ? [this.results.searchText] : []), ...this.results.otherNetworks, ...this.results.addresses, ...this.results.nodes, ...this.results.channels, ...this.results.pools];
}
}

View File

@ -253,8 +253,9 @@ export class ApiService {
)
.pipe(
map((response) => {
response.body.pools.forEach((pool) => {
if (pool.poolUniqueId === 0) {
const pools = interval !== undefined ? response.body.pools : response.body;
pools.forEach((pool) => {
if ((interval !== undefined && pool.poolUniqueId === 0) || (interval === undefined && pool.unique_id === 0)) {
pool.name = $localize`:@@e5d8bb389c702588877f039d72178f219453a72d:Unknown`;
}
});