diff --git a/README.md b/README.md index 75146d4b1..85cadb729 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,8 @@ JSON: "MEMPOOL_BLOCKS_AMOUNT": 8, "PRICE_FEED_UPDATE_INTERVAL": 600, "USE_SECOND_NODE_FOR_MINFEE": false, - "EXTERNAL_ASSETS": [] + "EXTERNAL_ASSETS": ["https://mempool.space/resources/pools.json"], + "STDOUT_LOG_MIN_PRIORITY": "debug" }, ``` @@ -111,6 +112,7 @@ docker-compose overrides:: MEMPOOL_PRICE_FEED_UPDATE_INTERVAL: "" MEMPOOL_USE_SECOND_NODE_FOR_MINFEE: "" MEMPOOL_EXTERNAL_ASSETS: "" + MEMPOOL_STDOUT_LOG_MIN_PRIORITY: "" ``` JSON: diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json index dc0f1a69e..5c45838ee 100644 --- a/backend/mempool-config.sample.json +++ b/backend/mempool-config.sample.json @@ -17,7 +17,8 @@ "USE_SECOND_NODE_FOR_MINFEE": false, "EXTERNAL_ASSETS": [ "https://mempool.space/resources/pools.json" - ] + ], + "STDOUT_LOG_MIN_PRIORITY": "debug" }, "CORE_RPC": { "HOST": "127.0.0.1", diff --git a/backend/src/config.ts b/backend/src/config.ts index 040d94bf1..97c3bb32a 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -18,6 +18,7 @@ interface IConfig { PRICE_FEED_UPDATE_INTERVAL: number; USE_SECOND_NODE_FOR_MINFEE: boolean; EXTERNAL_ASSETS: string[]; + STDOUT_LOG_MIN_PRIORITY: 'emerg' | 'alert' | 'crit' | 'err' | 'warn' | 'notice' | 'info' | 'debug'; }; ESPLORA: { REST_API_URL: string; @@ -94,7 +95,8 @@ const defaults: IConfig = { 'USE_SECOND_NODE_FOR_MINFEE': false, 'EXTERNAL_ASSETS': [ 'https://mempool.space/resources/pools.json' - ] + ], + 'STDOUT_LOG_MIN_PRIORITY': 'debug', }, 'ESPLORA': { 'REST_API_URL': 'http://127.0.0.1:3000', diff --git a/backend/src/index.ts b/backend/src/index.ts index f78c5922b..557c269dd 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -319,7 +319,9 @@ class Server { if (Common.isLiquid()) { this.app .get(config.MEMPOOL.API_URL_PREFIX + 'assets/icons', routes.getAllLiquidIcon) + .get(config.MEMPOOL.API_URL_PREFIX + 'assets/featured', routes.$getAllFeaturedLiquidAssets) .get(config.MEMPOOL.API_URL_PREFIX + 'asset/:assetId/icon', routes.getLiquidIcon) + .get(config.MEMPOOL.API_URL_PREFIX + 'assets/group/:id', routes.$getAssetGroup) ; } diff --git a/backend/src/logger.ts b/backend/src/logger.ts index 4e8c5ea11..43373e043 100644 --- a/backend/src/logger.ts +++ b/backend/src/logger.ts @@ -97,6 +97,9 @@ class Logger { syslogmsg = `<${(Logger.facilities[config.SYSLOG.FACILITY] * 8 + prionum)}> ${this.name}[${process.pid}]: ${priority.toUpperCase()}${network} ${msg}`; this.syslog(syslogmsg); } + if (Logger.priorities[priority] > Logger.priorities[config.MEMPOOL.STDOUT_LOG_MIN_PRIORITY]) { + return; + } if (priority === 'warning') { priority = 'warn'; } diff --git a/backend/src/routes.ts b/backend/src/routes.ts index 044f9a3ac..8ae2f9609 100644 --- a/backend/src/routes.ts +++ b/backend/src/routes.ts @@ -21,6 +21,7 @@ import bitcoinClient from './api/bitcoin/bitcoin-client'; import elementsParser from './api/liquid/elements-parser'; import icons from './api/liquid/icons'; import miningStats from './api/mining'; +import axios from 'axios'; class Routes { constructor() {} @@ -855,6 +856,25 @@ class Routes { res.status(404).send('Asset icons not found'); } } + + public async $getAllFeaturedLiquidAssets(req: Request, res: Response) { + try { + const response = await axios.get('https://liquid.network/api/v1/assets/featured', { responseType: 'stream', timeout: 10000 }); + response.data.pipe(res); + } catch (e) { + res.status(500).end(); + } + } + + public async $getAssetGroup(req: Request, res: Response) { + try { + const response = await axios.get('https://liquid.network/api/v1/assets/group/' + parseInt(req.params.id, 10), + { responseType: 'stream', timeout: 10000 }); + response.data.pipe(res); + } catch (e) { + res.status(500).end(); + } + } } export default new Routes(); diff --git a/docker/backend/mempool-config.json b/docker/backend/mempool-config.json index b97c9e571..3a0a0ec0b 100644 --- a/docker/backend/mempool-config.json +++ b/docker/backend/mempool-config.json @@ -14,7 +14,8 @@ "MEMPOOL_BLOCKS_AMOUNT": __MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__, "PRICE_FEED_UPDATE_INTERVAL": __MEMPOOL_PRICE_FEED_UPDATE_INTERVAL__, "USE_SECOND_NODE_FOR_MINFEE": __MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__, - "EXTERNAL_ASSETS": __MEMPOOL_EXTERNAL_ASSETS__ + "EXTERNAL_ASSETS": __MEMPOOL_EXTERNAL_ASSETS__, + "STDOUT_LOG_MIN_PRIORITY": "__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__" }, "CORE_RPC": { "HOST": "__CORE_RPC_HOST__", diff --git a/docker/backend/start.sh b/docker/backend/start.sh index d12978970..019f16217 100644 --- a/docker/backend/start.sh +++ b/docker/backend/start.sh @@ -16,7 +16,8 @@ __MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__=${MEMPOOL_MEMPOOL_BLOCKS_AMOUNT:=8} __MEMPOOL_INDEXING_BLOCKS_AMOUNT__=${MEMPOOL_INDEXING_BLOCKS_AMOUNT:=1100} __MEMPOOL_PRICE_FEED_UPDATE_INTERVAL__=${MEMPOOL_PRICE_FEED_UPDATE_INTERVAL:=600} __MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__=${MEMPOOL_USE_SECOND_NODE_FOR_MINFEE:=false} -__MEMPOOL_EXTERNAL_ASSETS__=${MEMPOOL_EXTERNAL_ASSETS:=[]} +__MEMPOOL_EXTERNAL_ASSETS__=${MEMPOOL_EXTERNAL_ASSETS:=[\"https://mempool.space/resources/pools.json\"]} +__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__=${MEMPOOL_STDOUT_LOG_MIN_PRIORITY:=debug} # CORE_RPC __CORE_RPC_HOST__=${CORE_RPC_HOST:=127.0.0.1} @@ -89,7 +90,8 @@ sed -i "s/__MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__/${__MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__} sed -i "s/__MEMPOOL_INDEXING_BLOCKS_AMOUNT__/${__MEMPOOL_INDEXING_BLOCKS_AMOUNT__}/g" mempool-config.json sed -i "s/__MEMPOOL_PRICE_FEED_UPDATE_INTERVAL__/${__MEMPOOL_PRICE_FEED_UPDATE_INTERVAL__}/g" mempool-config.json sed -i "s/__MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__/${__MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__}/g" mempool-config.json -sed -i "s/__MEMPOOL_EXTERNAL_ASSETS__/${__MEMPOOL_EXTERNAL_ASSETS__}/g" mempool-config.json +sed -i "s!__MEMPOOL_EXTERNAL_ASSETS__!${__MEMPOOL_EXTERNAL_ASSETS__}!g" mempool-config.json +sed -i "s/__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__/${__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__}/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 diff --git a/frontend/cypress/integration/liquid/liquid.spec.ts b/frontend/cypress/integration/liquid/liquid.spec.ts index af76314a1..d8d1c366d 100644 --- a/frontend/cypress/integration/liquid/liquid.spec.ts +++ b/frontend/cypress/integration/liquid/liquid.spec.ts @@ -115,17 +115,16 @@ describe('Liquid', () => { describe('assets', () => { it('shows the assets screen', () => { - cy.visit(`${basePath}`); - cy.get('#btn-assets'); + cy.visit(`${basePath}/assets`); cy.waitForSkeletonGone(); - cy.get('table tr').should('have.length.at.least', 5); + cy.get('.featuredBox .card').should('have.length.at.least', 5); }); it('allows searching assets', () => { cy.visit(`${basePath}/assets`); cy.waitForSkeletonGone(); cy.get('.container-xl input').click().type('Liquid Bitcoin').then(() => { - cy.get('table tr').should('have.length', 1); + cy.get('ngb-typeahead-window').should('have.length', 1); }); }); @@ -133,7 +132,7 @@ describe('Liquid', () => { cy.visit(`${basePath}/assets`); cy.waitForSkeletonGone(); cy.get('.container-xl input').click().type('Liquid AUD').then(() => { - cy.get('table tr td:nth-of-type(1) a').click(); + cy.get('ngb-typeahead-window:nth-of-type(1) button').click(); }); }); }); @@ -197,7 +196,7 @@ describe('Liquid', () => { }); it('shows asset peg in/out and burn transactions', () => { - cy.visit(`${basePath}/asset/6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d`); + cy.visit(`${basePath}/assets/asset/6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d`); cy.waitForSkeletonGone(); cy.get('#table-tx-vout tr').not('.assetBox'); cy.get('#table-tx-vin tr').not('.assetBox'); diff --git a/frontend/cypress/integration/liquidtestnet/liquidtestnet.spec.ts b/frontend/cypress/integration/liquidtestnet/liquidtestnet.spec.ts index eb75be773..90741539b 100644 --- a/frontend/cypress/integration/liquidtestnet/liquidtestnet.spec.ts +++ b/frontend/cypress/integration/liquidtestnet/liquidtestnet.spec.ts @@ -73,17 +73,11 @@ describe('Liquid Testnet', () => { }); describe('assets', () => { - it('shows the assets screen', () => { - cy.visit(`${basePath}/assets`); - cy.waitForSkeletonGone(); - cy.get('table tr').should('have.length.at.least', 5); - }); - it('allows searching assets', () => { cy.visit(`${basePath}/assets`); cy.waitForSkeletonGone(); cy.get('.container-xl input').click().type('Liquid Bitcoin').then(() => { - cy.get('table tr').should('have.length', 1); + cy.get('ngb-typeahead-window').should('have.length', 1); }); }); @@ -91,7 +85,7 @@ describe('Liquid Testnet', () => { cy.visit(`${basePath}/assets`); cy.waitForSkeletonGone(); cy.get('.container-xl input').click().type('Liquid CAD').then(() => { - cy.get('table tr td:nth-of-type(1) a').click(); + cy.get('ngb-typeahead-window:nth-of-type(1) button').click(); }); }); }); @@ -150,7 +144,7 @@ describe('Liquid Testnet', () => { cy.visit(`${basePath}/tx/0877bc0c7aa5c2b8d0e4b15450425879b8783c40e341806037a605ef836fb886#blinded=5000,38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5,328de54e90e867a9154b4f1eb7fcab86267e880fa2ee9e53b41a91e61dab86e6,8885831e6b089eaf06889d53a24843f0da533d300a7b1527b136883a6819f3ae,5000,38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5,aca78b953615d69ae0ae68c4c5c3c0ee077c10bc20ad3f0c5960706004e6cb56,d2ec175afe5f761e2dbd443faf46abbb7091f341deb3387e5787d812bdb2df9f,100000,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,4b54a4ca809b3844f34dd88b68617c4c866d92a02211f02ba355755bac20a1c6,eddd02e92b0cfbad8cab89828570a50f2c643bb2a54d886c86e25ce47e818685,99729,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,8b86d565c9549eb0352bb81ee576d01d064435b64fddcc045decebeb1d9913ce,b082ce3448d40d47b5b39f15d72b285f4a1046b636b56c25f32f498ece29d062,10000,38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5,62b04ee86198d6b41681cdd0acb450ab366af727a010aaee8ba0b9e69ff43896,3f98429bca9b538dc943c22111f25d9c4448d45a63ff0f4e58b22fd434c0365e`); cy.get('#table-tx-vout tr:nth-child(2) .amount a').click().then(() => { cy.waitForSkeletonGone(); - cy.url().should('contain', '/asset/38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5'); + cy.url().should('contain', '/assets/asset/38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5'); }); }); @@ -162,7 +156,7 @@ describe('Liquid Testnet', () => { }); it('shows asset peg in/out and burn transactions', () => { - cy.visit(`${basePath}/asset/ac3e0ff248c5051ffd61e00155b7122e5ebc04fd397a0ecbdd4f4e4a56232926`); + cy.visit(`${basePath}/assets/asset/ac3e0ff248c5051ffd61e00155b7122e5ebc04fd397a0ecbdd4f4e4a56232926`); cy.waitForSkeletonGone(); cy.get('#table-tx-vout tr').not('.assetBox'); cy.get('#table-tx-vin tr').not('.assetBox'); diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 36a53781f..aaf545206 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -10,7 +10,7 @@ import { TelevisionComponent } from './components/television/television.componen import { StatisticsComponent } from './components/statistics/statistics.component'; import { MempoolBlockComponent } from './components/mempool-block/mempool-block.component'; import { AssetComponent } from './components/asset/asset.component'; -import { AssetsComponent } from './assets/assets.component'; +import { AssetsNavComponent } from './components/assets/assets-nav/assets-nav.component'; import { StatusViewComponent } from './components/status-view/status-view.component'; import { DashboardComponent } from './dashboard/dashboard.component'; import { LatestBlocksComponent } from './components/latest-blocks/latest-blocks.component'; @@ -23,6 +23,9 @@ import { SponsorComponent } from './components/sponsor/sponsor.component'; import { LiquidMasterPageComponent } from './components/liquid-master-page/liquid-master-page.component'; import { PushTransactionComponent } from './components/push-transaction/push-transaction.component'; import { PoolRankingComponent } from './components/pool-ranking/pool-ranking.component'; +import { AssetGroupComponent } from './components/assets/asset-group/asset-group.component'; +import { AssetsFeaturedComponent } from './components/assets/assets-featured/assets-featured.component'; +import { AssetsComponent } from './components/assets/assets.component'; let routes: Routes = [ { @@ -343,13 +346,31 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') { path: 'address/:id', component: AddressComponent }, - { - path: 'asset/:id', - component: AssetComponent - }, { path: 'assets', - component: AssetsComponent, + component: AssetsNavComponent, + children: [ + { + path: 'featured', + component: AssetsFeaturedComponent, + }, + { + path: 'all', + component: AssetsComponent, + }, + { + path: 'asset/:id', + component: AssetComponent + }, + { + path: 'group/:id', + component: AssetGroupComponent + }, + { + path: '**', + redirectTo: 'featured' + } + ] }, { path: 'docs/api/:type', @@ -434,13 +455,27 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') { path: 'address/:id', component: AddressComponent }, - { - path: 'asset/:id', - component: AssetComponent - }, { path: 'assets', - component: AssetsComponent, + component: AssetsNavComponent, + children: [ + { + path: 'all', + component: AssetsComponent, + }, + { + path: 'asset/:id', + component: AssetComponent + }, + { + path: 'group/:id', + component: AssetGroupComponent + }, + { + path: '**', + redirectTo: 'all' + } + ] }, { path: 'docs/api/:type', diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index f9eae0666..97fc16204 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -40,7 +40,8 @@ import { MempoolGraphComponent } from './components/mempool-graph/mempool-graph. import { PoolRankingComponent } from './components/pool-ranking/pool-ranking.component'; import { LbtcPegsGraphComponent } from './components/lbtc-pegs-graph/lbtc-pegs-graph.component'; import { AssetComponent } from './components/asset/asset.component'; -import { AssetsComponent } from './assets/assets.component'; +import { AssetsComponent } from './components/assets/assets.component'; +import { AssetsNavComponent } from './components/assets/assets-nav/assets-nav.component'; import { StatusViewComponent } from './components/status-view/status-view.component'; import { MinerComponent } from './components/miner/miner.component'; import { SharedModule } from './shared/shared.module'; @@ -64,6 +65,8 @@ import { LanguageService } from './services/language.service'; import { SponsorComponent } from './components/sponsor/sponsor.component'; import { PushTransactionComponent } from './components/push-transaction/push-transaction.component'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { AssetsFeaturedComponent } from './components/assets/assets-featured/assets-featured.component'; +import { AssetGroupComponent } from './components/assets/asset-group/asset-group.component'; @NgModule({ declarations: [ @@ -110,6 +113,9 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; PushTransactionComponent, DocsComponent, ApiDocsNavComponent, + AssetsNavComponent, + AssetsFeaturedComponent, + AssetGroupComponent, ], imports: [ BrowserModule.withServerTransition({ appId: 'serverApp' }), diff --git a/frontend/src/app/assets/assets.component.html b/frontend/src/app/assets/assets.component.html deleted file mode 100644 index c8962cd15..000000000 --- a/frontend/src/app/assets/assets.component.html +++ /dev/null @@ -1,71 +0,0 @@ -
-
-

Registered assets

-
-
- -
-
- -
- -
-
-
- - - - - - - - - - - - - - - - - -
NameTickerIssuer domainAsset ID
{{ asset.name }}{{ asset.ticker }}{{ asset.entity && asset.entity.domain }}{{ asset.asset_id | shortenString : 13 }}
- -
- - - -
- - - - - - - - - - - - - - - - - - -
NameTickerIssuer domainAsset ID
- -
- - -
- Error loading assets data. -
- {{ error.error }} -
-
- -
- -
diff --git a/frontend/src/app/assets/assets.component.spec.ts b/frontend/src/app/assets/assets.component.spec.ts deleted file mode 100644 index ed39b7122..000000000 --- a/frontend/src/app/assets/assets.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { AssetsComponent } from './assets.component'; - -describe('AssetsComponent', () => { - let component: AssetsComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ AssetsComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(AssetsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/src/app/assets/assets.component.ts b/frontend/src/app/assets/assets.component.ts deleted file mode 100644 index 49c42d76e..000000000 --- a/frontend/src/app/assets/assets.component.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; -import { AssetsService } from '../services/assets.service'; -import { environment } from 'src/environments/environment'; -import { FormGroup, FormBuilder, Validators } from '@angular/forms'; -import { distinctUntilChanged, map, filter, mergeMap, tap, take } from 'rxjs/operators'; -import { ActivatedRoute, Router } from '@angular/router'; -import { merge, combineLatest, Observable } from 'rxjs'; -import { AssetExtended } from '../interfaces/electrs.interface'; -import { SeoService } from '../services/seo.service'; -import { StateService } from '../services/state.service'; - -@Component({ - selector: 'app-assets', - templateUrl: './assets.component.html', - styleUrls: ['./assets.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush -}) -export class AssetsComponent implements OnInit { - nativeAssetId = this.stateService.network === 'liquidtestnet' ? environment.nativeTestAssetId : environment.nativeAssetId; - - assets: AssetExtended[]; - assetsCache: AssetExtended[]; - searchForm: FormGroup; - assets$: Observable; - - error: any; - - page = 1; - itemsPerPage: number; - contentSpace = window.innerHeight - (250 + 200); - fiveItemsPxSize = 250; - - constructor( - private assetsService: AssetsService, - private formBuilder: FormBuilder, - private route: ActivatedRoute, - private router: Router, - private seoService: SeoService, - private stateService: StateService, - ) { } - - ngOnInit() { - this.seoService.setTitle($localize`:@@ee8f8008bae6ce3a49840c4e1d39b4af23d4c263:Assets`); - this.itemsPerPage = Math.max(Math.round(this.contentSpace / this.fiveItemsPxSize) * 5, 10); - - this.searchForm = this.formBuilder.group({ - searchText: [{ value: '', disabled: true }, Validators.required] - }); - - this.assets$ = combineLatest([ - this.assetsService.getAssetsJson$, - this.route.queryParams - ]) - .pipe( - take(1), - mergeMap(([assets, qp]) => { - this.assets = Object.values(assets); - if (this.stateService.network === 'liquid') { - // @ts-ignore - this.assets.push({ - name: 'Liquid Bitcoin', - ticker: 'L-BTC', - asset_id: this.nativeAssetId, - }); - } else if (this.stateService.network === 'liquidtestnet') { - // @ts-ignore - this.assets.push({ - name: 'Test Liquid Bitcoin', - ticker: 'tL-BTC', - asset_id: this.nativeAssetId, - }); - } - - this.assets = this.assets.sort((a: any, b: any) => a.name.localeCompare(b.name)); - this.assetsCache = this.assets; - this.searchForm.get('searchText').enable(); - - if (qp.search) { - this.searchForm.get('searchText').setValue(qp.search, { emitEvent: false }); - } - - return merge( - this.searchForm.get('searchText').valueChanges - .pipe( - distinctUntilChanged(), - tap((text) => { - this.page = 1; - this.searchTextChanged(text); - }) - ), - this.route.queryParams - .pipe( - filter((queryParams) => { - const newPage = parseInt(queryParams.page, 10); - if (newPage !== this.page || queryParams.search !== this.searchForm.get('searchText').value) { - return true; - } - return false; - }), - map((queryParams) => { - if (queryParams.page) { - const newPage = parseInt(queryParams.page, 10); - this.page = newPage; - } else { - this.page = 1; - } - if (this.searchForm.get('searchText').value !== (queryParams.search || '')) { - this.searchTextChanged(queryParams.search); - } - if (queryParams.search) { - this.searchForm.get('searchText').setValue(queryParams.search, { emitEvent: false }); - return queryParams.search; - } - return ''; - }) - ), - ); - }), - map((searchText) => { - const start = (this.page - 1) * this.itemsPerPage; - if (searchText.length ) { - const filteredAssets = this.assetsCache.filter((asset) => asset.name.toLowerCase().indexOf(searchText.toLowerCase()) > -1 - || (asset.ticker || '').toLowerCase().indexOf(searchText.toLowerCase()) > -1); - this.assets = filteredAssets; - return filteredAssets.slice(start, this.itemsPerPage + start); - } else { - this.assets = this.assetsCache; - return this.assets.slice(start, this.itemsPerPage + start); - } - }) - ); - } - - pageChange(page: number) { - const queryParams = { page: page, search: this.searchForm.get('searchText').value }; - if (queryParams.search === '') { - queryParams.search = null; - } - if (queryParams.page === 1) { - queryParams.page = null; - } - this.page = -1; - this.router.navigate([], { - relativeTo: this.route, - queryParams: queryParams, - queryParamsHandling: 'merge', - }); - } - - searchTextChanged(text: string) { - const queryParams = { search: text, page: 1 }; - if (queryParams.search === '') { - queryParams.search = null; - } - if (queryParams.page === 1) { - queryParams.page = null; - } - this.router.navigate([], { - relativeTo: this.route, - queryParams: queryParams, - queryParamsHandling: 'merge', - }); - } - - trackByAsset(index: number, asset: any) { - return asset.asset_id; - } -} diff --git a/frontend/src/app/components/asset/asset.component.html b/frontend/src/app/components/asset/asset.component.html index 9723a45e5..b1728a0ff 100644 --- a/frontend/src/app/components/asset/asset.component.html +++ b/frontend/src/app/components/asset/asset.component.html @@ -2,7 +2,7 @@

Asset