Browse Source

Merge remote-tracking branch 'origin/main' into task/create-update-activity-dialog-type-safety

pull/7294/head
KenTandrian 4 days ago
parent
commit
cf1dd9ad91
  1. 16
      CHANGELOG.md
  2. 6
      apps/api/src/app/endpoints/market-data/market-data.controller.ts
  3. 8
      apps/api/src/app/endpoints/market-data/market-data.module.ts
  4. 13
      apps/api/src/app/info/info.service.ts
  5. 3
      apps/api/src/services/configuration/configuration.service.ts
  6. 6
      apps/api/src/services/data-provider/data-provider.service.ts
  7. 4
      apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts
  8. 1
      apps/api/src/services/interfaces/environment.interface.ts
  9. 8
      apps/api/src/services/twitter-bot/twitter-bot.module.ts
  10. 10
      apps/api/src/services/twitter-bot/twitter-bot.service.ts
  11. 32
      apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts
  12. 46
      apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts
  13. 12
      apps/client/src/app/pages/about/about-page.component.ts
  14. 11
      apps/client/src/app/pages/admin/admin-page.component.ts
  15. 3
      apps/client/src/app/pages/faq/faq-page.component.ts
  16. 4
      apps/client/src/app/pages/home/home-page.component.ts
  17. 3
      apps/client/src/app/pages/resources/resources-page.component.ts
  18. 10
      apps/client/src/app/pages/user-account/user-account-page.component.ts
  19. 10
      apps/client/src/app/pages/zen/zen-page.component.ts
  20. 2
      apps/client/src/locales/messages.de.xlf
  21. 1
      libs/common/src/lib/config.ts
  22. 4
      package-lock.json
  23. 2
      package.json

16
CHANGELOG.md

@ -5,14 +5,28 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Unreleased
### Added
- Exposed the `DATA_SOURCE_FEAR_AND_GREED_INDEX_STOCKS` environment variable to set the data source of the _Fear & Greed Index_ (market mood)
## 3.23.0 - 2026-07-10
### Changed
- Migrated the deprecated `@nx/webpack:webpack` executor to `@nx/webpack/plugin`
- Set the change detection strategy to `OnPush` in the about page
- Set the change detection strategy to `OnPush` in the admin control panel
- Set the change detection strategy to `OnPush` in the blog page components
- Set the change detection strategy to `OnPush` in the Frequently Asked Questions (FAQ) page
- Set the change detection strategy to `OnPush` in the home page
- Set the change detection strategy to `OnPush` in the markets overview
- Set the change detection strategy to `OnPush` in the resources page
- Set the change detection strategy to `OnPush` in the user account page
- Set the change detection strategy to `OnPush` in the _Zen Mode_
- Improved the language localization for Chinese (`zh`)
- Improved the language localization for German (`de`)
## 3.22.0 - 2026-07-08

6
apps/api/src/app/endpoints/market-data/market-data.controller.ts

