Browse Source

Merge remote-tracking branch 'origin/main' into task/enable-strict-null-checks-in-client

pull/7309/head
KenTandrian 2 days ago
parent
commit
cb5f42a25a
  1. 3
      CHANGELOG.md
  2. 18
      apps/api/src/app/portfolio/calculator/portfolio-calculator.ts
  3. 30
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts
  4. 8
      apps/api/src/app/portfolio/interfaces/portfolio-order.interface.ts
  5. 8
      apps/client/src/styles.scss
  6. 16
      libs/ui/src/lib/page-tabs/page-tabs.component.html
  7. 5
      libs/ui/src/lib/page-tabs/page-tabs.component.scss
  8. 4
      package-lock.json
  9. 2
      package.json

3
CHANGELOG.md

@ -5,7 +5,7 @@ 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/), 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). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased ## 3.25.0 - 2026-07-12
### Changed ### Changed
@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
- Fixed the layout of the page tabs component by truncating long labels
- Fixed the display of assets without a currency in the search results of the assistant - Fixed the display of assets without a currency in the search results of the assistant
- Fixed the display of assets without a currency in the symbol autocomplete component - Fixed the display of assets without a currency in the symbol autocomplete component

18
apps/api/src/app/portfolio/calculator/portfolio-calculator.ts

