Browse Source

Merge branch 'main' into feature/extend-accounts-endpoint-by-allocations

pull/5358/head
Thomas Kaul 1 week ago
committed by GitHub
parent
commit
ab79ae807a
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 7
      CHANGELOG.md
  2. 2
      README.md
  3. 25
      apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts
  4. 26
      apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html
  5. 8
      apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html
  6. 10
      apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html
  7. 10
      apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html
  8. 4
      apps/client/src/app/components/home-overview/home-overview.component.ts
  9. 12
      apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts
  10. 16
      apps/client/src/app/components/portfolio-performance/portfolio-performance.module.ts
  11. 10
      apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html
  12. 10
      apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html
  13. 10
      apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html
  14. 13
      libs/common/src/lib/personal-finance-tools.ts

7
CHANGELOG.md

@ -7,11 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
### Added
- Added the interest and dividend values to the account detail dialog
### Changed
- Moved the chart of the account detail dialog from experimental to general availability
- Improved the dynamic numerical precision for various values in the account detail dialog
- Improved the usability of the _Cancel_ / _Close_ and _Save_ buttons in various dialogs
- Extended the accounts endpoint by allocations
- Extended the accounts endpoint by dividend and interest
- Refactored the portfolio performance component to standalone
- Improved the language localization for Portuguese (`pt`)
- Improved the language localization for Spanish (`es`)

2
README.md

