Compare commits

..

8 Commits

Author SHA1 Message Date
06d5ec9182 Release 1.117.0 (#713) 2022-02-19 19:48:51 +01:00
122107c8a1 Feature/distinguish today s data point in admin panel (#711)
* Distinguish today's data point

* Update changelog
2022-02-19 19:46:36 +01:00
ca46a9827a Do not tweet on Sunday (#712) 2022-02-19 19:29:49 +01:00
4ec351369b Bugfix/add fallback to default account in import (#709)
* Add fallback to default account if account id is invalid

* Update changelog
2022-02-19 18:51:16 +01:00
dced06ebb5 Bugfix/improve allocations (#710)
* Fix allocations by account for non-unique account names

* Refactor calculations with big.js

* Update changelog
2022-02-19 18:41:12 +01:00
baa6a3d0f0 Feature/restructure api modules (#706)
* Restructure modules

* Update changelog
2022-02-18 19:32:25 +01:00
d3382f0809 Update time (#707) 2022-02-17 21:31:08 +01:00
1eb4041837 Feature/move countries and sectors chart (#704)
* Move countries and sectors charts

* Update changelog
2022-02-17 20:40:28 +01:00
24 changed files with 157 additions and 98 deletions

View File

@ -5,6 +5,19 @@ 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).
## 1.117.0 - 19.02.2022
### Changed
- Moved the countries and sectors charts in the position detail dialog
- Distinguished today's data point of historical data in the admin control panel
- Restructured the server modules
### Fixed
- Fixed the allocations by account for non-unique account names
- Added a fallback to the default account if the `accountId` is invalid in the import functionality for activities
## 1.116.0 - 16.02.2022
### Added

View File

@ -1,4 +1,4 @@
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
import { PrismaModule } from '@ghostfolio/api/services/prisma.module';
import { Module } from '@nestjs/common';
import { AccessController } from './access.controller';
@ -7,7 +7,7 @@ import { AccessService } from './access.service';
@Module({
controllers: [AccessController],
exports: [AccessService],
imports: [],
providers: [AccessService, PrismaService]
imports: [PrismaModule],
providers: [AccessService]
})
export class AccessModule {}

View File

@ -13,6 +13,7 @@ import { AccountService } from './account.service';
@Module({
controllers: [AccountController],
exports: [AccountService],
imports: [
ConfigurationModule,
DataProviderModule,

View File

@ -1,18 +1,20 @@
import { AuthDeviceController } from '@ghostfolio/api/app/auth-device/auth-device.controller';
import { AuthDeviceService } from '@ghostfolio/api/app/auth-device/auth-device.service';
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma.module';
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
@Module({
controllers: [AuthDeviceController],
imports: [
ConfigurationModule,
JwtModule.register({
secret: process.env.JWT_SECRET_KEY,
signOptions: { expiresIn: '180 days' }
})
}),
PrismaModule
],
providers: [AuthDeviceService, ConfigurationService, PrismaService]
providers: [AuthDeviceService]
})
export class AuthDeviceModule {}

View File

@ -2,8 +2,8 @@ import { AuthDeviceService } from '@ghostfolio/api/app/auth-device/auth-device.s
import { WebAuthService } from '@ghostfolio/api/app/auth/web-auth.service';
import { SubscriptionModule } from '@ghostfolio/api/app/subscription/subscription.module';
import { UserModule } from '@ghostfolio/api/app/user/user.module';
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma.module';
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
@ -15,20 +15,20 @@ import { JwtStrategy } from './jwt.strategy';
@Module({
controllers: [AuthController],
imports: [
ConfigurationModule,
JwtModule.register({
secret: process.env.JWT_SECRET_KEY,
signOptions: { expiresIn: '180 days' }
}),
PrismaModule,
SubscriptionModule,
UserModule
],
providers: [
AuthDeviceService,
AuthService,
ConfigurationService,
GoogleStrategy,
JwtStrategy,
PrismaService,
WebAuthService
]
})

View File

@ -1,30 +1,27 @@
import { CacheService } from '@ghostfolio/api/app/cache/cache.service';
import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module';
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration.module';
import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering.module';
import { DataGatheringService } from '@ghostfolio/api/services/data-gathering.service';
import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module';
import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data.module';
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
import { PrismaModule } from '@ghostfolio/api/services/prisma.module';
import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile.module';
import { Module } from '@nestjs/common';
import { CacheController } from './cache.controller';
@Module({
exports: [CacheService],
controllers: [CacheController],
imports: [
ConfigurationModule,
DataGatheringModule,
DataProviderModule,
ExchangeRateDataModule,
PrismaModule,
RedisCacheModule,
SymbolProfileModule
],
controllers: [CacheController],
providers: [
CacheService,
ConfigurationService,
DataGatheringService,
PrismaService
]
providers: [CacheService]
})
export class CacheModule {}

View File

@ -1,4 +1,5 @@
import { CacheService } from '@ghostfolio/api/app/cache/cache.service';
import { AccountModule } from '@ghostfolio/api/app/account/account.module';
import { CacheModule } from '@ghostfolio/api/app/cache/cache.module';
import { OrderModule } from '@ghostfolio/api/app/order/order.module';
import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration.module';
@ -11,7 +12,10 @@ import { ImportController } from './import.controller';
import { ImportService } from './import.service';
@Module({
controllers: [ImportController],
imports: [
AccountModule,
CacheModule,
ConfigurationModule,
DataGatheringModule,
DataProviderModule,
@ -19,7 +23,6 @@ import { ImportService } from './import.service';
PrismaModule,
RedisCacheModule
],
controllers: [ImportController],
providers: [CacheService, ImportService]
providers: [ImportService]
})
export class ImportModule {}

View File

@ -1,3 +1,4 @@
import { AccountService } from '@ghostfolio/api/app/account/account.service';
import { OrderService } from '@ghostfolio/api/app/order/order.service';
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service';
@ -8,6 +9,7 @@ import { isSameDay, parseISO } from 'date-fns';
@Injectable()
export class ImportService {
public constructor(
private readonly accountService: AccountService,
private readonly configurationService: ConfigurationService,
private readonly dataProviderService: DataProviderService,
private readonly orderService: OrderService
@ -32,6 +34,12 @@ export class ImportService {
await this.validateOrders({ orders, userId });
const accountIds = (await this.accountService.getAccounts(userId)).map(
(account) => {
return account.id;
}
);
for (const {
accountId,
currency,
@ -44,7 +52,6 @@ export class ImportService {
unitPrice
} of orders) {
await this.orderService.createOrder({
accountId,
currency,
dataSource,
fee,
@ -53,6 +60,7 @@ export class ImportService {
type,
unitPrice,
userId,
accountId: accountIds.includes(accountId) ? accountId : undefined,
date: parseISO(<string>(<unknown>date)),
SymbolProfile: {
connectOrCreate: {

View File

@ -1,10 +1,9 @@
import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module';
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration.module';
import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering.module';
import { DataGatheringService } from '@ghostfolio/api/services/data-gathering.service';
import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module';
import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data.module';
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
import { PrismaModule } from '@ghostfolio/api/services/prisma.module';
import { PropertyModule } from '@ghostfolio/api/services/property/property.module';
import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile.module';
import { Module } from '@nestjs/common';
@ -14,7 +13,9 @@ import { InfoController } from './info.controller';
import { InfoService } from './info.service';
@Module({
controllers: [InfoController],
imports: [
ConfigurationModule,
DataGatheringModule,
DataProviderModule,
ExchangeRateDataModule,
@ -22,16 +23,11 @@ import { InfoService } from './info.service';
secret: process.env.JWT_SECRET_KEY,
signOptions: { expiresIn: '30 days' }
}),
PrismaModule,
PropertyModule,
RedisCacheModule,
SymbolProfileModule
],
controllers: [InfoController],
providers: [
ConfigurationService,
DataGatheringService,
InfoService,
PrismaService
]
providers: [InfoService]
})
export class InfoModule {}

View File

@ -1,5 +1,5 @@
import { AccountService } from '@ghostfolio/api/app/account/account.service';
import { CacheService } from '@ghostfolio/api/app/cache/cache.service';
import { CacheModule } from '@ghostfolio/api/app/cache/cache.module';
import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module';
import { UserModule } from '@ghostfolio/api/app/user/user.module';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration.module';
@ -15,7 +15,10 @@ import { OrderController } from './order.controller';
import { OrderService } from './order.service';
@Module({
controllers: [OrderController],
exports: [OrderService],
imports: [
CacheModule,
ConfigurationModule,
DataGatheringModule,
DataProviderModule,
@ -26,8 +29,6 @@ import { OrderService } from './order.service';
SymbolProfileModule,
UserModule
],
controllers: [OrderController],
providers: [AccountService, CacheService, OrderService],
exports: [OrderService]
providers: [AccountService, OrderService]
})
export class OrderModule {}

View File

@ -20,6 +20,7 @@ import { PortfolioServiceNew } from './portfolio.service-new';
import { RulesService } from './rules.service';
@Module({
controllers: [PortfolioController],
exports: [PortfolioServiceStrategy],
imports: [
AccessModule,
@ -34,7 +35,6 @@ import { RulesService } from './rules.service';
SymbolProfileModule,
UserModule
],
controllers: [PortfolioController],
providers: [
AccountService,
CurrentRateService,

View File

@ -1,3 +1,4 @@
import { ConfigurationModule } from '@ghostfolio/api/services/configuration.module';
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
import { CacheModule, Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
@ -17,9 +18,10 @@ import { RedisCacheService } from './redis-cache.service';
store: redisStore,
ttl: configurationService.get('CACHE_TTL')
})
})
}),
ConfigurationModule
],
providers: [ConfigurationService, RedisCacheService],
providers: [RedisCacheService],
exports: [RedisCacheService]
})
export class RedisCacheModule {}

View File

@ -1,5 +1,5 @@
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma.module';
import { PropertyModule } from '@ghostfolio/api/services/property/property.module';
import { Module } from '@nestjs/common';
@ -7,9 +7,9 @@ import { SubscriptionController } from './subscription.controller';
import { SubscriptionService } from './subscription.service';
@Module({
imports: [PropertyModule],
controllers: [SubscriptionController],
providers: [ConfigurationService, PrismaService, SubscriptionService],
exports: [SubscriptionService]
exports: [SubscriptionService],
imports: [ConfigurationModule, PrismaModule, PropertyModule],
providers: [SubscriptionService]
})
export class SubscriptionModule {}

View File

@ -1,6 +1,6 @@
import { SubscriptionModule } from '@ghostfolio/api/app/subscription/subscription.module';
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
import { PrismaService } from '@ghostfolio/api/services/prisma.service';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration.module';
import { PrismaModule } from '@ghostfolio/api/services/prisma.module';
import { PropertyModule } from '@ghostfolio/api/services/property/property.module';
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
@ -9,16 +9,18 @@ import { UserController } from './user.controller';
import { UserService } from './user.service';
@Module({
controllers: [UserController],
exports: [UserService],
imports: [
ConfigurationModule,
JwtModule.register({
secret: process.env.JWT_SECRET_KEY,
signOptions: { expiresIn: '30 days' }
}),
PrismaModule,
PropertyModule,
SubscriptionModule
],
controllers: [UserController],
providers: [ConfigurationService, PrismaService, UserService],
exports: [UserService]
providers: [UserService]
})
export class UserModule {}

View File

@ -23,8 +23,8 @@ export class CronService {
await this.exchangeRateDataService.loadCurrencies();
}
@Cron(CronExpression.EVERY_DAY_AT_6PM)
public async runEveryDayAtSixPM() {
@Cron(CronExpression.EVERY_DAY_AT_5PM)
public async runEveryDayAtFivePM() {
this.twitterBotService.tweetFearAndGreedIndex();
}

View File

@ -6,6 +6,7 @@ import {
} from '@ghostfolio/common/config';
import { resolveFearAndGreedIndex } from '@ghostfolio/common/helper';
import { Injectable, Logger } from '@nestjs/common';
import { isSunday } from 'date-fns';
import { TwitterApi, TwitterApiReadWrite } from 'twitter-api-v2';
@Injectable()
@ -27,7 +28,10 @@ export class TwitterBotService {
}
public async tweetFearAndGreedIndex() {
if (!this.configurationService.get('ENABLE_FEATURE_FEAR_AND_GREED_INDEX')) {
if (
!this.configurationService.get('ENABLE_FEATURE_FEAR_AND_GREED_INDEX') ||
isSunday(new Date())
) {
return;
}

View File

@ -19,7 +19,10 @@
marketDataByMonth[itemByMonth.key][
i + 1 < 10 ? '0' + (i + 1) : i + 1
]?.day ===
i + 1
i + 1,
today: isToday(
itemByMonth.key + '-' + (i + 1 < 10 ? '0' + (i + 1) : i + 1)
)
}"
[title]="
(itemByMonth.key + '-' + (i + 1 < 10 ? '0' + (i + 1) : i + 1)

View File

@ -25,5 +25,10 @@
&.available {
background-color: var(--success);
}
&.today {
background-color: rgba(var(--palette-accent-500), 1);
cursor: default;
}
}
}

View File

@ -12,7 +12,7 @@ import { DEFAULT_DATE_FORMAT } from '@ghostfolio/common/config';
import { DATE_FORMAT } from '@ghostfolio/common/helper';
import { LineChartItem } from '@ghostfolio/ui/line-chart/interfaces/line-chart.interface';
import { DataSource, MarketData } from '@prisma/client';
import { format, isBefore, isValid, parse } from 'date-fns';
import { format, isBefore, isSameDay, isValid, parse } from 'date-fns';
import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject, takeUntil } from 'rxjs';
@ -82,6 +82,11 @@ export class AdminMarketDataDetailComponent implements OnChanges, OnInit {
return isValid(date) && isBefore(date, new Date());
}
public isToday(aDateString: string) {
const date = parse(aDateString, DATE_FORMAT, new Date());
return isValid(date) && isSameDay(date, new Date());
}
public onOpenMarketDataDetail({
day,
yearMonth
@ -89,13 +94,18 @@ export class AdminMarketDataDetailComponent implements OnChanges, OnInit {
day: string;
yearMonth: string;
}) {
const date = new Date(`${yearMonth}-${day}`);
const marketPrice = this.marketDataByMonth[yearMonth]?.[day]?.marketPrice;
if (isSameDay(date, new Date())) {
return;
}
const dialogRef = this.dialog.open(MarketDataDetailDialog, {
data: {
date,
marketPrice,
dataSource: this.dataSource,
date: new Date(`${yearMonth}-${day}`),
symbol: this.symbol
},
height: this.deviceType === 'mobile' ? '97.5vh' : '80vh',

View File

@ -144,6 +144,14 @@
<ng-container
*ngIf="SymbolProfile?.countries?.length === 1 && SymbolProfile?.sectors?.length === 1; else charts"
>
<div *ngIf="SymbolProfile?.sectors?.length === 1" class="col-6 mb-3">
<gf-value
label="Sector"
size="medium"
[locale]="data.locale"
[value]="SymbolProfile.sectors[0].name"
></gf-value>
</div>
<div
*ngIf="SymbolProfile?.countries?.length === 1"
class="col-6 mb-3"
@ -155,27 +163,8 @@
[value]="SymbolProfile.countries[0].name"
></gf-value>
</div>
<div *ngIf="SymbolProfile?.sectors?.length === 1" class="col-6 mb-3">
<gf-value
label="Sector"
size="medium"
[locale]="data.locale"
[value]="SymbolProfile.sectors[0].name"
></gf-value>
</div>
</ng-container>
<ng-template #charts>
<div class="col-md-6 mb-3">
<div class="h4" i18n>Countries</div>
<gf-portfolio-proportion-chart
[baseCurrency]="user?.settings?.baseCurrency"
[isInPercent]="true"
[keys]="['name']"
[locale]="user?.settings?.locale"
[maxItems]="10"
[positions]="countries"
></gf-portfolio-proportion-chart>
</div>
<div class="col-md-6 mb-3">
<div class="h4" i18n>Sectors</div>
<gf-portfolio-proportion-chart
@ -187,6 +176,17 @@
[positions]="sectors"
></gf-portfolio-proportion-chart>
</div>
<div class="col-md-6 mb-3">
<div class="h4" i18n>Countries</div>
<gf-portfolio-proportion-chart
[baseCurrency]="user?.settings?.baseCurrency"
[isInPercent]="true"
[keys]="['name']"
[locale]="user?.settings?.locale"
[maxItems]="10"
[positions]="countries"
></gf-portfolio-proportion-chart>
</div>
</ng-template>
</ng-container>
</div>

View File

@ -14,7 +14,7 @@ import {
} from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { ToggleOption } from '@ghostfolio/common/types';
import { AssetClass, DataSource } from '@prisma/client';
import { Account, AssetClass, DataSource } from '@prisma/client';
import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject, Subscription } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@ -27,7 +27,10 @@ import { takeUntil } from 'rxjs/operators';
})
export class AllocationsPageComponent implements OnDestroy, OnInit {
public accounts: {
[symbol: string]: Pick<PortfolioPosition, 'name'> & { value: number };
[id: string]: Pick<Account, 'name'> & {
id: string;
value: number;
};
};
public continents: {
[code: string]: { name: string; value: number };
@ -171,6 +174,7 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
this.portfolioDetails.accounts
)) {
this.accounts[id] = {
id,
name,
value: aPeriod === 'original' ? original : current
};

View File

@ -20,7 +20,7 @@
<gf-portfolio-proportion-chart
[baseCurrency]="user?.settings?.baseCurrency"
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
[keys]="['name']"
[keys]="['id']"
[locale]="user?.settings?.locale"
[positions]="accounts"
></gf-portfolio-proportion-chart>

View File

@ -11,6 +11,7 @@ import {
import { UNKNOWN_KEY } from '@ghostfolio/common/config';
import { getTextColor } from '@ghostfolio/common/helper';
import { PortfolioPosition } from '@ghostfolio/common/interfaces';
import Big from 'big.js';
import { Tooltip } from 'chart.js';
import { LinearScale } from 'chart.js';
import { ArcElement } from 'chart.js';
@ -78,16 +79,17 @@ export class PortfolioProportionChartComponent
[symbol: string]: {
color?: string;
name: string;
subCategory: { [symbol: string]: { value: number } };
value: number;
subCategory: { [symbol: string]: { value: Big } };
value: Big;
};
} = {};
Object.keys(this.positions).forEach((symbol) => {
if (this.positions[symbol][this.keys[0]]) {
if (chartData[this.positions[symbol][this.keys[0]]]) {
chartData[this.positions[symbol][this.keys[0]]].value +=
this.positions[symbol].value;
chartData[this.positions[symbol][this.keys[0]]].value = chartData[
this.positions[symbol][this.keys[0]]
].value.plus(this.positions[symbol].value);
if (
chartData[this.positions[symbol][this.keys[0]]].subCategory[
@ -96,37 +98,43 @@ export class PortfolioProportionChartComponent
) {
chartData[this.positions[symbol][this.keys[0]]].subCategory[
this.positions[symbol][this.keys[1]]
].value += this.positions[symbol].value;
].value = chartData[
this.positions[symbol][this.keys[0]]
].subCategory[this.positions[symbol][this.keys[1]]].value.plus(
this.positions[symbol].value
);
} else {
chartData[this.positions[symbol][this.keys[0]]].subCategory[
this.positions[symbol][this.keys[1]] ?? UNKNOWN_KEY
] = { value: this.positions[symbol].value };
] = { value: new Big(this.positions[symbol].value) };
}
} else {
chartData[this.positions[symbol][this.keys[0]]] = {
name: this.positions[symbol].name,
subCategory: {},
value: this.positions[symbol].value
value: new Big(this.positions[symbol].value)
};
if (this.positions[symbol][this.keys[1]]) {
chartData[this.positions[symbol][this.keys[0]]].subCategory = {
[this.positions[symbol][this.keys[1]]]: {
value: this.positions[symbol].value
value: new Big(this.positions[symbol].value)
}
};
}
}
} else {
if (chartData[UNKNOWN_KEY]) {
chartData[UNKNOWN_KEY].value += this.positions[symbol].value;
chartData[UNKNOWN_KEY].value = chartData[UNKNOWN_KEY].value.plus(
this.positions[symbol].value
);
} else {
chartData[UNKNOWN_KEY] = {
name: this.positions[symbol].name,
subCategory: this.keys[1]
? { [this.keys[1]]: { value: 0 } }
? { [this.keys[1]]: { value: new Big(0) } }
: undefined,
value: this.positions[symbol].value
value: new Big(this.positions[symbol].value)
};
}
}
@ -134,7 +142,7 @@ export class PortfolioProportionChartComponent
let chartDataSorted = Object.entries(chartData)
.sort((a, b) => {
return a[1].value - b[1].value;
return a[1].value.minus(b[1].value).toNumber();
})
.reverse();
@ -152,7 +160,7 @@ export class PortfolioProportionChartComponent
if (!unknownItem) {
chartDataSorted.push([
UNKNOWN_KEY,
{ name: UNKNOWN_KEY, subCategory: {}, value: 0 }
{ name: UNKNOWN_KEY, subCategory: {}, value: new Big(0) }
]);
unknownItem = chartDataSorted[chartDataSorted.length - 1];
}
@ -162,7 +170,7 @@ export class PortfolioProportionChartComponent
unknownItem[1] = {
name: UNKNOWN_KEY,
subCategory: {},
value: unknownItem[1].value + restItem[1].value
value: unknownItem[1].value.plus(restItem[1].value)
};
}
});
@ -170,7 +178,7 @@ export class PortfolioProportionChartComponent
// Sort data again
chartDataSorted = chartDataSorted
.sort((a, b) => {
return a[1].value - b[1].value;
return a[1].value.minus(b[1].value).toNumber();
})
.reverse();
}
@ -201,7 +209,7 @@ export class PortfolioProportionChartComponent
backgroundColorSubCategory.push(
Color(item.color).lighten(lightnessRatio).hex()
);
dataSubCategory.push(item.subCategory[subCategory].value);
dataSubCategory.push(item.subCategory[subCategory].value.toNumber());
labelSubCategory.push(subCategory);
lightnessRatio += 0.1;
@ -215,7 +223,7 @@ export class PortfolioProportionChartComponent
}),
borderWidth: 0,
data: chartDataSorted.map(([, item]) => {
return item.value;
return item.value.toNumber();
})
}
];

View File

@ -1,6 +1,6 @@
{
"name": "ghostfolio",
"version": "1.116.0",
"version": "1.117.0",
"homepage": "https://ghostfol.io",
"license": "AGPL-3.0",
"scripts": {