Browse Source

Merge branch 'main' into feature/asset-profile-update-api

pull/6981/head
Thomas Kaul 3 months ago
committed by GitHub
parent
commit
e8725b1596
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 4
      CHANGELOG.md
  2. 21
      apps/api/src/services/fetch/fetch.service.ts
  3. 2
      apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html
  4. 2
      apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
  5. 2
      apps/client/src/app/components/investment-chart/investment-chart.component.html
  6. 3
      apps/client/src/app/components/investment-chart/investment-chart.component.ts
  7. 3
      apps/client/src/app/pages/portfolio/fire/fire-page.component.ts
  8. 11
      apps/client/src/app/pages/portfolio/fire/fire-page.html
  9. 250
      apps/client/src/locales/messages.ko.xlf
  10. 1
      libs/common/src/lib/config.ts
  11. 7
      libs/ui/src/lib/account-balances/account-balances.component.html
  12. 1
      libs/ui/src/lib/account-balances/account-balances.component.ts
  13. 2
      libs/ui/src/lib/fire-calculator/fire-calculator.component.html
  14. 5
      libs/ui/src/lib/line-chart/line-chart.component.html
  15. 3
      libs/ui/src/lib/line-chart/line-chart.component.ts
  16. 5
      libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.html
  17. 3
      libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts
  18. 2
      libs/ui/src/lib/premium-indicator/premium-indicator.component.html
  19. 3
      libs/ui/src/lib/premium-indicator/premium-indicator.component.ts
  20. 5
      libs/ui/src/lib/treemap-chart/treemap-chart.component.html
  21. 3
      libs/ui/src/lib/treemap-chart/treemap-chart.component.ts

4
CHANGELOG.md

@ -10,10 +10,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Extended the _Public API_ with the endpoint to update the asset profile data (`PATCH api/v1/asset-profiles/:dataSource/:symbol`) (experimental) - Extended the _Public API_ with the endpoint to update the asset profile data (`PATCH api/v1/asset-profiles/:dataSource/:symbol`) (experimental)
- Added support for a dedicated _OpenRouter_ model for the `web_fetch` tool in the `FetchService`
### Changed ### Changed
- Prefilled the form in the account balance management with the current cash balance - Prefilled the form in the account balance management with the current cash balance
- Disabled the selection of future dates in the account balance management
- Migrated various components from `NgStyle` to style bindings
- Improved the language localization for Korean (`ko`)
## 3.8.0 - 2026-06-07 ## 3.8.0 - 2026-06-07

21
apps/api/src/services/fetch/fetch.service.ts