@ -295,7 +295,7 @@ Are you building your own project? Add the `ghostfolio` topic to your _GitHub_ r
Ghostfolio is **100% free** and **open source**. We encourage and support an active and healthy community that accepts contributions from the public - including you.
Not sure what to work on? We have [some ideas](https://github.com/ghostfolio/ghostfolio/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22), even for [newcomers](https://github.com/ghostfolio/ghostfolio/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22). Please join the Ghostfolio [Slack](https://join.slack.com/t/ghostfolio/shared_invite/zt-vsaan64h-F_I0fEo5M0P88lP9ibCxFg) channel or post to [@ghostfolio\_](https://x.com/ghostfolio_) on _X_. We would love to hear from you.
Not sure what to work on? We have [some ideas](https://github.com/ghostfolio/ghostfolio/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22%20no%3Aassignee), even for [newcomers](https://github.com/ghostfolio/ghostfolio/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22%20no%3Aassignee). Please join the Ghostfolio [Slack](https://join.slack.com/t/ghostfolio/shared_invite/zt-vsaan64h-F_I0fEo5M0P88lP9ibCxFg) channel or post to [@ghostfolio\_](https://x.com/ghostfolio_) on _X_. We would love to hear from you.
If you like to support this project, get [**Ghostfolio Premium**](https://ghostfol.io/en/pricing) or [**Buy me a coffee**](https://www.buymeacoffee.com/ghostfolio).

25
apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts

@ -55,11 +55,15 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
public balancePrecision = 2;
public currency: string;
public dataSource: MatTableDataSource<Activity>;
public dividendInBaseCurrency: number;
public dividendInBaseCurrencyPrecision = 2;
public equity: number;
public equityPrecision = 2;
public hasPermissionToDeleteAccountBalance: boolean;
public historicalDataItems: HistoricalDataItem[];
public holdings: PortfolioPosition[];
public interestInBaseCurrency: number;
public interestInBaseCurrencyPrecision = 2;
public isLoadingActivities: boolean;
public isLoadingChart: boolean;
public name: string;
@ -184,6 +188,8 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
({
balance,
currency,
dividendInBaseCurrency,
interestInBaseCurrency,
name,
platform,
transactionCount,
@ -200,6 +206,15 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
}
this.currency = currency;
this.dividendInBaseCurrency = dividendInBaseCurrency;
if (
this.data.deviceType === 'mobile' &&
this.dividendInBaseCurrency >=
NUMERICAL_PRECISION_THRESHOLD_6_FIGURES
) {
this.dividendInBaseCurrencyPrecision = 0;
}
if (isNumber(balance) && isNumber(value)) {
this.equity = new Big(value).minus(balance).toNumber();
@ -214,6 +229,16 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
this.equity = null;
}
this.interestInBaseCurrency = interestInBaseCurrency;
if (
this.data.deviceType === 'mobile' &&
this.interestInBaseCurrency >=
NUMERICAL_PRECISION_THRESHOLD_6_FIGURES
) {
this.interestInBaseCurrencyPrecision = 0;
}
this.name = name;
this.platformName = platform?.name ?? '-';
this.transactionCount = transactionCount;

26
apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html

@ -20,7 +20,6 @@
</div>
</div>
@if (user?.settings?.isExperimentalFeatures) {
<div class="chart-container mb-3">
<gf-investment-chart
class="h-100"
@ -33,7 +32,6 @@
[locale]="user?.settings?.locale"
/>
</div>
}
<div class="mb-3 row">
<div class="col-6 mb-3">
@ -60,6 +58,30 @@
>Equity</gf-value
>
</div>
<div class="col-6 mb-3">
<gf-value
i18n
size="medium"
[isCurrency]="true"
[locale]="user?.settings?.locale"
[precision]="interestInBaseCurrencyPrecision"
[unit]="user?.settings?.baseCurrency"
[value]="interestInBaseCurrency"
>Interest</gf-value
>
</div>
<div class="col-6 mb-3">
<gf-value
i18n
size="medium"
[isCurrency]="true"
[locale]="user?.settings?.locale"
[precision]="dividendInBaseCurrencyPrecision"
[unit]="user?.settings?.baseCurrency"
[value]="dividendInBaseCurrency"
>Dividend</gf-value
>
</div>
<div class="col-6 mb-3">
<gf-value i18n size="medium" [value]="transactionCount"
>Activities</gf-value

8
apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html

@ -549,7 +549,13 @@
<ng-container i18n>Data Gathering</ng-container>
</mat-checkbox>
</div>
<button i18n mat-button type="button" (click)="onClose()">Cancel</button>
<button mat-button type="button" (click)="onClose()">
@if (assetProfileForm.dirty) {
<ng-container i18n>Cancel</ng-container>
} @else {
<ng-container i18n>Close</ng-container>
}
</button>
<button
color="primary"
mat-flat-button

10
apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html

@ -39,12 +39,18 @@
</div>
</div>
<div class="justify-content-end" mat-dialog-actions>
<button i18n mat-button type="button" (click)="onCancel()">Cancel</button>
<button mat-button type="button" (click)="onCancel()">
@if (platformForm.dirty) {
<ng-container i18n>Cancel</ng-container>
} @else {
<ng-container i18n>Close</ng-container>
}
</button>
<button
color="primary"
mat-flat-button
type="submit"
[disabled]="!platformForm.valid"
[disabled]="!(platformForm.dirty && platformForm.valid)"
>
<ng-container i18n>Save</ng-container>
</button>

10
apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html

@ -22,12 +22,18 @@
</div>
</div>
<div class="justify-content-end" mat-dialog-actions>
<button i18n mat-button type="button" (click)="onCancel()">Cancel</button>
<button mat-button type="button" (click)="onCancel()">
@if (tagForm.dirty) {
<ng-container i18n>Cancel</ng-container>
} @else {
<ng-container i18n>Close</ng-container>
}
</button>
<button
color="primary"
mat-flat-button
type="submit"
[disabled]="!tagForm.valid"
[disabled]="!(tagForm.dirty && tagForm.valid)"
>
<ng-container i18n>Save</ng-container>
</button>

4
apps/client/src/app/components/home-overview/home-overview.component.ts

@ -1,4 +1,4 @@
import { GfPortfolioPerformanceModule } from '@ghostfolio/client/components/portfolio-performance/portfolio-performance.module';
import { GfPortfolioPerformanceComponent } from '@ghostfolio/client/components/portfolio-performance/portfolio-performance.component';
import { LayoutService } from '@ghostfolio/client/core/layout.service';
import { DataService } from '@ghostfolio/client/services/data.service';
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
@ -32,7 +32,7 @@ import { takeUntil } from 'rxjs/operators';
imports: [
CommonModule,
GfLineChartComponent,
GfPortfolioPerformanceModule,
GfPortfolioPerformanceComponent,
MatButtonModule,
RouterModule
],

12
apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts

@ -8,7 +8,9 @@ import {
PortfolioPerformance,
ResponseError
} from '@ghostfolio/common/interfaces';
import { GfValueComponent } from '@ghostfolio/ui/value';
import { CommonModule } from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
@ -17,19 +19,21 @@ import {
OnChanges,
ViewChild
} from '@angular/core';
import { IonIcon } from '@ionic/angular/standalone';
import { CountUp } from 'countup.js';
import { addIcons } from 'ionicons';
import { timeOutline } from 'ionicons/icons';
import { isNumber } from 'lodash';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
@Component({
selector: 'gf-portfolio-performance',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './portfolio-performance.component.html',
imports: [CommonModule, GfValueComponent, IonIcon, NgxSkeletonLoaderModule],
selector: 'gf-portfolio-performance',
styleUrls: ['./portfolio-performance.component.scss'],
standalone: false
templateUrl: './portfolio-performance.component.html'
})
export class PortfolioPerformanceComponent implements OnChanges {
export class GfPortfolioPerformanceComponent implements OnChanges {
@Input() deviceType: string;
@Input() errors: ResponseError['errors'];
@Input() isAllTimeHigh: boolean;

16
apps/client/src/app/components/portfolio-performance/portfolio-performance.module.ts

@ -1,16 +0,0 @@
import { GfValueComponent } from '@ghostfolio/ui/value';
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { IonIcon } from '@ionic/angular/standalone';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { PortfolioPerformanceComponent } from './portfolio-performance.component';
@NgModule({
declarations: [PortfolioPerformanceComponent],
exports: [PortfolioPerformanceComponent],
imports: [CommonModule, GfValueComponent, IonIcon, NgxSkeletonLoaderModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class GfPortfolioPerformanceModule {}

10
apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html

@ -55,12 +55,18 @@
}
</div>
<div class="justify-content-end" mat-dialog-actions>
<button i18n mat-button type="button" (click)="onCancel()">Cancel</button>
<button mat-button type="button" (click)="onCancel()">
@if (accessForm.dirty) {
<ng-container i18n>Cancel</ng-container>
} @else {
<ng-container i18n>Close</ng-container>
}
</button>
<button
color="primary"
mat-flat-button
type="submit"
[disabled]="!accessForm.valid"
[disabled]="!(accessForm.dirty && accessForm.valid)"
>
<ng-container i18n>Save</ng-container>
</button>

10
apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html

@ -100,12 +100,18 @@
}
</div>
<div class="justify-content-end" mat-dialog-actions>
<button i18n mat-button type="button" (click)="onCancel()">Cancel</button>
<button mat-button type="button" (click)="onCancel()">
@if (accountForm.dirty) {
<ng-container i18n>Cancel</ng-container>
} @else {
<ng-container i18n>Close</ng-container>
}
</button>
<button
color="primary"
mat-flat-button
type="submit"
[disabled]="!accountForm.valid"
[disabled]="!(accountForm.dirty && accountForm.valid)"
>
<ng-container i18n>Save</ng-container>
</button>

10
apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html

@ -335,12 +335,18 @@
[value]="total"
/>
<div>
<button i18n mat-button type="button" (click)="onCancel()">Cancel</button>
<button mat-button type="button" (click)="onCancel()">
@if (activityForm.dirty) {
<ng-container i18n>Cancel</ng-container>
} @else {
<ng-container i18n>Close</ng-container>
}
</button>
<button
color="primary"
mat-flat-button
type="submit"
[disabled]="!activityForm.valid"
[disabled]="!(activityForm.dirty && activityForm.valid)"
>
<ng-container i18n>Save</ng-container>
</button>

13
libs/common/src/lib/personal-finance-tools.ts

@ -57,7 +57,7 @@ export const personalFinanceTools: Product[] = [
founded: 2016,
key: 'atominvest',
name: 'Atominvest',
origin: 'London',
origin: 'United Kingdom',
slogan: 'Portfolio Management'
},
{
@ -139,6 +139,7 @@ export const personalFinanceTools: Product[] = [
founded: 2011,
key: 'cobalt',
name: 'Cobalt',
origin: 'United States',
slogan: 'Next-Level Portfolio Monitoring'
},
{
@ -683,6 +684,16 @@ export const personalFinanceTools: Product[] = [
origin: 'Italy',
slogan: 'Your Personal Finance Hub'
},
{
founded: 2015,
hasFreePlan: false,
hasSelfHostingAbility: false,
key: 'pocketguard',
name: 'PocketGuard',
origin: 'United States',
pricingPerYear: '$74.99',
slogan: 'Budgeting App & Finance Planner'
},
{
founded: 2008,
hasFreePlan: true,

Loading…
Cancel
Save