@ -141,9 +141,9 @@ export abstract class PortfolioCalculator {
} }
return { return {
SymbolProfile,
tags, tags,
type, type,
assetProfile: SymbolProfile,
date: format(date, DATE_FORMAT), date: format(date, DATE_FORMAT),
fee: new Big(feeInAssetProfileCurrency), fee: new Big(feeInAssetProfileCurrency),
feeInBaseCurrency: new Big(feeInBaseCurrency), feeInBaseCurrency: new Big(feeInBaseCurrency),
@ -934,23 +934,23 @@ export abstract class PortfolioCalculator {
let lastTransactionPoint: TransactionPoint = null; let lastTransactionPoint: TransactionPoint = null;
for (const { for (const {
assetProfile,
date, date,
fee, fee,
feeInBaseCurrency, feeInBaseCurrency,
quantity, quantity,
SymbolProfile,
tags, tags,
type, type,
unitPrice unitPrice
} of this.activities) { } of this.activities) {
let currentTransactionPointItem: TransactionPointSymbol; let currentTransactionPointItem: TransactionPointSymbol;
const assetSubClass = SymbolProfile.assetSubClass; const assetSubClass = assetProfile.assetSubClass;
const currency = SymbolProfile.currency; const currency = assetProfile.currency;
const dataSource = SymbolProfile.dataSource; const dataSource = assetProfile.dataSource;
const factor = getFactor(type); const factor = getFactor(type);
const skipErrors = !!SymbolProfile.userId; // Skip errors for custom asset profiles const skipErrors = !!assetProfile.userId; // Skip errors for custom asset profiles
const symbol = SymbolProfile.symbol; const symbol = assetProfile.symbol;
const oldAccumulatedSymbol = symbols[symbol]; const oldAccumulatedSymbol = symbols[symbol];
@ -1034,12 +1034,12 @@ export abstract class PortfolioCalculator {
'id' 'id'
); );
symbols[SymbolProfile.symbol] = currentTransactionPointItem; symbols[symbol] = currentTransactionPointItem;
const items = lastTransactionPoint?.items ?? []; const items = lastTransactionPoint?.items ?? [];
const newItems = items.filter(({ symbol }) => { const newItems = items.filter(({ symbol }) => {
return symbol !== SymbolProfile.symbol; return symbol !== assetProfile.symbol;
}); });
newItems.push(currentTransactionPointItem); newItems.push(currentTransactionPointItem);

30
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts

@ -192,12 +192,12 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
// Clone orders to keep the original values in this.orders // Clone orders to keep the original values in this.orders
let orders: PortfolioOrderItem[] = cloneDeep( let orders: PortfolioOrderItem[] = cloneDeep(
this.activities.filter(({ SymbolProfile }) => { this.activities.filter(({ assetProfile }) => {
return SymbolProfile.symbol === symbol; return assetProfile.symbol === symbol;
}) })
); );
const isCash = orders[0]?.SymbolProfile?.assetSubClass === 'CASH'; const isCash = orders[0]?.assetProfile?.assetSubClass === 'CASH';
if (orders.length <= 0) { if (orders.length <= 0) {
return { return {
@ -299,32 +299,30 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
}; };
} }
const assetProfile: PortfolioOrderItem['assetProfile'] = {
dataSource,
symbol,
assetSubClass: isCash ? 'CASH' : undefined
};
// Add a synthetic order at the start and the end date // Add a synthetic order at the start and the end date
orders.push({ orders.push({
assetProfile,
date: startDateString, date: startDateString,
fee: new Big(0), fee: new Big(0),
feeInBaseCurrency: new Big(0), feeInBaseCurrency: new Big(0),
itemType: 'start', itemType: 'start',
quantity: new Big(0), quantity: new Big(0),
SymbolProfile: {
dataSource,
symbol,
assetSubClass: isCash ? 'CASH' : undefined
},
type: 'BUY', type: 'BUY',
unitPrice: unitPriceAtStartDate unitPrice: unitPriceAtStartDate
}); });
orders.push({ orders.push({
assetProfile,
date: endDateString, date: endDateString,
fee: new Big(0), fee: new Big(0),
feeInBaseCurrency: new Big(0), feeInBaseCurrency: new Big(0),
itemType: 'end', itemType: 'end',
SymbolProfile: {
dataSource,
symbol,
assetSubClass: isCash ? 'CASH' : undefined
},
quantity: new Big(0), quantity: new Big(0),
type: 'BUY', type: 'BUY',
unitPrice: unitPriceAtEndDate unitPrice: unitPriceAtEndDate
@ -357,15 +355,11 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
} }
} else { } else {
orders.push({ orders.push({
assetProfile,
date: dateString, date: dateString,
fee: new Big(0), fee: new Big(0),
feeInBaseCurrency: new Big(0), feeInBaseCurrency: new Big(0),
quantity: new Big(0), quantity: new Big(0),
SymbolProfile: {
dataSource,
symbol,
assetSubClass: isCash ? 'CASH' : undefined
},
type: 'BUY', type: 'BUY',
unitPrice: marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice, unitPrice: marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice,
unitPriceFromMarketData: unitPriceFromMarketData:

8
apps/api/src/app/portfolio/interfaces/portfolio-order.interface.ts

@ -1,13 +1,13 @@
import { Activity } from '@ghostfolio/common/interfaces'; import { Activity } from '@ghostfolio/common/interfaces';
export interface PortfolioOrder extends Pick<Activity, 'tags' | 'type'> { export interface PortfolioOrder extends Pick<Activity, 'tags' | 'type'> {
assetProfile: Pick<
Activity['SymbolProfile'],
'assetSubClass' | 'currency' | 'dataSource' | 'name' | 'symbol' | 'userId'
>;
date: string; date: string;
fee: Big; fee: Big;
feeInBaseCurrency: Big; feeInBaseCurrency: Big;
quantity: Big; quantity: Big;
SymbolProfile: Pick<
Activity['SymbolProfile'],
'assetSubClass' | 'currency' | 'dataSource' | 'name' | 'symbol' | 'userId'
>;
unitPrice: Big; unitPrice: Big;
} }

8
apps/client/src/styles.scss

@ -376,12 +376,16 @@ ngx-skeleton-loader {
visibility: hidden; visibility: hidden;
} }
.lead {
font-weight: unset;
}
.line-height-1 { .line-height-1 {
line-height: 1; line-height: 1;
} }
.lead { .line-height-normal {
font-weight: unset; line-height: normal;
} }
.mat-mdc-button-base { .mat-mdc-button-base {

16
libs/ui/src/lib/page-tabs/page-tabs.component.html

@ -45,9 +45,15 @@
</nav> </nav>
<ng-template #tabContent let-tab> <ng-template #tabContent let-tab>
<ion-icon <span class="align-items-center d-flex justify-content-start text-left w-100">
[name]="tab.iconName" <ion-icon
[size]="deviceType === 'mobile' ? 'large' : 'small'" class="flex-shrink-0"
/> [name]="tab.iconName"
<div class="d-none d-sm-block ml-1" [innerHTML]="tab.label"></div> [size]="deviceType === 'mobile' ? 'large' : 'small'"
/>
<span
class="d-none d-sm-block line-height-normal ml-1 overflow-hidden p-0 text-truncate"
[innerHTML]="tab.label"
></span>
</span>
</ng-template> </ng-template>

5
libs/ui/src/lib/page-tabs/page-tabs.component.scss

@ -56,6 +56,11 @@
padding: 2rem 0; padding: 2rem 0;
width: 14rem; width: 14rem;
.mat-mdc-tab-list,
.mat-mdc-tab-links {
width: 100%;
}
.mat-mdc-tab-links { .mat-mdc-tab-links {
flex-direction: column; flex-direction: column;

4
package-lock.json

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

2
package.json

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

Loading…
Cancel
Save