Browse Source

Merge branch 'main' into bugfix/date-ranges-in-time-zones-other-than-utc

pull/8099/head
Thomas Kaul 5 days ago
committed by GitHub
parent
commit
c8cf5eb75d
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 19
      apps/api/src/app/endpoints/ai/ai.controller.ts
  3. 2
      apps/api/src/app/endpoints/ai/ai.module.ts
  4. 10
      apps/client/src/app/components/home-overview/home-overview.component.ts
  5. 2
      apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts

2
CHANGELOG.md

@ -9,11 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Simplified the portfolio performance on the overview tab of the home page by hiding the currency on mobile
- Extended the access to share the portfolio with the Model Context Protocol (MCP) to support the _View_ and the _View and manage_ permissions (experimental)
- Improved the performance of getting the historical market data by selecting only the required columns
### Fixed
- Fixed the _Copy AI prompt to clipboard_ actions on the analysis page in impersonation mode to be based on the impersonated user (experimental)
- Fixed the start date of the date ranges for instances in time zones with a negative UTC offset
## 3.83.0 - 2026-10-10

19
apps/api/src/app/endpoints/ai/ai.controller.ts

@ -1,11 +1,17 @@
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
import { Impersonation } from '@ghostfolio/api/decorators/impersonation.decorator';
import { RequiresScope } from '@ghostfolio/api/decorators/requires-scope.decorator';
import { FilterDto } from '@ghostfolio/api/dtos/filter.dto';
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor';
import { ApiService } from '@ghostfolio/api/services/api/api.service';
import { AiPromptResponse } from '@ghostfolio/common/interfaces';
import { permissions } from '@ghostfolio/common/permissions';
import type { AiPromptMode, RequestWithUser } from '@ghostfolio/common/types';
import { scopes } from '@ghostfolio/common/scopes';
import type {
AiPromptMode,
ImpersonationContext,
RequestWithUser
} from '@ghostfolio/common/types';
import {
Controller,
@ -13,11 +19,9 @@ import {
Inject,
Param,
Query,
UseGuards,
UseInterceptors
} from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
import { AiService } from './ai.service';
@ -31,9 +35,10 @@ export class AiController {
@Get('prompt/:mode')
@HasPermission(permissions.readAiPrompt)
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
@RequiresScope(scopes.portfolioRead)
@UseInterceptors(TransformDataSourceInRequestInterceptor)
public async getPrompt(
@Impersonation() { userId, userSettings }: ImpersonationContext,
@Param('mode') mode: AiPromptMode,
@Query()
{ accounts, assetClasses, dataSource, symbol, tags }: FilterDto
@ -49,9 +54,9 @@ export class AiController {
const prompt = await this.aiService.getPrompt({
filters,
mode,
userId,
languageCode: this.request.user.settings.settings.language,
userCurrency: this.request.user.settings.settings.baseCurrency,
userId: this.request.user.id
userCurrency: userSettings.baseCurrency
});
return { prompt };

2
apps/api/src/app/endpoints/ai/ai.module.ts

@ -1,6 +1,7 @@
import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module';
import { ApiModule } from '@ghostfolio/api/services/api/api.module';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module';
import { ImpersonationModule } from '@ghostfolio/api/services/impersonation/impersonation.module';
import { PortfolioTableModule } from '@ghostfolio/api/services/portfolio-table/portfolio-table.module';
import { PropertyModule } from '@ghostfolio/api/services/property/property.module';
@ -15,6 +16,7 @@ import { AiService } from './ai.service';
imports: [
ApiModule,
ConfigurationModule,
ImpersonationModule,
PortfolioTableModule,
PropertyModule,
TransformDataSourceInRequestModule

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

@ -106,11 +106,13 @@ export class GfHomeOverviewComponent implements OnInit {
});
protected readonly unit = computed(() => {
const user = this.user();
if (!this.showDetails()) {
return '%';
}
return this.showDetails()
? (user?.settings?.baseCurrency ?? DEFAULT_CURRENCY)
: '%';
return this.deviceType() === 'mobile'
? undefined
: (this.user()?.settings?.baseCurrency ?? DEFAULT_CURRENCY);
});
private readonly dataService = inject(DataService);

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

@ -44,7 +44,7 @@ export class GfPortfolioPerformanceComponent {
}
});
public readonly showDetails = input<boolean>(false);
public readonly unit = input.required<string>();
public readonly unit = input.required<string | undefined>();
private readonly value =
viewChild.required<ElementRef<HTMLSpanElement>>('value');

Loading…
Cancel
Save