From a7043787025f8d831851227139715148d4894658 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 1 Nov 2023 13:55:48 +0100 Subject: [PATCH 01/21] Refactor interface of getQuotes() to object (#2570) --- .../alpha-vantage/alpha-vantage.service.ts | 8 +++-- .../coingecko/coingecko.service.ts | 20 +++++++------ .../data-provider/data-provider.service.ts | 4 ++- .../eod-historical-data.service.ts | 30 +++++++++++-------- .../financial-modeling-prep.service.ts | 20 +++++++------ .../google-sheets/google-sheets.service.ts | 20 +++++++------ .../interfaces/data-provider.interface.ts | 8 +++-- .../data-provider/manual/manual.service.ts | 16 +++++----- .../rapid-api/rapid-api.service.ts | 12 ++++---- .../yahoo-finance/yahoo-finance.service.ts | 18 ++++++----- 10 files changed, 90 insertions(+), 66 deletions(-) diff --git a/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts b/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts index 973fc5df2..fbbfffc67 100644 --- a/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts +++ b/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts @@ -105,9 +105,11 @@ export class AlphaVantageService implements DataProviderInterface { return DataSource.ALPHA_VANTAGE; } - public async getQuotes( - aSymbols: string[] - ): Promise<{ [symbol: string]: IDataProviderResponse }> { + public async getQuotes({ + symbols + }: { + symbols: string[]; + }): Promise<{ [symbol: string]: IDataProviderResponse }> { return {}; } diff --git a/apps/api/src/services/data-provider/coingecko/coingecko.service.ts b/apps/api/src/services/data-provider/coingecko/coingecko.service.ts index 4360822f0..b7b571836 100644 --- a/apps/api/src/services/data-provider/coingecko/coingecko.service.ts +++ b/apps/api/src/services/data-provider/coingecko/coingecko.service.ts @@ -134,13 +134,15 @@ export class CoinGeckoService implements DataProviderInterface { return DataSource.COINGECKO; } - public async getQuotes( - aSymbols: string[] - ): Promise<{ [symbol: string]: IDataProviderResponse }> { - const results: { [symbol: string]: IDataProviderResponse } = {}; + public async getQuotes({ + symbols + }: { + symbols: string[]; + }): Promise<{ [symbol: string]: IDataProviderResponse }> { + const response: { [symbol: string]: IDataProviderResponse } = {}; - if (aSymbols.length <= 0) { - return {}; + if (symbols.length <= 0) { + return response; } try { @@ -151,7 +153,7 @@ export class CoinGeckoService implements DataProviderInterface { }, DEFAULT_REQUEST_TIMEOUT); const response = await got( - `${this.URL}/simple/price?ids=${aSymbols.join( + `${this.URL}/simple/price?ids=${symbols.join( ',' )}&vs_currencies=${DEFAULT_CURRENCY.toLowerCase()}`, { @@ -162,7 +164,7 @@ export class CoinGeckoService implements DataProviderInterface { for (const symbol in response) { if (Object.prototype.hasOwnProperty.call(response, symbol)) { - results[symbol] = { + response[symbol] = { currency: DEFAULT_CURRENCY, dataProviderInfo: this.getDataProviderInfo(), dataSource: DataSource.COINGECKO, @@ -175,7 +177,7 @@ export class CoinGeckoService implements DataProviderInterface { Logger.error(error, 'CoinGeckoService'); } - return results; + return response; } public getTestSymbol() { diff --git a/apps/api/src/services/data-provider/data-provider.service.ts b/apps/api/src/services/data-provider/data-provider.service.ts index 557699495..7a998eeb3 100644 --- a/apps/api/src/services/data-provider/data-provider.service.ts +++ b/apps/api/src/services/data-provider/data-provider.service.ts @@ -311,7 +311,9 @@ export class DataProviderService { i + maximumNumberOfSymbolsPerRequest ); - const promise = Promise.resolve(dataProvider.getQuotes(symbolsChunk)); + const promise = Promise.resolve( + dataProvider.getQuotes({ symbols: symbolsChunk }) + ); promises.push( promise.then(async (result) => { diff --git a/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts b/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts index ac2f35c04..37c37e389 100644 --- a/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts +++ b/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts @@ -131,17 +131,21 @@ export class EodHistoricalDataService implements DataProviderInterface { return DataSource.EOD_HISTORICAL_DATA; } - public async getQuotes( - aSymbols: string[] - ): Promise<{ [symbol: string]: IDataProviderResponse }> { - const symbols = aSymbols.map((symbol) => { - return this.convertToEodSymbol(symbol); - }); + public async getQuotes({ + symbols + }: { + symbols: string[]; + }): Promise<{ [symbol: string]: IDataProviderResponse }> { + let response: { [symbol: string]: IDataProviderResponse } = {}; if (symbols.length <= 0) { - return {}; + return response; } + const eodHistoricalDataSymbols = symbols.map((symbol) => { + return this.convertToEodSymbol(symbol); + }); + try { const abortController = new AbortController(); @@ -150,9 +154,9 @@ export class EodHistoricalDataService implements DataProviderInterface { }, DEFAULT_REQUEST_TIMEOUT); const realTimeResponse = await got( - `${this.URL}/real-time/${symbols[0]}?api_token=${ + `${this.URL}/real-time/${eodHistoricalDataSymbols[0]}?api_token=${ this.apiKey - }&fmt=json&s=${symbols.join(',')}`, + }&fmt=json&s=${eodHistoricalDataSymbols.join(',')}`, { // @ts-ignore signal: abortController.signal @@ -160,10 +164,12 @@ export class EodHistoricalDataService implements DataProviderInterface { ).json(); const quotes = - symbols.length === 1 ? [realTimeResponse] : realTimeResponse; + eodHistoricalDataSymbols.length === 1 + ? [realTimeResponse] + : realTimeResponse; const searchResponse = await Promise.all( - symbols + eodHistoricalDataSymbols .filter((symbol) => { return !symbol.endsWith('.FOREX'); }) @@ -176,7 +182,7 @@ export class EodHistoricalDataService implements DataProviderInterface { return items[0]; }); - const response = quotes.reduce( + response = quotes.reduce( ( result: { [symbol: string]: IDataProviderResponse }, { close, code, timestamp } diff --git a/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts b/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts index 4fd1d4ebd..b08bc099e 100644 --- a/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts +++ b/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts @@ -113,13 +113,15 @@ export class FinancialModelingPrepService implements DataProviderInterface { return DataSource.FINANCIAL_MODELING_PREP; } - public async getQuotes( - aSymbols: string[] - ): Promise<{ [symbol: string]: IDataProviderResponse }> { - const results: { [symbol: string]: IDataProviderResponse } = {}; + public async getQuotes({ + symbols + }: { + symbols: string[]; + }): Promise<{ [symbol: string]: IDataProviderResponse }> { + const response: { [symbol: string]: IDataProviderResponse } = {}; - if (aSymbols.length <= 0) { - return {}; + if (symbols.length <= 0) { + return response; } try { @@ -130,7 +132,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { }, DEFAULT_REQUEST_TIMEOUT); const response = await got( - `${this.URL}/quote/${aSymbols.join(',')}?apikey=${this.apiKey}`, + `${this.URL}/quote/${symbols.join(',')}?apikey=${this.apiKey}`, { // @ts-ignore signal: abortController.signal @@ -138,7 +140,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { ).json(); for (const { price, symbol } of response) { - results[symbol] = { + response[symbol] = { currency: DEFAULT_CURRENCY, dataProviderInfo: this.getDataProviderInfo(), dataSource: DataSource.FINANCIAL_MODELING_PREP, @@ -150,7 +152,7 @@ export class FinancialModelingPrepService implements DataProviderInterface { Logger.error(error, 'FinancialModelingPrepService'); } - return results; + return response; } public getTestSymbol() { diff --git a/apps/api/src/services/data-provider/google-sheets/google-sheets.service.ts b/apps/api/src/services/data-provider/google-sheets/google-sheets.service.ts index f4b592371..a541fcd12 100644 --- a/apps/api/src/services/data-provider/google-sheets/google-sheets.service.ts +++ b/apps/api/src/services/data-provider/google-sheets/google-sheets.service.ts @@ -99,18 +99,20 @@ export class GoogleSheetsService implements DataProviderInterface { return DataSource.GOOGLE_SHEETS; } - public async getQuotes( - aSymbols: string[] - ): Promise<{ [symbol: string]: IDataProviderResponse }> { - if (aSymbols.length <= 0) { - return {}; + public async getQuotes({ + symbols + }: { + symbols: string[]; + }): Promise<{ [symbol: string]: IDataProviderResponse }> { + const response: { [symbol: string]: IDataProviderResponse } = {}; + + if (symbols.length <= 0) { + return response; } try { - const response: { [symbol: string]: IDataProviderResponse } = {}; - const symbolProfiles = await this.symbolProfileService.getSymbolProfiles( - aSymbols.map((symbol) => { + symbols.map((symbol) => { return { symbol, dataSource: this.getName() @@ -129,7 +131,7 @@ export class GoogleSheetsService implements DataProviderInterface { const marketPrice = parseFloat(row['marketPrice']); const symbol = row['symbol']; - if (aSymbols.includes(symbol)) { + if (symbols.includes(symbol)) { response[symbol] = { marketPrice, currency: symbolProfiles.find((symbolProfile) => { diff --git a/apps/api/src/services/data-provider/interfaces/data-provider.interface.ts b/apps/api/src/services/data-provider/interfaces/data-provider.interface.ts index 2a16cc24c..f4daeb108 100644 --- a/apps/api/src/services/data-provider/interfaces/data-provider.interface.ts +++ b/apps/api/src/services/data-provider/interfaces/data-provider.interface.ts @@ -36,9 +36,11 @@ export interface DataProviderInterface { getName(): DataSource; - getQuotes( - aSymbols: string[] - ): Promise<{ [symbol: string]: IDataProviderResponse }>; + getQuotes({ + symbols + }: { + symbols: string[]; + }): Promise<{ [symbol: string]: IDataProviderResponse }>; getTestSymbol(): string; diff --git a/apps/api/src/services/data-provider/manual/manual.service.ts b/apps/api/src/services/data-provider/manual/manual.service.ts index 5c84a9c92..bea4b60ce 100644 --- a/apps/api/src/services/data-provider/manual/manual.service.ts +++ b/apps/api/src/services/data-provider/manual/manual.service.ts @@ -133,18 +133,20 @@ export class ManualService implements DataProviderInterface { return DataSource.MANUAL; } - public async getQuotes( - aSymbols: string[] - ): Promise<{ [symbol: string]: IDataProviderResponse }> { + public async getQuotes({ + symbols + }: { + symbols: string[]; + }): Promise<{ [symbol: string]: IDataProviderResponse }> { const response: { [symbol: string]: IDataProviderResponse } = {}; - if (aSymbols.length <= 0) { + if (symbols.length <= 0) { return response; } try { const symbolProfiles = await this.symbolProfileService.getSymbolProfiles( - aSymbols.map((symbol) => { + symbols.map((symbol) => { return { symbol, dataSource: this.getName() }; }) ); @@ -154,10 +156,10 @@ export class ManualService implements DataProviderInterface { orderBy: { date: 'desc' }, - take: aSymbols.length, + take: symbols.length, where: { symbol: { - in: aSymbols + in: symbols } } }); diff --git a/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts b/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts index 7743d7805..ce188ffe0 100644 --- a/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts +++ b/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts @@ -87,15 +87,17 @@ export class RapidApiService implements DataProviderInterface { return DataSource.RAPID_API; } - public async getQuotes( - aSymbols: string[] - ): Promise<{ [symbol: string]: IDataProviderResponse }> { - if (aSymbols.length <= 0) { + public async getQuotes({ + symbols + }: { + symbols: string[]; + }): Promise<{ [symbol: string]: IDataProviderResponse }> { + if (symbols.length <= 0) { return {}; } try { - const symbol = aSymbols[0]; + const symbol = symbols[0]; if (symbol === ghostfolioFearAndGreedIndexSymbol) { const fgi = await this.getFearAndGreedIndex(); diff --git a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts index c7c0ebbc8..16d48be8e 100644 --- a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts +++ b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts @@ -156,20 +156,22 @@ export class YahooFinanceService implements DataProviderInterface { return DataSource.YAHOO; } - public async getQuotes( - aSymbols: string[] - ): Promise<{ [symbol: string]: IDataProviderResponse }> { - if (aSymbols.length <= 0) { - return {}; + public async getQuotes({ + symbols + }: { + symbols: string[]; + }): Promise<{ [symbol: string]: IDataProviderResponse }> { + const response: { [symbol: string]: IDataProviderResponse } = {}; + + if (symbols.length <= 0) { + return response; } - const yahooFinanceSymbols = aSymbols.map((symbol) => + const yahooFinanceSymbols = symbols.map((symbol) => this.yahooFinanceDataEnhancerService.convertToYahooFinanceSymbol(symbol) ); try { - const response: { [symbol: string]: IDataProviderResponse } = {}; - let quotes: Pick< Quote, 'currency' | 'marketState' | 'regularMarketPrice' | 'symbol' From 5191415b5a5bb262ed23a06c03bdc50a534f4e86 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 2 Nov 2023 19:34:42 +0100 Subject: [PATCH 02/21] Add Intuit Mint (#2578) --- apps/api/src/assets/sitemap.xml | 16 ++++++++++ .../personal-finance-tools/products.ts | 18 +++++++++-- .../products/intuit-mint-page.component.ts | 31 +++++++++++++++++++ 3 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 apps/client/src/app/pages/resources/personal-finance-tools/products/intuit-mint-page.component.ts diff --git a/apps/api/src/assets/sitemap.xml b/apps/api/src/assets/sitemap.xml index 2b34b50ec..6b6184b7a 100644 --- a/apps/api/src/assets/sitemap.xml +++ b/apps/api/src/assets/sitemap.xml @@ -102,6 +102,10 @@ https://ghostfol.io/de/ressourcen/personal-finance-tools/open-source-alternative-zu-gospatz ${currentDate}T00:00:00+00:00 + + https://ghostfol.io/de/ressourcen/personal-finance-tools/open-source-alternative-zu-intuit-mint + ${currentDate}T00:00:00+00:00 + https://ghostfol.io/de/ressourcen/personal-finance-tools/open-source-alternative-zu-justetf ${currentDate}T00:00:00+00:00 @@ -368,6 +372,10 @@ https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-gospatz ${currentDate}T00:00:00+00:00 + + https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-intuit-mint + ${currentDate}T00:00:00+00:00 + https://ghostfol.io/en/resources/personal-finance-tools/open-source-alternative-to-justetf ${currentDate}T00:00:00+00:00 @@ -662,6 +670,10 @@ https://ghostfol.io/it/risorse/personal-finance-tools/alternativa-open-source-a-gospatz ${currentDate}T00:00:00+00:00 + + https://ghostfol.io/it/risorse/personal-finance-tools/alternativa-open-source-a-intuit-mint + ${currentDate}T00:00:00+00:00 + https://ghostfol.io/it/risorse/personal-finance-tools/alternativa-open-source-a-justetf ${currentDate}T00:00:00+00:00 @@ -802,6 +814,10 @@ https://ghostfol.io/nl/bronnen/personal-finance-tools/open-source-alternatief-voor-gospatz ${currentDate}T00:00:00+00:00 + + https://ghostfol.io/nl/bronnen/personal-finance-tools/open-source-alternatief-voor-intuit-mint + ${currentDate}T00:00:00+00:00 + https://ghostfol.io/nl/bronnen/personal-finance-tools/open-source-alternatief-voor-justetf ${currentDate}T00:00:00+00:00 diff --git a/apps/client/src/app/pages/resources/personal-finance-tools/products.ts b/apps/client/src/app/pages/resources/personal-finance-tools/products.ts index 5799437b4..8eddbea16 100644 --- a/apps/client/src/app/pages/resources/personal-finance-tools/products.ts +++ b/apps/client/src/app/pages/resources/personal-finance-tools/products.ts @@ -12,6 +12,7 @@ import { FinaryPageComponent } from './products/finary-page.component'; import { FolisharePageComponent } from './products/folishare-page.component'; import { GetquinPageComponent } from './products/getquin-page.component'; import { GoSpatzPageComponent } from './products/gospatz-page.component'; +import { IntuitMintPageComponent } from './products/intuit-mint-page.component'; import { JustEtfPageComponent } from './products/justetf-page.component'; import { KuberaPageComponent } from './products/kubera-page.component'; import { MarketsShPageComponent } from './products/markets.sh-page.component'; @@ -93,7 +94,7 @@ export const products: Product[] = [ key: 'capmon', name: 'CapMon.org', origin: $localize`Germany`, - note: 'Sunset in 2023', + note: 'CapMon.org has discontinued in 2023', slogan: 'Next Generation Assets Tracking' }, { @@ -182,6 +183,17 @@ export const products: Product[] = [ origin: $localize`Germany`, slogan: 'Volle Kontrolle über deine Investitionen' }, + { + component: IntuitMintPageComponent, + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'intuit-mint', + name: 'Intuit Mint', + note: 'Intuit Mint has discontinued in 2023', + origin: $localize`United States`, + pricingPerYear: '$60', + slogan: 'Managing money, made simple' + }, { component: JustEtfPageComponent, founded: 2011, @@ -224,7 +236,7 @@ export const products: Product[] = [ key: 'maybe-finance', languages: ['English'], name: 'Maybe Finance', - note: 'Sunset in 2023', + note: 'Maybe Finance has discontinued in 2023', origin: $localize`United States`, pricingPerYear: '$145', region: $localize`United States`, @@ -352,7 +364,7 @@ export const products: Product[] = [ key: 'stockmarketeye', name: 'StockMarketEye', origin: $localize`France`, - note: 'Sunset in 2023', + note: 'StockMarketEye has discontinued in 2023', slogan: 'A Powerful Portfolio & Investment Tracking App' }, { diff --git a/apps/client/src/app/pages/resources/personal-finance-tools/products/intuit-mint-page.component.ts b/apps/client/src/app/pages/resources/personal-finance-tools/products/intuit-mint-page.component.ts new file mode 100644 index 000000000..f2b594ab9 --- /dev/null +++ b/apps/client/src/app/pages/resources/personal-finance-tools/products/intuit-mint-page.component.ts @@ -0,0 +1,31 @@ +import { CommonModule } from '@angular/common'; +import { Component } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { RouterModule } from '@angular/router'; + +import { products } from '../products'; + +@Component({ + host: { class: 'page' }, + imports: [CommonModule, MatButtonModule, RouterModule], + selector: 'gf-intuit-mint-page', + standalone: true, + styleUrls: ['../product-page-template.scss'], + templateUrl: '../product-page-template.html' +}) +export class IntuitMintPageComponent { + public product1 = products.find(({ key }) => { + return key === 'ghostfolio'; + }); + + public product2 = products.find(({ key }) => { + return key === 'intuit-mint'; + }); + + public routerLinkAbout = ['/' + $localize`about`]; + public routerLinkFeatures = ['/' + $localize`features`]; + public routerLinkResourcesPersonalFinanceTools = [ + '/' + $localize`resources`, + 'personal-finance-tools' + ]; +} From e69c7a753c8004e88eabf358cd3d708bac13fa15 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 2 Nov 2023 19:35:03 +0100 Subject: [PATCH 03/21] Feature/add edit exchange rate button to admin control (#2577) * Ad edit button * Update changelog --- CHANGELOG.md | 4 ++++ apps/api/src/app/admin/admin.service.ts | 20 ++++++++++++++++--- .../asset-profile-dialog.component.ts | 6 +++--- .../admin-overview/admin-overview.html | 12 +++++++++++ .../admin-overview/admin-overview.module.ts | 4 +++- .../lib/interfaces/admin-data.interface.ts | 8 +++++++- 6 files changed, 46 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d77b922ea..ae48c564d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Added a button to edit the exchange rates in the admin control panel + ### Changed - Improved the language localization for German (`de`) diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts index a42723ba3..b46a0a13a 100644 --- a/apps/api/src/app/admin/admin.service.ts +++ b/apps/api/src/app/admin/admin.service.ts @@ -23,7 +23,13 @@ import { } from '@ghostfolio/common/interfaces'; import { MarketDataPreset } from '@ghostfolio/common/types'; import { BadRequestException, Injectable } from '@nestjs/common'; -import { AssetSubClass, Prisma, Property, SymbolProfile } from '@prisma/client'; +import { + AssetSubClass, + DataSource, + Prisma, + Property, + SymbolProfile +} from '@prisma/client'; import { differenceInDays } from 'date-fns'; import { groupBy } from 'lodash'; @@ -94,9 +100,17 @@ export class AdminService { return currency !== DEFAULT_CURRENCY; }) .map((currency) => { + const label1 = DEFAULT_CURRENCY; + const label2 = currency; + return { - label1: DEFAULT_CURRENCY, - label2: currency, + label1, + label2, + dataSource: + DataSource[ + this.configurationService.get('DATA_SOURCE_EXCHANGE_RATES') + ], + symbol: `${label1}${label2}`, value: this.exchangeRateDataService.toCurrency( 1, DEFAULT_CURRENCY, diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts index 5e331ca91..5ccfda503 100644 --- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts +++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts @@ -128,10 +128,10 @@ export class AssetProfileDialog implements OnDestroy, OnInit { } this.assetProfileForm.setValue({ - name: this.assetProfile.name, - assetClass: this.assetProfile.assetClass, - assetSubClass: this.assetProfile.assetSubClass, + assetClass: this.assetProfile.assetClass ?? null, + assetSubClass: this.assetProfile.assetSubClass ?? null, comment: this.assetProfile?.comment ?? '', + name: this.assetProfile.name ?? this.assetProfile.symbol, scraperConfiguration: JSON.stringify( this.assetProfile?.scraperConfiguration ?? {} ), diff --git a/apps/client/src/app/components/admin-overview/admin-overview.html b/apps/client/src/app/components/admin-overview/admin-overview.html index 40ae7a150..e82f787f9 100644 --- a/apps/client/src/app/components/admin-overview/admin-overview.html +++ b/apps/client/src/app/components/admin-overview/admin-overview.html @@ -55,6 +55,18 @@ {{ exchangeRate.label2 }} + + +