diff --git a/CHANGELOG.md b/CHANGELOG.md index 3bab8d75d..3fb49cfa9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,10 +11,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added support for filtering in the _Copy AI prompt to clipboard_ actions on the analysis page (experimental) - Added support for generating a new _Security Token_ via the users table of the admin control panel +- Added an endpoint to localize the `site.webmanifest` +- Added the _Storybook_ path to the `sitemap.xml` file ### Changed +- Improved the export functionality by applying filters on accounts and tags - Improved the symbol validation in the _Yahoo Finance_ service (get asset profiles) +- Refactored `lodash.uniq` with `Array.from(new Set(...))` - Refreshed the cryptocurrencies list ### Fixed diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index cea43095d..1c45aeca1 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -60,6 +60,10 @@ Remove permission in `UserService` using `without()` Use `@if (user?.settings?.isExperimentalFeatures) {}` in HTML template +## Component Library (_Storybook_) + +https://ghostfol.io/development/storybook + ## Git ### Rebase diff --git a/README.md b/README.md index 14477ea9a..ed82ac723 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ Ghostfolio is for you if you are... - ✅ Create, update and delete transactions - ✅ Multi account management -- ✅ Portfolio performance: Time-weighted rate of return (TWR) for `Today`, `WTD`, `MTD`, `YTD`, `1Y`, `5Y`, `Max` +- ✅ Portfolio performance: Return on Average Investment (ROAI) for `Today`, `WTD`, `MTD`, `YTD`, `1Y`, `5Y`, `Max` - ✅ Various charts - ✅ Static analysis to identify potential risks in your portfolio - ✅ Import and export transactions diff --git a/apps/api/src/app/app.module.ts b/apps/api/src/app/app.module.ts index 2a515bf43..99080e1e1 100644 --- a/apps/api/src/app/app.module.ts +++ b/apps/api/src/app/app.module.ts @@ -32,6 +32,7 @@ import { AuthModule } from './auth/auth.module'; import { CacheModule } from './cache/cache.module'; import { AiModule } from './endpoints/ai/ai.module'; import { ApiKeysModule } from './endpoints/api-keys/api-keys.module'; +import { AssetsModule } from './endpoints/assets/assets.module'; import { BenchmarksModule } from './endpoints/benchmarks/benchmarks.module'; import { GhostfolioModule } from './endpoints/data-providers/ghostfolio/ghostfolio.module'; import { MarketDataModule } from './endpoints/market-data/market-data.module'; @@ -61,6 +62,7 @@ import { UserModule } from './user/user.module'; AiModule, ApiKeysModule, AssetModule, + AssetsModule, AuthDeviceModule, AuthModule, BenchmarksModule, diff --git a/apps/api/src/app/endpoints/assets/assets.controller.ts b/apps/api/src/app/endpoints/assets/assets.controller.ts new file mode 100644 index 000000000..1735cc594 --- /dev/null +++ b/apps/api/src/app/endpoints/assets/assets.controller.ts @@ -0,0 +1,46 @@ +import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; +import { interpolate } from '@ghostfolio/common/helper'; + +import { + Controller, + Get, + Param, + Res, + Version, + VERSION_NEUTRAL +} from '@nestjs/common'; +import { Response } from 'express'; +import { readFileSync } from 'fs'; +import { join } from 'path'; + +@Controller('assets') +export class AssetsController { + private webManifest = ''; + + public constructor( + public readonly configurationService: ConfigurationService + ) { + try { + this.webManifest = readFileSync( + join(__dirname, 'assets', 'site.webmanifest'), + 'utf8' + ); + } catch {} + } + + @Get('/:languageCode/site.webmanifest') + @Version(VERSION_NEUTRAL) + public getWebManifest( + @Param('languageCode') languageCode: string, + @Res() response: Response + ): void { + const rootUrl = this.configurationService.get('ROOT_URL'); + const webManifest = interpolate(this.webManifest, { + languageCode, + rootUrl + }); + + response.setHeader('Content-Type', 'application/json'); + response.send(webManifest); + } +} diff --git a/apps/api/src/app/endpoints/assets/assets.module.ts b/apps/api/src/app/endpoints/assets/assets.module.ts new file mode 100644 index 000000000..51d330e50 --- /dev/null +++ b/apps/api/src/app/endpoints/assets/assets.module.ts @@ -0,0 +1,11 @@ +import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; + +import { Module } from '@nestjs/common'; + +import { AssetsController } from './assets.controller'; + +@Module({ + controllers: [AssetsController], + providers: [ConfigurationService] +}) +export class AssetsModule {} diff --git a/apps/api/src/app/export/export.controller.ts b/apps/api/src/app/export/export.controller.ts index 551b3e489..d807132c9 100644 --- a/apps/api/src/app/export/export.controller.ts +++ b/apps/api/src/app/export/export.controller.ts @@ -21,10 +21,11 @@ export class ExportController { @UseGuards(AuthGuard('jwt'), HasPermissionGuard) public async export( @Query('accounts') filterByAccounts?: string, - @Query('activityIds') activityIds?: string[], + @Query('activityIds') filterByActivityIds?: string, @Query('assetClasses') filterByAssetClasses?: string, @Query('tags') filterByTags?: string ): Promise { + const activityIds = filterByActivityIds?.split(',') ?? []; const filters = this.apiService.buildFiltersFromQueryParams({ filterByAccounts, filterByAssetClasses, diff --git a/apps/api/src/app/export/export.service.ts b/apps/api/src/app/export/export.service.ts index 8b9d2c56c..f0449dc14 100644 --- a/apps/api/src/app/export/export.service.ts +++ b/apps/api/src/app/export/export.service.ts @@ -28,6 +28,22 @@ export class ExportService { }): Promise { const platformsMap: { [platformId: string]: Platform } = {}; + let { activities } = await this.orderService.getOrders({ + filters, + userCurrency, + userId, + includeDrafts: true, + sortColumn: 'date', + sortDirection: 'asc', + withExcludedAccounts: true + }); + + if (activityIds?.length > 0) { + activities = activities.filter(({ id }) => { + return activityIds.includes(id); + }); + } + const accounts = ( await this.accountService.accounts({ include: { @@ -39,57 +55,55 @@ export class ExportService { }, where: { userId } }) - ).map( - ({ - balance, - balances, - comment, - currency, - id, - isExcluded, - name, - Platform: platform, - platformId - }) => { - if (platformId) { - platformsMap[platformId] = platform; - } - - return { + ) + .filter(({ id }) => { + return activities.length > 0 + ? activities.some(({ accountId }) => { + return accountId === id; + }) + : true; + }) + .map( + ({ balance, - balances: balances.map(({ date, value }) => { - return { date: date.toISOString(), value }; - }), + balances, comment, currency, id, isExcluded, name, + Platform: platform, platformId - }; - } - ); - - let { activities } = await this.orderService.getOrders({ - filters, - userCurrency, - userId, - includeDrafts: true, - sortColumn: 'date', - sortDirection: 'asc', - withExcludedAccounts: true - }); + }) => { + if (platformId) { + platformsMap[platformId] = platform; + } - if (activityIds) { - activities = activities.filter((activity) => { - return activityIds.includes(activity.id); - }); - } + return { + balance, + balances: balances.map(({ date, value }) => { + return { date: date.toISOString(), value }; + }), + comment, + currency, + id, + isExcluded, + name, + platformId + }; + } + ); const tags = (await this.tagService.getTagsForUser(userId)) - .filter(({ isUsed }) => { - return isUsed; - }) + .filter( + ({ id, isUsed }) => + isUsed && + activities.some((activity) => { + return activity.tags.some(({ id: tagId }) => { + return tagId === id; + }); + }) + ) .map(({ id, name }) => { return { id, diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index 54d80a955..52d57230b 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -49,7 +49,7 @@ import { min, subDays } from 'date-fns'; -import { isNumber, sortBy, sum, uniq, uniqBy } from 'lodash'; +import { isNumber, sortBy, sum, uniqBy } from 'lodash'; export abstract class PortfolioCalculator { protected static readonly ENABLE_LOGGING = false; @@ -222,7 +222,7 @@ export abstract class PortfolioCalculator { const exchangeRatesByCurrency = await this.exchangeRateDataService.getExchangeRatesByCurrency({ - currencies: uniq(Object.values(currencies)), + currencies: Array.from(new Set(Object.values(currencies))), endDate: endOfDay(this.endDate), startDate: this.startDate, targetCurrency: this.currency diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index e90ebd4ae..a3d9e3c4a 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -82,7 +82,7 @@ import { parseISO, set } from 'date-fns'; -import { isEmpty, uniq } from 'lodash'; +import { isEmpty } from 'lodash'; import { PortfolioCalculator } from './calculator/portfolio-calculator'; import { @@ -2032,14 +2032,16 @@ export class PortfolioService { where: { id: filters[0].id } }); } else { - const accountIds = uniq( - activities - .filter(({ accountId }) => { - return accountId; - }) - .map(({ accountId }) => { - return accountId; - }) + const accountIds = Array.from( + new Set( + activities + .filter(({ accountId }) => { + return accountId; + }) + .map(({ accountId }) => { + return accountId; + }) + ) ); currentAccounts = await this.accountService.accounts({ diff --git a/apps/api/src/app/sitemap/sitemap.controller.ts b/apps/api/src/app/sitemap/sitemap.controller.ts index ea21906ef..aad5e39a1 100644 --- a/apps/api/src/app/sitemap/sitemap.controller.ts +++ b/apps/api/src/app/sitemap/sitemap.controller.ts @@ -9,8 +9,8 @@ import { personalFinanceTools } from '@ghostfolio/common/personal-finance-tools' import { Controller, Get, Res, VERSION_NEUTRAL, Version } from '@nestjs/common'; import { format } from 'date-fns'; import { Response } from 'express'; -import * as fs from 'fs'; -import * as path from 'path'; +import { readFileSync } from 'fs'; +import { join } from 'path'; @Controller('sitemap.xml') export class SitemapController { @@ -20,8 +20,8 @@ export class SitemapController { private readonly configurationService: ConfigurationService ) { try { - this.sitemapXml = fs.readFileSync( - path.join(__dirname, 'assets', 'sitemap.xml'), + this.sitemapXml = readFileSync( + join(__dirname, 'assets', 'sitemap.xml'), 'utf8' ); } catch {} diff --git a/apps/client/src/assets/site.webmanifest b/apps/api/src/assets/site.webmanifest similarity index 92% rename from apps/client/src/assets/site.webmanifest rename to apps/api/src/assets/site.webmanifest index 8f1eceefb..a28719625 100644 --- a/apps/client/src/assets/site.webmanifest +++ b/apps/api/src/assets/site.webmanifest @@ -25,7 +25,7 @@ "name": "Ghostfolio", "orientation": "portrait", "short_name": "Ghostfolio", - "start_url": "/en/", + "start_url": "/${languageCode}/", "theme_color": "#FFFFFF", - "url": "https://ghostfol.io" + "url": "${rootUrl}" } diff --git a/apps/api/src/assets/sitemap.xml b/apps/api/src/assets/sitemap.xml index a422ff31a..fc1e89dba 100644 --- a/apps/api/src/assets/sitemap.xml +++ b/apps/api/src/assets/sitemap.xml @@ -92,6 +92,10 @@ https://ghostfol.io/de/ueber-uns/oss-friends ${currentDate}T00:00:00+00:00 + + https://ghostfol.io/development/storybook + ${currentDate}T00:00:00+00:00 + https://ghostfol.io/en ${currentDate}T00:00:00+00:00 diff --git a/apps/api/src/environments/environment.prod.ts b/apps/api/src/environments/environment.prod.ts index 81b324963..6d4cbb4bf 100644 --- a/apps/api/src/environments/environment.prod.ts +++ b/apps/api/src/environments/environment.prod.ts @@ -1,4 +1,7 @@ +import { DEFAULT_HOST, DEFAULT_PORT } from '@ghostfolio/common/config'; + export const environment = { production: true, + rootUrl: `http://${DEFAULT_HOST}:${DEFAULT_PORT}`, version: `${require('../../../../package.json').version}` }; diff --git a/apps/api/src/environments/environment.ts b/apps/api/src/environments/environment.ts index c0ae2e7e5..054766460 100644 --- a/apps/api/src/environments/environment.ts +++ b/apps/api/src/environments/environment.ts @@ -1,4 +1,7 @@ +import { DEFAULT_HOST } from '@ghostfolio/common/config'; + export const environment = { production: false, + rootUrl: `https://${DEFAULT_HOST}:4200`, version: 'dev' }; diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index 7cd5953b0..73502525c 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -1,4 +1,8 @@ -import { STORYBOOK_PATH } from '@ghostfolio/common/config'; +import { + DEFAULT_HOST, + DEFAULT_PORT, + STORYBOOK_PATH +} from '@ghostfolio/common/config'; import { Logger, @@ -75,8 +79,8 @@ async function bootstrap() { app.use(HtmlTemplateMiddleware); - const HOST = configService.get('HOST') || '0.0.0.0'; - const PORT = configService.get('PORT') || 3333; + const HOST = configService.get('HOST') || DEFAULT_HOST; + const PORT = configService.get('PORT') || DEFAULT_PORT; await app.listen(PORT, HOST, () => { logLogo(); diff --git a/apps/api/src/middlewares/html-template.middleware.ts b/apps/api/src/middlewares/html-template.middleware.ts index 256876952..403b09610 100644 --- a/apps/api/src/middlewares/html-template.middleware.ts +++ b/apps/api/src/middlewares/html-template.middleware.ts @@ -2,7 +2,6 @@ import { environment } from '@ghostfolio/api/environments/environment'; import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; import { DEFAULT_LANGUAGE_CODE, - DEFAULT_ROOT_URL, STORYBOOK_PATH, SUPPORTED_LANGUAGE_CODES } from '@ghostfolio/common/config'; @@ -126,7 +125,7 @@ export const HtmlTemplateMiddleware = async ( } const currentDate = format(new Date(), DATE_FORMAT); - const rootUrl = process.env.ROOT_URL || DEFAULT_ROOT_URL; + const rootUrl = process.env.ROOT_URL || environment.rootUrl; if ( path.startsWith('/api/') || diff --git a/apps/api/src/services/configuration/configuration.service.ts b/apps/api/src/services/configuration/configuration.service.ts index 3dfe5d5c5..473d909ee 100644 --- a/apps/api/src/services/configuration/configuration.service.ts +++ b/apps/api/src/services/configuration/configuration.service.ts @@ -1,11 +1,13 @@ +import { environment } from '@ghostfolio/api/environments/environment'; import { Environment } from '@ghostfolio/api/services/interfaces/environment.interface'; import { CACHE_TTL_NO_CACHE, + DEFAULT_HOST, + DEFAULT_PORT, DEFAULT_PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY, DEFAULT_PROCESSOR_GATHER_HISTORICAL_MARKET_DATA_CONCURRENCY, DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_CONCURRENCY, - DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT, - DEFAULT_ROOT_URL + DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT } from '@ghostfolio/common/config'; import { Injectable } from '@nestjs/common'; @@ -49,11 +51,11 @@ export class ConfigurationService { GOOGLE_SHEETS_ACCOUNT: str({ default: '' }), GOOGLE_SHEETS_ID: str({ default: '' }), GOOGLE_SHEETS_PRIVATE_KEY: str({ default: '' }), - HOST: host({ default: '0.0.0.0' }), + HOST: host({ default: DEFAULT_HOST }), JWT_SECRET_KEY: str({}), MAX_ACTIVITIES_TO_IMPORT: num({ default: Number.MAX_SAFE_INTEGER }), MAX_CHART_ITEMS: num({ default: 365 }), - PORT: port({ default: 3333 }), + PORT: port({ default: DEFAULT_PORT }), PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY: num({ default: DEFAULT_PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY }), @@ -71,7 +73,9 @@ export class ConfigurationService { REDIS_PASSWORD: str({ default: '' }), REDIS_PORT: port({ default: 6379 }), REQUEST_TIMEOUT: num({ default: ms('3 seconds') }), - ROOT_URL: url({ default: DEFAULT_ROOT_URL }), + ROOT_URL: url({ + default: environment.rootUrl + }), STRIPE_PUBLIC_KEY: str({ default: '' }), STRIPE_SECRET_KEY: str({ default: '' }), TWITTER_ACCESS_TOKEN: str({ default: 'dummyAccessToken' }), diff --git a/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts b/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts index db95a3487..0a2d177ce 100644 --- a/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts +++ b/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts @@ -23,7 +23,7 @@ import { isToday, subDays } from 'date-fns'; -import { isNumber, uniq } from 'lodash'; +import { isNumber } from 'lodash'; import ms from 'ms'; @Injectable() @@ -515,7 +515,7 @@ export class ExchangeRateDataService { } } - return uniq(currencies).filter(Boolean).sort(); + return Array.from(new Set(currencies)).filter(Boolean).sort(); } private prepareCurrencyPairs(aCurrencies: string[]) { diff --git a/apps/client/ngsw-config.json b/apps/client/ngsw-config.json index c0f03a135..56e1cfd63 100644 --- a/apps/client/ngsw-config.json +++ b/apps/client/ngsw-config.json @@ -6,13 +6,7 @@ "name": "app", "installMode": "prefetch", "resources": { - "files": [ - "/favicon.ico", - "/index.html", - "/assets/site.webmanifest", - "/*.css", - "/*.js" - ] + "files": ["/favicon.ico", "/index.html", "/*.css", "/*.js"] } }, { diff --git a/apps/client/project.json b/apps/client/project.json index 160a27ea7..b2144d7b3 100644 --- a/apps/client/project.json +++ b/apps/client/project.json @@ -146,9 +146,6 @@ { "command": "shx cp apps/client/src/assets/robots.txt dist/apps/client" }, - { - "command": "shx cp apps/client/src/assets/site.webmanifest dist/apps/client" - }, { "command": "shx cp node_modules/ionicons/dist/index.js dist/apps/client" }, diff --git a/apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.component.ts b/apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.component.ts index b0f69fa5c..e84554577 100644 --- a/apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.component.ts +++ b/apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.component.ts @@ -20,7 +20,6 @@ import { } from '@angular/forms'; import { MatDialogRef } from '@angular/material/dialog'; import { isISO4217CurrencyCode } from 'class-validator'; -import { uniq } from 'lodash'; import { Subject, takeUntil } from 'rxjs'; import { CreateAssetProfileDialogMode } from './interfaces/interfaces'; @@ -87,7 +86,9 @@ export class CreateAssetProfileDialog implements OnInit, OnDestroy { this.createAssetProfileForm.get('addCurrency').value as string ).toUpperCase(); - const currencies = uniq([...this.customCurrencies, currency]).sort(); + const currencies = Array.from( + new Set([...this.customCurrencies, currency]) + ).sort(); this.dataService .putAdminSetting(PROPERTY_CURRENCIES, { diff --git a/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts b/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts index ced617117..1ee23ff8a 100644 --- a/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts +++ b/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts @@ -24,7 +24,6 @@ import { FormBuilder, Validators } from '@angular/forms'; import { MatSlideToggleChange } from '@angular/material/slide-toggle'; import { MatSnackBar } from '@angular/material/snack-bar'; import { format, parseISO } from 'date-fns'; -import { uniq } from 'lodash'; import ms from 'ms'; import { EMPTY, Subject, throwError } from 'rxjs'; import { catchError, takeUntil } from 'rxjs/operators'; @@ -108,7 +107,7 @@ export class UserAccountSettingsComponent implements OnDestroy, OnInit { ); this.locales.push(this.user.settings.locale); - this.locales = uniq(this.locales.sort()); + this.locales = Array.from(new Set(this.locales)).sort(); this.changeDetectorRef.markForCheck(); } diff --git a/apps/client/src/index.html b/apps/client/src/index.html index 47f2c3d1a..e11bd1575 100644 --- a/apps/client/src/index.html +++ b/apps/client/src/index.html @@ -45,7 +45,10 @@ sizes="16x16" type="image/png" /> - + diff --git a/apps/client/src/locales/messages.ca.xlf b/apps/client/src/locales/messages.ca.xlf index 0f9de4906..52a1a1dac 100644 --- a/apps/client/src/locales/messages.ca.xlf +++ b/apps/client/src/locales/messages.ca.xlf @@ -2475,7 +2475,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 160 + 159 @@ -3343,7 +3343,7 @@ Auto apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 40 + 39 @@ -3351,7 +3351,7 @@ Do you really want to close your Ghostfolio account? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 175 + 174 @@ -3359,7 +3359,7 @@ Do you really want to remove this sign in method? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 249 + 248 @@ -3367,7 +3367,7 @@ Oops! There was an error setting up biometric authentication. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 302 @@ -7589,7 +7589,7 @@ AI prompt has been copied to the clipboard apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 170 + 173 @@ -7685,7 +7685,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 171 + 174 diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index 223253bae..49495d26e 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -1022,7 +1022,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 160 + 159 @@ -1662,7 +1662,7 @@ Möchtest du diese Anmeldemethode wirklich löschen? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 249 + 248 @@ -2906,7 +2906,7 @@ Automatisch apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 40 + 39 @@ -6603,7 +6603,7 @@ Möchtest du dieses Ghostfolio Konto wirklich schliessen? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 175 + 174 @@ -6651,7 +6651,7 @@ Ups! Beim Einrichten der biometrischen Authentifizierung ist ein Fehler aufgetreten. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 302 @@ -7589,7 +7589,7 @@ KI-Anweisung wurde in die Zwischenablage kopiert apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 170 + 173 @@ -7685,7 +7685,7 @@ Öffne Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 171 + 174 diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index a763a3902..2997331e2 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -1023,7 +1023,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 160 + 159 @@ -1663,7 +1663,7 @@ ¿Estás seguro de eliminar este método de acceso? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 249 + 248 @@ -2907,7 +2907,7 @@ Automático apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 40 + 39 @@ -6604,7 +6604,7 @@ ¿Estás seguro de querer borrar tu cuenta de Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 175 + 174 @@ -6652,7 +6652,7 @@ Oops! There was an error setting up biometric authentication. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 302 @@ -7590,7 +7590,7 @@ AI prompt has been copied to the clipboard apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 170 + 173 @@ -7686,7 +7686,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 171 + 174 diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index 0e7b6b9aa..3819bc98d 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -1334,7 +1334,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 160 + 159 @@ -1878,7 +1878,7 @@ Auto apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 40 + 39 @@ -1918,7 +1918,7 @@ Voulez-vous vraiment supprimer cette méthode de connexion ? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 249 + 248 @@ -6603,7 +6603,7 @@ Confirmer la suppresion de votre compte Ghostfolio ? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 175 + 174 @@ -6651,7 +6651,7 @@ Oops! Une erreur s'est produite lors de la configuration de l'authentification biométrique. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 302 @@ -7589,7 +7589,7 @@ AI prompt has been copied to the clipboard apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 170 + 173 @@ -7685,7 +7685,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 171 + 174 diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index 4ab6c53a1..257f8f68a 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -1023,7 +1023,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 160 + 159 @@ -1663,7 +1663,7 @@ Vuoi davvero rimuovere questo metodo di accesso? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 249 + 248 @@ -2907,7 +2907,7 @@ Auto apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 40 + 39 @@ -6604,7 +6604,7 @@ Confermi di voler chiudere il tuo account Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 175 + 174 @@ -6652,7 +6652,7 @@ Ops! C'è stato un errore impostando l'autenticazione biometrica. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 302 @@ -7590,7 +7590,7 @@ AI prompt has been copied to the clipboard apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 170 + 173 @@ -7686,7 +7686,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 171 + 174 diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf index 13671956d..00341b16c 100644 --- a/apps/client/src/locales/messages.nl.xlf +++ b/apps/client/src/locales/messages.nl.xlf @@ -1022,7 +1022,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 160 + 159 @@ -1662,7 +1662,7 @@ Wil je deze aanmeldingsmethode echt verwijderen? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 249 + 248 @@ -2906,7 +2906,7 @@ Automatisch apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 40 + 39 @@ -6603,7 +6603,7 @@ Do you really want to close your Ghostfolio account? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 175 + 174 @@ -6651,7 +6651,7 @@ Oops! There was an error setting up biometric authentication. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 302 @@ -7589,7 +7589,7 @@ AI prompt has been copied to the clipboard apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 170 + 173 @@ -7685,7 +7685,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 171 + 174 diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index ac208d13a..aaed78ea7 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -2287,7 +2287,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 160 + 159 @@ -3075,7 +3075,7 @@ Auto apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 40 + 39 @@ -3083,7 +3083,7 @@ Czy na pewno chcesz usunąć tą metode logowania? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 249 + 248 @@ -6603,7 +6603,7 @@ Czy na pewno chcesz zamknąć swoje konto Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 175 + 174 @@ -6651,7 +6651,7 @@ Ups! Wystąpił błąd podczas konfigurowania uwierzytelniania biometrycznego. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 302 @@ -7589,7 +7589,7 @@ AI prompt has been copied to the clipboard apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 170 + 173 @@ -7685,7 +7685,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 171 + 174 diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index 789ee6360..5fe949db4 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -1206,7 +1206,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 160 + 159 @@ -1862,7 +1862,7 @@ Auto apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 40 + 39 @@ -1902,7 +1902,7 @@ Deseja realmente remover este método de início de sessão? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 249 + 248 @@ -6603,7 +6603,7 @@ Do you really want to close your Ghostfolio account? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 175 + 174 @@ -6651,7 +6651,7 @@ Oops! There was an error setting up biometric authentication. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 302 @@ -7589,7 +7589,7 @@ AI prompt has been copied to the clipboard apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 170 + 173 @@ -7685,7 +7685,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 171 + 174 diff --git a/apps/client/src/locales/messages.tr.xlf b/apps/client/src/locales/messages.tr.xlf index 05e2566f8..2e385d887 100644 --- a/apps/client/src/locales/messages.tr.xlf +++ b/apps/client/src/locales/messages.tr.xlf @@ -2135,7 +2135,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 160 + 159 @@ -4895,7 +4895,7 @@ Otomatik apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 40 + 39 @@ -4935,7 +4935,7 @@ Bu giriş yöntemini kaldırmayı gerçekten istiyor musunuz? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 249 + 248 @@ -6603,7 +6603,7 @@ Do you really want to close your Ghostfolio account? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 175 + 174 @@ -6651,7 +6651,7 @@ Oops! There was an error setting up biometric authentication. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 302 @@ -7589,7 +7589,7 @@ AI prompt has been copied to the clipboard apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 170 + 173 @@ -7685,7 +7685,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 171 + 174 diff --git a/apps/client/src/locales/messages.uk.xlf b/apps/client/src/locales/messages.uk.xlf index 94d3893ba..b2dc82d73 100644 --- a/apps/client/src/locales/messages.uk.xlf +++ b/apps/client/src/locales/messages.uk.xlf @@ -2595,7 +2595,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 160 + 159 @@ -3591,7 +3591,7 @@ Автоматичний apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 40 + 39 @@ -3599,7 +3599,7 @@ Ви дійсно хочете закрити ваш обліковий запис Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 175 + 174 @@ -3607,7 +3607,7 @@ Ви дійсно хочете вилучити цей спосіб входу? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 249 + 248 @@ -3615,7 +3615,7 @@ Упс! Виникла помилка під час налаштування біометричної автентифікації. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 302 @@ -7597,7 +7597,7 @@ Запит AI скопійовано в буфер обміну apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 170 + 173 @@ -7685,7 +7685,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 171 + 174 diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf index c1ec934be..417df8c83 100644 --- a/apps/client/src/locales/messages.xlf +++ b/apps/client/src/locales/messages.xlf @@ -2152,7 +2152,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 160 + 159 @@ -2864,14 +2864,14 @@ Auto apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 40 + 39 Do you really want to remove this sign in method? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 249 + 248 @@ -6009,7 +6009,7 @@ Do you really want to close your Ghostfolio account? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 175 + 174 @@ -6044,7 +6044,7 @@ Oops! There was an error setting up biometric authentication. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 302 @@ -6867,7 +6867,7 @@ AI prompt has been copied to the clipboard apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 170 + 173 @@ -6951,7 +6951,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 171 + 174 diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf index 6d6054df6..ca4b21fe0 100644 --- a/apps/client/src/locales/messages.zh.xlf +++ b/apps/client/src/locales/messages.zh.xlf @@ -2296,7 +2296,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 160 + 159 @@ -3084,7 +3084,7 @@ 自动 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 40 + 39 @@ -3092,7 +3092,7 @@ 您确实要删除此登录方法吗? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 249 + 248 @@ -6604,7 +6604,7 @@ Do you really want to close your Ghostfolio account? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 175 + 174 @@ -6652,7 +6652,7 @@ Oops! There was an error setting up biometric authentication. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 303 + 302 @@ -7590,7 +7590,7 @@ AI prompt has been copied to the clipboard apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 170 + 173 @@ -7686,7 +7686,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 171 + 174 diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index 696ca86d2..b8588fd0d 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -48,13 +48,14 @@ export const PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE_PRIORITY_LOW = export const DEFAULT_CURRENCY = 'USD'; export const DEFAULT_DATE_FORMAT_MONTH_YEAR = 'MMM yyyy'; +export const DEFAULT_HOST = '0.0.0.0'; export const DEFAULT_LANGUAGE_CODE = 'en'; export const DEFAULT_PAGE_SIZE = 50; +export const DEFAULT_PORT = 3333; export const DEFAULT_PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY = 1; export const DEFAULT_PROCESSOR_GATHER_HISTORICAL_MARKET_DATA_CONCURRENCY = 1; export const DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_CONCURRENCY = 1; export const DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT = 30000; -export const DEFAULT_ROOT_URL = 'https://localhost:4200'; // USX is handled separately export const DERIVED_CURRENCIES = [ diff --git a/libs/ui/src/lib/fire-calculator/fire-calculator.component.stories.ts b/libs/ui/src/lib/fire-calculator/fire-calculator.component.stories.ts index 0ad868ff9..e4cfa18ea 100644 --- a/libs/ui/src/lib/fire-calculator/fire-calculator.component.stories.ts +++ b/libs/ui/src/lib/fire-calculator/fire-calculator.component.stories.ts @@ -45,7 +45,7 @@ type Story = StoryObj; export const Simple: Story = { args: { currency: 'USD', - fireWealth: 0, + fireWealth: 50000, locale: locale } };