Merge pull request #5117 from mempool/natsoni/pools-search
Add mining pools to search results
This commit is contained in:
		
						commit
						11cfb8a783
					
				@ -22,6 +22,7 @@ export class SearchFormComponent implements OnInit {
 | 
				
			|||||||
  env: Env;
 | 
					  env: Env;
 | 
				
			||||||
  network = '';
 | 
					  network = '';
 | 
				
			||||||
  assets: object = {};
 | 
					  assets: object = {};
 | 
				
			||||||
 | 
					  pools: object[] = [];
 | 
				
			||||||
  isSearching = false;
 | 
					  isSearching = false;
 | 
				
			||||||
  isTypeaheading$ = new BehaviorSubject<boolean>(false);
 | 
					  isTypeaheading$ = new BehaviorSubject<boolean>(false);
 | 
				
			||||||
  typeAhead$: Observable<any>;
 | 
					  typeAhead$: Observable<any>;
 | 
				
			||||||
@ -118,7 +119,8 @@ export class SearchFormComponent implements OnInit {
 | 
				
			|||||||
        if (!text.length) {
 | 
					        if (!text.length) {
 | 
				
			||||||
          return of([
 | 
					          return of([
 | 
				
			||||||
            [],
 | 
					            [],
 | 
				
			||||||
            { nodes: [], channels: [] }
 | 
					            { nodes: [], channels: [] },
 | 
				
			||||||
 | 
					            this.pools
 | 
				
			||||||
          ]);
 | 
					          ]);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        this.isTypeaheading$.next(true);
 | 
					        this.isTypeaheading$.next(true);
 | 
				
			||||||
@ -126,6 +128,7 @@ export class SearchFormComponent implements OnInit {
 | 
				
			|||||||
          return zip(
 | 
					          return zip(
 | 
				
			||||||
            this.electrsApiService.getAddressesByPrefix$(text).pipe(catchError(() => of([]))),
 | 
					            this.electrsApiService.getAddressesByPrefix$(text).pipe(catchError(() => of([]))),
 | 
				
			||||||
            [{ nodes: [], channels: [] }],
 | 
					            [{ nodes: [], channels: [] }],
 | 
				
			||||||
 | 
					            this.getMiningPools()
 | 
				
			||||||
          );
 | 
					          );
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return zip(
 | 
					        return zip(
 | 
				
			||||||
@ -134,6 +137,7 @@ export class SearchFormComponent implements OnInit {
 | 
				
			|||||||
            nodes: [],
 | 
					            nodes: [],
 | 
				
			||||||
            channels: [],
 | 
					            channels: [],
 | 
				
			||||||
          }))),
 | 
					          }))),
 | 
				
			||||||
 | 
					          this.getMiningPools()
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      }),
 | 
					      }),
 | 
				
			||||||
      map((result: any[]) => {
 | 
					      map((result: any[]) => {
 | 
				
			||||||
@ -153,11 +157,14 @@ export class SearchFormComponent implements OnInit {
 | 
				
			|||||||
          {
 | 
					          {
 | 
				
			||||||
            nodes: [],
 | 
					            nodes: [],
 | 
				
			||||||
            channels: [],
 | 
					            channels: [],
 | 
				
			||||||
          }
 | 
					          },
 | 
				
			||||||
 | 
					          this.pools
 | 
				
			||||||
        ]))
 | 
					        ]))
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
      ).pipe(
 | 
					      ).pipe(
 | 
				
			||||||
        map((latestData) => {
 | 
					        map((latestData) => {
 | 
				
			||||||
 | 
					          this.pools = latestData[1][2] || [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          let searchText = latestData[0];
 | 
					          let searchText = latestData[0];
 | 
				
			||||||
          if (!searchText.length) {
 | 
					          if (!searchText.length) {
 | 
				
			||||||
            return {
 | 
					            return {
 | 
				
			||||||
@ -171,6 +178,7 @@ export class SearchFormComponent implements OnInit {
 | 
				
			|||||||
              nodes: [],
 | 
					              nodes: [],
 | 
				
			||||||
              channels: [],
 | 
					              channels: [],
 | 
				
			||||||
              liquidAsset: [],
 | 
					              liquidAsset: [],
 | 
				
			||||||
 | 
					              pools: []
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -189,6 +197,7 @@ export class SearchFormComponent implements OnInit {
 | 
				
			|||||||
          const matchesAddress = !matchesTxId && this.regexAddress.test(searchText);
 | 
					          const matchesAddress = !matchesTxId && this.regexAddress.test(searchText);
 | 
				
			||||||
          const otherNetworks = findOtherNetworks(searchText, this.network as any || 'mainnet', this.env);
 | 
					          const otherNetworks = findOtherNetworks(searchText, this.network as any || 'mainnet', this.env);
 | 
				
			||||||
          const liquidAsset = this.assets ? (this.assets[searchText] || []) : [];
 | 
					          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) {
 | 
					          if (matchesDateTime && searchText.indexOf('/') !== -1) {
 | 
				
			||||||
            searchText = searchText.replace(/\//g, '-');
 | 
					            searchText = searchText.replace(/\//g, '-');
 | 
				
			||||||
@ -208,6 +217,7 @@ export class SearchFormComponent implements OnInit {
 | 
				
			|||||||
            nodes: lightningResults.nodes,
 | 
					            nodes: lightningResults.nodes,
 | 
				
			||||||
            channels: lightningResults.channels,
 | 
					            channels: lightningResults.channels,
 | 
				
			||||||
            liquidAsset: liquidAsset,
 | 
					            liquidAsset: liquidAsset,
 | 
				
			||||||
 | 
					            pools: pools
 | 
				
			||||||
          };
 | 
					          };
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
@ -239,6 +249,8 @@ export class SearchFormComponent implements OnInit {
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
        this.isSearching = false;
 | 
					        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;
 | 
					      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([]))
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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">
 | 
					  <ng-template [ngIf]="results.blockHeight">
 | 
				
			||||||
    <div class="card-title" i18n="search.bitcoin-block-height">{{ networkName }} Block Height</div>
 | 
					    <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">
 | 
					    <button (click)="clickItem(0)" [class.active]="0 === activeIdx" type="button" role="option" class="dropdown-item">
 | 
				
			||||||
@ -67,6 +67,14 @@
 | 
				
			|||||||
      </button>
 | 
					      </button>
 | 
				
			||||||
    </ng-template>
 | 
					    </ng-template>
 | 
				
			||||||
  </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">
 | 
					  <ng-template [ngIf]="results.liquidAsset.length">
 | 
				
			||||||
    <div class="card-title" i18n="search.liquid-asset">Liquid Asset</div>
 | 
					    <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">
 | 
					    <button (click)="clickItem(0)" [class.active]="0 === activeIdx" type="button" role="option" class="dropdown-item">
 | 
				
			||||||
 | 
				
			|||||||
@ -22,3 +22,7 @@
 | 
				
			|||||||
.inactive {
 | 
					.inactive {
 | 
				
			||||||
  opacity: 0.2;
 | 
					  opacity: 0.2;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.active {
 | 
				
			||||||
 | 
					  background-color: var(--active-bg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -27,7 +27,7 @@ export class SearchResultsComponent implements OnChanges {
 | 
				
			|||||||
  ngOnChanges() {
 | 
					  ngOnChanges() {
 | 
				
			||||||
    this.activeIdx = 0;
 | 
					    this.activeIdx = 0;
 | 
				
			||||||
    if (this.results) {
 | 
					    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];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -253,8 +253,9 @@ export class ApiService {
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
    .pipe(
 | 
					    .pipe(
 | 
				
			||||||
      map((response) => {
 | 
					      map((response) => {
 | 
				
			||||||
        response.body.pools.forEach((pool) => {
 | 
					        const pools = interval !== undefined ? response.body.pools : response.body;
 | 
				
			||||||
          if (pool.poolUniqueId === 0) {
 | 
					        pools.forEach((pool) => {
 | 
				
			||||||
 | 
					          if ((interval !== undefined && pool.poolUniqueId === 0) || (interval === undefined && pool.unique_id === 0)) {
 | 
				
			||||||
            pool.name = $localize`:@@e5d8bb389c702588877f039d72178f219453a72d:Unknown`;
 | 
					            pool.name = $localize`:@@e5d8bb389c702588877f039d72178f219453a72d:Unknown`;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user