@ -1,11 +1,11 @@
import { SymbolService } from '@ghostfolio/api/app/symbol/symbol.service';
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service';
import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service';
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service';
import {
ghostfolioFearAndGreedIndexDataSourceCryptocurrencies,
ghostfolioFearAndGreedIndexDataSourceStocks,
ghostfolioFearAndGreedIndexSymbolCryptocurrencies,
ghostfolioFearAndGreedIndexSymbolStocks
} from '@ghostfolio/common/config';
@ -36,6 +36,7 @@ import { getReasonPhrase, StatusCodes } from 'http-status-codes';
@Controller('market-data')
export class MarketDataController {
public constructor(
private readonly dataProviderService: DataProviderService,
private readonly marketDataService: MarketDataService,
@Inject(REQUEST) private readonly request: RequestWithUser,
private readonly symbolProfileService: SymbolProfileService,
@ -64,7 +65,8 @@ export class MarketDataController {
this.symbolService.get({
includeHistoricalData,
dataGatheringItem: {
dataSource: ghostfolioFearAndGreedIndexDataSourceStocks,
dataSource:
this.dataProviderService.getDataSourceForFearAndGreedIndexStocks(),
symbol: ghostfolioFearAndGreedIndexSymbolStocks
},
useIntradayData: true

8
apps/api/src/app/endpoints/market-data/market-data.module.ts

@ -1,4 +1,5 @@
import { SymbolModule } from '@ghostfolio/api/app/symbol/symbol.module';
import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module';
import { MarketDataModule as MarketDataServiceModule } from '@ghostfolio/api/services/market-data/market-data.module';
import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module';
@ -8,6 +9,11 @@ import { MarketDataController } from './market-data.controller';
@Module({
controllers: [MarketDataController],
imports: [MarketDataServiceModule, SymbolModule, SymbolProfileModule]
imports: [
DataProviderModule,
MarketDataServiceModule,
SymbolModule,
SymbolProfileModule
]
})
export class MarketDataModule {}

13
apps/api/src/app/info/info.service.ts

@ -4,6 +4,7 @@ import { UserService } from '@ghostfolio/api/app/user/user.service';
import { encodeDataSource } from '@ghostfolio/api/helper/data-source.helper';
import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.service';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
import {
@ -15,8 +16,7 @@ import {
PROPERTY_GITHUB_STARGAZERS,
PROPERTY_IS_READ_ONLY_MODE,
PROPERTY_SLACK_COMMUNITY_USERS,
PROPERTY_UPTIME,
ghostfolioFearAndGreedIndexDataSourceStocks
PROPERTY_UPTIME
} from '@ghostfolio/common/config';
import { InfoItem, Statistics } from '@ghostfolio/common/interfaces';
import { permissions } from '@ghostfolio/common/permissions';
@ -33,6 +33,7 @@ export class InfoService {
public constructor(
private readonly benchmarkService: BenchmarkService,
private readonly configurationService: ConfigurationService,
private readonly dataProviderService: DataProviderService,
private readonly exchangeRateDataService: ExchangeRateDataService,
private readonly jwtService: JwtService,
private readonly propertyService: PropertyService,
@ -60,13 +61,15 @@ export class InfoService {
}
if (this.configurationService.get('ENABLE_FEATURE_FEAR_AND_GREED_INDEX')) {
const fearAndGreedIndexDataSource =
this.dataProviderService.getDataSourceForFearAndGreedIndexStocks();
if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) {
info.fearAndGreedDataSource = encodeDataSource(
ghostfolioFearAndGreedIndexDataSourceStocks
fearAndGreedIndexDataSource
);
} else {
info.fearAndGreedDataSource =
ghostfolioFearAndGreedIndexDataSourceStocks;
info.fearAndGreedDataSource = fearAndGreedIndexDataSource;
}
globalPermissions.push(permissions.enableFearAndGreedIndex);

3
apps/api/src/services/configuration/configuration.service.ts

@ -34,6 +34,9 @@ export class ConfigurationService {
CACHE_QUOTES_TTL: num({ default: ms('1 minute') }),
CACHE_TTL: num({ default: CACHE_TTL_NO_CACHE }),
DATA_SOURCE_EXCHANGE_RATES: str({ default: DataSource.YAHOO }),
DATA_SOURCE_FEAR_AND_GREED_INDEX_STOCKS: str({
default: DataSource.RAPID_API
}),
DATA_SOURCE_IMPORT: str({ default: DataSource.YAHOO }),
DATA_SOURCES: json({
default: [DataSource.COINGECKO, DataSource.MANUAL, DataSource.YAHOO]

6
apps/api/src/services/data-provider/data-provider.service.ts

@ -177,6 +177,12 @@ export class DataProviderService implements OnModuleInit {
];
}
public getDataSourceForFearAndGreedIndexStocks(): DataSource {
return DataSource[
this.configurationService.get('DATA_SOURCE_FEAR_AND_GREED_INDEX_STOCKS')
];
}
public getDataSourceForImport(): DataSource {
return DataSource[this.configurationService.get('DATA_SOURCE_IMPORT')];
}

4
apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts

@ -64,6 +64,7 @@ export class RapidApiService implements DataProviderInterface {
if (symbol === ghostfolioFearAndGreedIndexSymbolStocks) {
const fgi = await this.getFearAndGreedIndex();
if (fgi) {
return {
[symbol]: {
[format(getYesterday(), DATE_FORMAT)]: {
@ -72,6 +73,7 @@ export class RapidApiService implements DataProviderInterface {
}
};
}
}
} catch (error) {
throw new Error(
`Could not get historical market data for ${symbol} (${this.getName()}) from ${format(
@ -101,6 +103,7 @@ export class RapidApiService implements DataProviderInterface {
if (symbol === ghostfolioFearAndGreedIndexSymbolStocks) {
const fgi = await this.getFearAndGreedIndex();
if (fgi) {
return {
[symbol]: {
currency: undefined,
@ -110,6 +113,7 @@ export class RapidApiService implements DataProviderInterface {
}
};
}
}
} catch (error) {
this.logger.error(error);
}

1
apps/api/src/services/interfaces/environment.interface.ts

@ -13,6 +13,7 @@ export interface Environment extends CleanedEnvAccessors {
CACHE_QUOTES_TTL: number;
CACHE_TTL: number;
DATA_SOURCE_EXCHANGE_RATES: string;
DATA_SOURCE_FEAR_AND_GREED_INDEX_STOCKS: string;
DATA_SOURCE_IMPORT: string;
DATA_SOURCES: string[];
DATA_SOURCES_GHOSTFOLIO_DATA_PROVIDER: string[];

8
apps/api/src/services/twitter-bot/twitter-bot.module.ts

@ -1,13 +1,19 @@
import { SymbolModule } from '@ghostfolio/api/app/symbol/symbol.module';
import { BenchmarkModule } from '@ghostfolio/api/services/benchmark/benchmark.module';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module';
import { TwitterBotService } from '@ghostfolio/api/services/twitter-bot/twitter-bot.service';
import { Module } from '@nestjs/common';
@Module({
exports: [TwitterBotService],
imports: [BenchmarkModule, ConfigurationModule, SymbolModule],
imports: [
BenchmarkModule,
ConfigurationModule,
DataProviderModule,
SymbolModule
],
providers: [TwitterBotService]
})
export class TwitterBotModule {}

10
apps/api/src/services/twitter-bot/twitter-bot.service.ts

@ -1,10 +1,8 @@
import { SymbolService } from '@ghostfolio/api/app/symbol/symbol.service';
import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.service';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import {
ghostfolioFearAndGreedIndexDataSourceStocks,
ghostfolioFearAndGreedIndexSymbolStocks
} from '@ghostfolio/common/config';
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service';
import { ghostfolioFearAndGreedIndexSymbolStocks } from '@ghostfolio/common/config';
import {
resolveFearAndGreedIndex,
resolveMarketCondition
@ -24,6 +22,7 @@ export class TwitterBotService implements OnModuleInit {
public constructor(
private readonly benchmarkService: BenchmarkService,
private readonly configurationService: ConfigurationService,
private readonly dataProviderService: DataProviderService,
private readonly symbolService: SymbolService
) {}
@ -49,7 +48,8 @@ export class TwitterBotService implements OnModuleInit {
try {
const symbolItem = await this.symbolService.get({
dataGatheringItem: {
dataSource: ghostfolioFearAndGreedIndexDataSourceStocks,
dataSource:
this.dataProviderService.getDataSourceForFearAndGreedIndexStocks(),
symbol: ghostfolioFearAndGreedIndexSymbolStocks
}
});

32
apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts

@ -8,10 +8,10 @@ import { GfValueComponent } from '@ghostfolio/ui/value';
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
inject,
Input,
OnChanges,
Output
output
} from '@angular/core';
import { MatTooltipModule } from '@angular/material/tooltip';
import { IonIcon } from '@ionic/angular/standalone';
@ -40,44 +40,46 @@ export class GfPortfolioSummaryComponent implements OnChanges {
@Input() summary: PortfolioSummary;
@Input() user: User;
@Output() emergencyFundChanged = new EventEmitter<number>();
public emergencyFundChanged = output<number>();
public buyAndSellActivitiesTooltip = translate(
protected readonly buyAndSellActivitiesTooltip = translate(
'BUY_AND_SELL_ACTIVITIES_TOOLTIP'
);
public precision = 2;
public timeInMarket: string;
protected precision = 2;
protected timeInMarket: string | undefined;
public get buyingPowerPercentage() {
private readonly notificationService = inject(NotificationService);
public constructor() {
addIcons({ ellipsisHorizontalCircleOutline, informationCircleOutline });
}
protected get buyingPowerPercentage() {
return this.summary?.totalValueInBaseCurrency
? this.summary.cash / this.summary.totalValueInBaseCurrency
: 0;
}
public get emergencyFundPercentage() {
protected get emergencyFundPercentage() {
return this.summary?.totalValueInBaseCurrency
? (this.summary.emergencyFund?.total || 0) /
this.summary.totalValueInBaseCurrency
: 0;
}
public get excludedFromAnalysisPercentage() {
protected get excludedFromAnalysisPercentage() {
return this.summary?.totalValueInBaseCurrency
? this.summary.excludedAccountsAndActivities /
this.summary.totalValueInBaseCurrency
: 0;
}
public constructor(private notificationService: NotificationService) {
addIcons({ ellipsisHorizontalCircleOutline, informationCircleOutline });
}
public ngOnChanges() {
if (this.summary) {
if (
this.deviceType === 'mobile' &&
this.summary.totalValueInBaseCurrency >=
(this.summary.totalValueInBaseCurrency ?? 0) >=
NUMERICAL_PRECISION_THRESHOLD_6_FIGURES
) {
this.precision = 0;
@ -98,7 +100,7 @@ export class GfPortfolioSummaryComponent implements OnChanges {
}
}
public onEditEmergencyFund() {
protected onEditEmergencyFund() {
this.notificationService.prompt({
confirmFn: (value) => {
const emergencyFund = parseFloat(value.trim()) || 0;

46
apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts

@ -9,7 +9,7 @@ import {
Component,
CUSTOM_ELEMENTS_SCHEMA,
DestroyRef,
Inject,
inject,
OnInit
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
@ -49,28 +49,30 @@ import {
templateUrl: './user-detail-dialog.html'
})
export class GfUserDetailDialogComponent implements OnInit {
public baseCurrency: string;
public readonly getCountryName = getCountryName;
public subscriptionsDataSource = new MatTableDataSource<Subscription>();
public subscriptionsDisplayedColumns = [
protected baseCurrency: string;
protected readonly getCountryName = getCountryName;
protected readonly subscriptionsDataSource =
new MatTableDataSource<Subscription>();
protected readonly subscriptionsDisplayedColumns = [
'createdAt',
'type',
'price',
'expiresAt'
];
public user: AdminUserResponse;
public constructor(
private adminService: AdminService,
private changeDetectorRef: ChangeDetectorRef,
@Inject(MAT_DIALOG_DATA) public data: UserDetailDialogParams,
private dataService: DataService,
private destroyRef: DestroyRef,
public dialogRef: MatDialogRef<
GfUserDetailDialogComponent,
UserDetailDialogResult
>
) {
protected user: AdminUserResponse;
protected readonly data = inject<UserDetailDialogParams>(MAT_DIALOG_DATA);
private readonly adminService = inject(AdminService);
private readonly changeDetectorRef = inject(ChangeDetectorRef);
private readonly dataService = inject(DataService);
private readonly destroyRef = inject(DestroyRef);
private readonly dialogRef =
inject<MatDialogRef<GfUserDetailDialogComponent, UserDetailDialogResult>>(
MatDialogRef
);
public constructor() {
this.baseCurrency = this.dataService.fetchInfo().baseCurrency;
addIcons({
@ -98,14 +100,14 @@ export class GfUserDetailDialogComponent implements OnInit {
});
}
public deleteUser() {
protected deleteUser() {
this.dialogRef.close({
action: 'delete',
userId: this.data.userId
});
}
public getSum() {
protected getSum() {
return getSum(
this.subscriptionsDataSource.data
.filter(({ price }) => {
@ -117,7 +119,7 @@ export class GfUserDetailDialogComponent implements OnInit {
).toNumber();
}
public getType({ createdAt, expiresAt, price }: Subscription) {
protected getType({ createdAt, expiresAt, price }: Subscription) {
if (price) {
return $localize`Paid`;
}
@ -127,7 +129,7 @@ export class GfUserDetailDialogComponent implements OnInit {
: $localize`Coupon`;
}
public onClose() {
protected onClose() {
this.dialogRef.close();
}
}

12
apps/client/src/app/pages/about/about-page.component.ts

@ -8,7 +8,12 @@ import {
} from '@ghostfolio/ui/page-tabs';
import { DataService } from '@ghostfolio/ui/services';
import { ChangeDetectorRef, Component, DestroyRef } from '@angular/core';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
DestroyRef
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { addIcons } from 'ionicons';
import {
@ -21,6 +26,7 @@ import {
} from 'ionicons/icons';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'page' },
imports: [GfPageTabsComponent],
selector: 'gf-about-page',
@ -83,8 +89,6 @@ export class AboutPageComponent {
});
this.user = state.user;
this.changeDetectorRef.markForCheck();
}
this.tabs.push({
@ -92,6 +96,8 @@ export class AboutPageComponent {
label: publicRoutes.about.subRoutes.ossFriends.title,
routerLink: publicRoutes.about.subRoutes.ossFriends.routerLink
});
this.changeDetectorRef.markForCheck();
});
addIcons({

11
apps/client/src/app/pages/admin/admin-page.component.ts

@ -12,7 +12,12 @@ import {
TabConfiguration
} from '@ghostfolio/ui/page-tabs';
import { Component, inject } from '@angular/core';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
inject
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { addIcons } from 'ionicons';
import {
@ -24,6 +29,7 @@ import {
} from 'ionicons/icons';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'page' },
imports: [GfPageTabsComponent],
selector: 'gf-admin-page',
@ -35,6 +41,7 @@ export class AdminPageComponent {
private user: User;
private readonly changeDetectorRef = inject(ChangeDetectorRef);
private readonly tokenStorageService = inject(TokenStorageService);
private readonly userService = inject(UserService);
@ -45,6 +52,8 @@ export class AdminPageComponent {
this.user = state?.user;
this.initializeTabs();
this.changeDetectorRef.markForCheck();
});
addIcons({

3
apps/client/src/app/pages/faq/faq-page.component.ts

@ -6,11 +6,12 @@ import {
} from '@ghostfolio/ui/page-tabs';
import { DataService } from '@ghostfolio/ui/services';
import { Component } from '@angular/core';
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { addIcons } from 'ionicons';
import { cloudyOutline, readerOutline, serverOutline } from 'ionicons/icons';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'page' },
imports: [GfPageTabsComponent],
selector: 'gf-faq-page',

4
apps/client/src/app/pages/home/home-page.component.ts

@ -9,6 +9,7 @@ import {
} from '@ghostfolio/ui/page-tabs';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
DestroyRef,
@ -25,6 +26,7 @@ import {
} from 'ionicons/icons';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'page' },
imports: [GfPageTabsComponent],
selector: 'gf-home-page',
@ -85,9 +87,9 @@ export class GfHomePageComponent implements OnInit {
: internalRoutes.home.subRoutes.markets.routerLink
}
];
}
this.changeDetectorRef.markForCheck();
}
});
addIcons({

3
apps/client/src/app/pages/resources/resources-page.component.ts

@ -4,7 +4,7 @@ import {
TabConfiguration
} from '@ghostfolio/ui/page-tabs';
import { Component } from '@angular/core';
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { addIcons } from 'ionicons';
import {
bookOutline,
@ -14,6 +14,7 @@ import {
} from 'ionicons/icons';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'page' },
imports: [GfPageTabsComponent],
selector: 'gf-resources-page',

10
apps/client/src/app/pages/user-account/user-account-page.component.ts

@ -6,12 +6,18 @@ import {
TabConfiguration
} from '@ghostfolio/ui/page-tabs';
import { ChangeDetectorRef, Component, DestroyRef } from '@angular/core';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
DestroyRef
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { addIcons } from 'ionicons';
import { diamondOutline, keyOutline, settingsOutline } from 'ionicons/icons';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'page' },
imports: [GfPageTabsComponent],
selector: 'gf-user-account-page',
@ -52,9 +58,9 @@ export class GfUserAccountPageComponent {
routerLink: internalRoutes.account.subRoutes.access.routerLink
}
];
}
this.changeDetectorRef.markForCheck();
}
});
addIcons({ diamondOutline, keyOutline, settingsOutline });

10
apps/client/src/app/pages/zen/zen-page.component.ts

@ -6,12 +6,18 @@ import {
TabConfiguration
} from '@ghostfolio/ui/page-tabs';
import { ChangeDetectorRef, Component, DestroyRef } from '@angular/core';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
DestroyRef
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { addIcons } from 'ionicons';
import { albumsOutline, analyticsOutline } from 'ionicons/icons';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'page' },
imports: [GfPageTabsComponent],
selector: 'gf-zen-page',
@ -44,9 +50,9 @@ export class GfZenPageComponent {
}
];
this.user = state.user;
}
this.changeDetectorRef.markForCheck();
}
});
addIcons({ albumsOutline, analyticsOutline });

2
apps/client/src/locales/messages.de.xlf

@ -1739,7 +1739,7 @@
</trans-unit>
<trans-unit id="7407646470109951507" datatype="html">
<source>popular</source>
<target state="new">popular</target>
<target state="translated">beliebt</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-settings/admin-settings.component.html</context>
<context context-type="linenumber">79</context>

1
libs/common/src/lib/config.ts

@ -11,7 +11,6 @@ export const ghostfolioScraperApiSymbolPrefix = `_${ghostfolioPrefix}_`;
export const ghostfolioFearAndGreedIndexDataSourceCryptocurrencies =
DataSource.MANUAL;
export const ghostfolioFearAndGreedIndexDataSourceStocks = DataSource.RAPID_API;
export const ghostfolioFearAndGreedIndexSymbolCryptocurrencies = `${ghostfolioPrefix}_FEAR_AND_GREED_INDEX_CRYPTOCURRENCIES`;
export const ghostfolioFearAndGreedIndexSymbolStocks = `${ghostfolioPrefix}_FEAR_AND_GREED_INDEX_STOCKS`;

4
package-lock.json

@ -1,12 +1,12 @@
{
"name": "ghostfolio",
"version": "3.22.0",
"version": "3.23.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ghostfolio",
"version": "3.22.0",
"version": "3.23.0",
"hasInstallScript": true,
"license": "AGPL-3.0",
"dependencies": {

2
package.json

@ -1,6 +1,6 @@
{
"name": "ghostfolio",
"version": "3.22.0",
"version": "3.23.0",
"homepage": "https://ghostfol.io",
"license": "AGPL-3.0",
"repository": "https://github.com/ghostfolio/ghostfolio",

Loading…
Cancel
Save