@ -3,6 +3,7 @@ import { PropertyService } from '@ghostfolio/api/services/property/property.serv
import { import {
PROPERTY_API_KEY_OPENROUTER, PROPERTY_API_KEY_OPENROUTER,
PROPERTY_OPENROUTER_MODEL, PROPERTY_OPENROUTER_MODEL,
PROPERTY_OPENROUTER_MODEL_WEB_FETCH,
PROPERTY_WEB_FETCH_ROUTES PROPERTY_WEB_FETCH_ROUTES
} from '@ghostfolio/common/config'; } from '@ghostfolio/common/config';
@ -80,12 +81,18 @@ export class FetchService implements OnModuleInit {
url: string; url: string;
webFetchRoute: WebFetchRoute; webFetchRoute: WebFetchRoute;
}) { }) {
const [openRouterApiKey, openRouterModel] = await Promise.all([ const [openRouterApiKey, openRouterModel, openRouterModelWebFetch] =
this.propertyService.getByKey<string>(PROPERTY_API_KEY_OPENROUTER), await Promise.all([
this.propertyService.getByKey<string>(PROPERTY_OPENROUTER_MODEL) this.propertyService.getByKey<string>(PROPERTY_API_KEY_OPENROUTER),
]); this.propertyService.getByKey<string>(PROPERTY_OPENROUTER_MODEL),
this.propertyService.getByKey<string>(
if (!openRouterApiKey || !openRouterModel) { PROPERTY_OPENROUTER_MODEL_WEB_FETCH
)
]);
const model = openRouterModelWebFetch || openRouterModel;
if (!model || !openRouterApiKey) {
return undefined; return undefined;
} }
@ -93,7 +100,7 @@ export class FetchService implements OnModuleInit {
const openRouterService = createOpenRouter({ apiKey: openRouterApiKey }); const openRouterService = createOpenRouter({ apiKey: openRouterApiKey });
const { sources, text } = await generateText({ const { sources, text } = await generateText({
model: openRouterService.chat(openRouterModel), model: openRouterService.chat(model),
prompt: [ prompt: [
'You have access to a web_fetch tool. You MUST call it to retrieve the URL below, do not answer from prior knowledge.', 'You have access to a web_fetch tool. You MUST call it to retrieve the URL below, do not answer from prior knowledge.',
'Return the fetched response body exactly as received: raw body only, no commentary, no Markdown, and no code fences.', 'Return the fetched response body exactly as received: raw body only, no commentary, no Markdown, and no code fences.',

2
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html

@ -53,6 +53,6 @@
<canvas <canvas
#chartCanvas #chartCanvas
class="h-100" class="h-100"
[ngStyle]="{ display: isLoading() ? 'none' : 'block' }" [style.display]="isLoading() ? 'none' : 'block'"
></canvas> ></canvas>
</div> </div>

2
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts

@ -17,7 +17,6 @@ import { ColorScheme } from '@ghostfolio/common/types';
import { registerChartConfiguration } from '@ghostfolio/ui/chart'; import { registerChartConfiguration } from '@ghostfolio/ui/chart';
import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator';
import { CommonModule } from '@angular/common';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
Component, Component,
@ -53,7 +52,6 @@ import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
@Component({ @Component({
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ imports: [
CommonModule,
FormsModule, FormsModule,
GfPremiumIndicatorComponent, GfPremiumIndicatorComponent,
IonIcon, IonIcon,

2
apps/client/src/app/components/investment-chart/investment-chart.component.html

@ -10,5 +10,5 @@
<canvas <canvas
#chartCanvas #chartCanvas
class="h-100" class="h-100"
[ngStyle]="{ display: isLoading ? 'none' : 'block' }" [style.display]="isLoading ? 'none' : 'block'"
></canvas> ></canvas>

3
apps/client/src/app/components/investment-chart/investment-chart.component.ts

@ -16,7 +16,6 @@ import { InvestmentItem } from '@ghostfolio/common/interfaces/investment-item.in
import { ColorScheme, GroupBy } from '@ghostfolio/common/types'; import { ColorScheme, GroupBy } from '@ghostfolio/common/types';
import { registerChartConfiguration } from '@ghostfolio/ui/chart'; import { registerChartConfiguration } from '@ghostfolio/ui/chart';
import { CommonModule } from '@angular/common';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
Component, Component,
@ -49,7 +48,7 @@ import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
@Component({ @Component({
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, NgxSkeletonLoaderModule], imports: [NgxSkeletonLoaderModule],
selector: 'gf-investment-chart', selector: 'gf-investment-chart',
styleUrls: ['./investment-chart.component.scss'], styleUrls: ['./investment-chart.component.scss'],
templateUrl: './investment-chart.component.html' templateUrl: './investment-chart.component.html'

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

@ -12,7 +12,7 @@ import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator';
import { DataService } from '@ghostfolio/ui/services'; import { DataService } from '@ghostfolio/ui/services';
import { GfValueComponent } from '@ghostfolio/ui/value'; import { GfValueComponent } from '@ghostfolio/ui/value';
import { CommonModule, NgStyle } from '@angular/common'; import { CommonModule } from '@angular/common';
import { import {
ChangeDetectorRef, ChangeDetectorRef,
Component, Component,
@ -35,7 +35,6 @@ import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
GfFireCalculatorComponent, GfFireCalculatorComponent,
GfPremiumIndicatorComponent, GfPremiumIndicatorComponent,
GfValueComponent, GfValueComponent,
NgStyle,
NgxSkeletonLoaderModule, NgxSkeletonLoaderModule,
ReactiveFormsModule ReactiveFormsModule
], ],

11
apps/client/src/app/pages/portfolio/fire/fire-page.html

@ -19,14 +19,15 @@
!hasImpersonationId && hasPermissionToUpdateUserSettings !hasImpersonationId && hasPermissionToUpdateUserSettings
" "
[locale]="user?.settings?.locale" [locale]="user?.settings?.locale"
[ngStyle]="{
opacity: user?.subscription?.type === 'Basic' ? '0.67' : 'initial',
'pointer-events':
user?.subscription?.type === 'Basic' ? 'none' : 'initial'
}"
[projectedTotalAmount]="user?.settings?.projectedTotalAmount" [projectedTotalAmount]="user?.settings?.projectedTotalAmount"
[retirementDate]="user?.settings?.retirementDate" [retirementDate]="user?.settings?.retirementDate"
[savingsRate]="user?.settings?.savingsRate" [savingsRate]="user?.settings?.savingsRate"
[style.opacity]="
user?.subscription?.type === 'Basic' ? '0.67' : 'initial'
"
[style.pointer-events]="
user?.subscription?.type === 'Basic' ? 'none' : 'initial'
"
(annualInterestRateChanged)="onAnnualInterestRateChange($event)" (annualInterestRateChanged)="onAnnualInterestRateChange($event)"
(calculationCompleted)="onCalculationComplete($event)" (calculationCompleted)="onCalculationComplete($event)"
(projectedTotalAmountChanged)="onProjectedTotalAmountChange($event)" (projectedTotalAmountChanged)="onProjectedTotalAmountChange($event)"

250
apps/client/src/locales/messages.ko.xlf

File diff suppressed because it is too large

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

@ -252,6 +252,7 @@ export const PROPERTY_IS_DATA_GATHERING_ENABLED = 'IS_DATA_GATHERING_ENABLED';
export const PROPERTY_IS_READ_ONLY_MODE = 'IS_READ_ONLY_MODE'; export const PROPERTY_IS_READ_ONLY_MODE = 'IS_READ_ONLY_MODE';
export const PROPERTY_IS_USER_SIGNUP_ENABLED = 'IS_USER_SIGNUP_ENABLED'; export const PROPERTY_IS_USER_SIGNUP_ENABLED = 'IS_USER_SIGNUP_ENABLED';
export const PROPERTY_OPENROUTER_MODEL = 'OPENROUTER_MODEL'; export const PROPERTY_OPENROUTER_MODEL = 'OPENROUTER_MODEL';
export const PROPERTY_OPENROUTER_MODEL_WEB_FETCH = 'OPENROUTER_MODEL_WEB_FETCH';
export const PROPERTY_SLACK_COMMUNITY_USERS = 'SLACK_COMMUNITY_USERS'; export const PROPERTY_SLACK_COMMUNITY_USERS = 'SLACK_COMMUNITY_USERS';
export const PROPERTY_STRIPE_CONFIG = 'STRIPE_CONFIG'; export const PROPERTY_STRIPE_CONFIG = 'STRIPE_CONFIG';
export const PROPERTY_SYSTEM_MESSAGE = 'SYSTEM_MESSAGE'; export const PROPERTY_SYSTEM_MESSAGE = 'SYSTEM_MESSAGE';

7
libs/ui/src/lib/account-balances/account-balances.component.html

@ -16,7 +16,12 @@
</td> </td>
<td *matFooterCellDef class="px-2" mat-footer-cell> <td *matFooterCellDef class="px-2" mat-footer-cell>
<mat-form-field appearance="outline" class="py-1 without-hint"> <mat-form-field appearance="outline" class="py-1 without-hint">
<input formControlName="date" matInput [matDatepicker]="date" /> <input
formControlName="date"
matInput
[matDatepicker]="date"
[max]="maxDate"
/>
<mat-datepicker-toggle matSuffix [for]="date"> <mat-datepicker-toggle matSuffix [for]="date">
<ion-icon <ion-icon
class="text-muted" class="text-muted"

1
libs/ui/src/lib/account-balances/account-balances.component.ts

@ -85,6 +85,7 @@ export class GfAccountBalancesComponent implements OnChanges, OnInit {
public dataSource = new MatTableDataSource< public dataSource = new MatTableDataSource<
AccountBalancesResponse['balances'][0] AccountBalancesResponse['balances'][0]
>(); >();
public maxDate = new Date();
private dateAdapter = inject<DateAdapter<Date, string>>(DateAdapter); private dateAdapter = inject<DateAdapter<Date, string>>(DateAdapter);
private notificationService = inject(NotificationService); private notificationService = inject(NotificationService);

2
libs/ui/src/lib/fire-calculator/fire-calculator.component.html

@ -81,7 +81,7 @@
<canvas <canvas
#chartCanvas #chartCanvas
class="h-100" class="h-100"
[ngStyle]="{ display: isLoading ? 'none' : 'block' }" [style.display]="isLoading ? 'none' : 'block'"
></canvas> ></canvas>
</div> </div>
</div> </div>

5
libs/ui/src/lib/line-chart/line-chart.component.html

@ -7,7 +7,4 @@
}" }"
/> />
} }
<canvas <canvas #chartCanvas [style.display]="isLoading ? 'none' : 'block'"></canvas>
#chartCanvas
[ngStyle]="{ display: isLoading ? 'none' : 'block' }"
></canvas>

3
libs/ui/src/lib/line-chart/line-chart.component.ts

@ -12,7 +12,6 @@ import {
import { LineChartItem } from '@ghostfolio/common/interfaces'; import { LineChartItem } from '@ghostfolio/common/interfaces';
import { ColorScheme } from '@ghostfolio/common/types'; import { ColorScheme } from '@ghostfolio/common/types';
import { CommonModule } from '@angular/common';
import { import {
AfterViewInit, AfterViewInit,
ChangeDetectionStrategy, ChangeDetectionStrategy,
@ -43,7 +42,7 @@ import { registerChartConfiguration } from '../chart';
@Component({ @Component({
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, NgxSkeletonLoaderModule], imports: [NgxSkeletonLoaderModule],
selector: 'gf-line-chart', selector: 'gf-line-chart',
styleUrls: ['./line-chart.component.scss'], styleUrls: ['./line-chart.component.scss'],
templateUrl: './line-chart.component.html' templateUrl: './line-chart.component.html'

5
libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.html

@ -7,7 +7,4 @@
}" }"
/> />
} }
<canvas <canvas #chartCanvas [style.display]="isLoading ? 'none' : 'block'"></canvas>
#chartCanvas
[ngStyle]="{ display: isLoading ? 'none' : 'block' }"
></canvas>

3
libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts

@ -7,7 +7,6 @@ import {
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { ColorScheme } from '@ghostfolio/common/types'; import { ColorScheme } from '@ghostfolio/common/types';
import { CommonModule } from '@angular/common';
import { import {
AfterViewInit, AfterViewInit,
ChangeDetectionStrategy, ChangeDetectionStrategy,
@ -54,7 +53,7 @@ const {
@Component({ @Component({
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, NgxSkeletonLoaderModule], imports: [NgxSkeletonLoaderModule],
selector: 'gf-portfolio-proportion-chart', selector: 'gf-portfolio-proportion-chart',
styleUrls: ['./portfolio-proportion-chart.component.scss'], styleUrls: ['./portfolio-proportion-chart.component.scss'],
templateUrl: './portfolio-proportion-chart.component.html' templateUrl: './portfolio-proportion-chart.component.html'

2
libs/ui/src/lib/premium-indicator/premium-indicator.component.html

@ -1,7 +1,7 @@
<a <a
class="align-items-center d-flex" class="align-items-center d-flex"
title="Upgrade to Ghostfolio Premium" title="Upgrade to Ghostfolio Premium"
[ngStyle]="{ 'pointer-events': enableLink ? 'initial' : 'none' }"
[routerLink]="routerLinkPricing" [routerLink]="routerLinkPricing"
[style.pointer-events]="enableLink ? 'initial' : 'none'"
><ion-icon class="text-muted" name="diamond-outline" ><ion-icon class="text-muted" name="diamond-outline"
/></a> /></a>

3
libs/ui/src/lib/premium-indicator/premium-indicator.component.ts

@ -1,6 +1,5 @@
import { publicRoutes } from '@ghostfolio/common/routes/routes'; import { publicRoutes } from '@ghostfolio/common/routes/routes';
import { CommonModule } from '@angular/common';
import { import {
CUSTOM_ELEMENTS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA,
ChangeDetectionStrategy, ChangeDetectionStrategy,
@ -14,7 +13,7 @@ import { diamondOutline } from 'ionicons/icons';
@Component({ @Component({
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, IonIcon, RouterModule], imports: [IonIcon, RouterModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA], schemas: [CUSTOM_ELEMENTS_SCHEMA],
selector: 'gf-premium-indicator', selector: 'gf-premium-indicator',
styleUrls: ['./premium-indicator.component.scss'], styleUrls: ['./premium-indicator.component.scss'],

5
libs/ui/src/lib/treemap-chart/treemap-chart.component.html

@ -7,7 +7,4 @@
}" }"
/> />
} }
<canvas <canvas #chartCanvas [style.display]="isLoading ? 'none' : 'block'"></canvas>
#chartCanvas
[ngStyle]="{ display: isLoading ? 'none' : 'block' }"
></canvas>

3
libs/ui/src/lib/treemap-chart/treemap-chart.component.ts

@ -10,7 +10,6 @@ import {
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { ColorScheme, DateRange } from '@ghostfolio/common/types'; import { ColorScheme, DateRange } from '@ghostfolio/common/types';
import { CommonModule } from '@angular/common';
import { import {
AfterViewInit, AfterViewInit,
ChangeDetectionStrategy, ChangeDetectionStrategy,
@ -45,7 +44,7 @@ const { gray, green, red } = OpenColor;
@Component({ @Component({
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, NgxSkeletonLoaderModule], imports: [NgxSkeletonLoaderModule],
selector: 'gf-treemap-chart', selector: 'gf-treemap-chart',
styleUrls: ['./treemap-chart.component.scss'], styleUrls: ['./treemap-chart.component.scss'],
templateUrl: './treemap-chart.component.html' templateUrl: './treemap-chart.component.html'

Loading…
Cancel
Save