From fc083fb0cd36efa2da17ebeeeb9d668ed15e3ea8 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 1 Sep 2026 20:19:16 +0200 Subject: [PATCH 1/2] Bugfix/loading state of holdings table on portfolio holdings page (#7788) * Fix loading state of holdings table * Update changelog --- CHANGELOG.md | 1 + .../src/app/components/home-holdings/home-holdings.html | 2 +- libs/ui/src/lib/holdings-table/holdings-table.component.ts | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 646c59ecb9..ad6228c2ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fixed the loading state of the accounts table on the accounts page +- Fixed the loading state of the holdings table on the portfolio holdings page ## 3.65.0 - 2026-08-31 diff --git a/apps/client/src/app/components/home-holdings/home-holdings.html b/apps/client/src/app/components/home-holdings/home-holdings.html index df6d57c0e9..b55b1c54ef 100644 --- a/apps/client/src/app/components/home-holdings/home-holdings.html +++ b/apps/client/src/app/components/home-holdings/home-holdings.html @@ -37,7 +37,7 @@ }
diff --git a/libs/ui/src/lib/holdings-table/holdings-table.component.ts b/libs/ui/src/lib/holdings-table/holdings-table.component.ts index 7fe21720ef..1bbfa515b1 100644 --- a/libs/ui/src/lib/holdings-table/holdings-table.component.ts +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.ts @@ -50,7 +50,7 @@ export class GfHoldingsTableComponent { public readonly hasPermissionToOpenDetails = input(true); public readonly hasPermissionToShowQuantities = input(true); public readonly hasPermissionToShowValues = input(true); - public readonly holdings = input.required(); + public readonly holdings = input.required(); public readonly locale = input(getLocale()); public readonly pageSize = model(Number.MAX_SAFE_INTEGER); @@ -89,7 +89,7 @@ export class GfHoldingsTableComponent { // Reactive data update effect(() => { - this.dataSource.data = this.holdings(); + this.dataSource.data = this.holdings() ?? []; }); // Reactive view connection From 2ce58d767d78356ac373f3b9056c00eb9ed3f001 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 1 Sep 2026 20:22:55 +0200 Subject: [PATCH 2/2] Task/restrict restricted view and manage permission to MCP (#7783) * Restrict restricted view and manage permission to MCP * Update changelog --- CHANGELOG.md | 4 ++++ ...reate-or-update-access-dialog.component.ts | 5 +++++ .../create-or-update-access-dialog.html | 2 +- libs/common/src/lib/scopes.ts | 21 +++++++++++++++++-- 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad6228c2ac..56b2f2e35c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Changed + +- Restricted the _Restricted view and manage_ permission of the access to share the portfolio to the Model Context Protocol (MCP) (experimental) + ### Fixed - Fixed the loading state of the accounts table on the accounts page diff --git a/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts b/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts index b0be5c0c52..8c2bb0353a 100644 --- a/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts +++ b/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts @@ -6,6 +6,7 @@ import { Filter, PortfolioPosition } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { Scope, + canGrantRestrictedWriteAccess, getAccessLevel, getScopesOfAccess, getScopesOfAccessLevel, @@ -125,6 +126,10 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit { return this.hasExperimentalFeatures && this.hasPermissionToEnableMcp; } + public get canGrantRestrictedWriteAccess() { + return canGrantRestrictedWriteAccess({ type: this.accessType }); + } + public get canGrantWriteAccess() { return this.hasExperimentalFeatures; } diff --git a/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html b/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html index 89893e5708..21c0cd3a8b 100644 --- a/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html +++ b/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -82,7 +82,7 @@ - @if (!isPublicAccess) { + @if (canGrantRestrictedWriteAccess) { = { MCP: [...SCOPES_OF_READ_RESTRICTED_ACCESS, scopes.activityCreate], @@ -72,6 +74,14 @@ const SCOPES_OF_TYPE: Record = { PUBLIC: SCOPES_OF_PUBLIC_ACCESS }; +/** + * Access types which combine a write scope with the restricted read access, + * because their tools change data without exposing the monetary values + */ +export function canGrantRestrictedWriteAccess({ type }: { type: AccessType }) { + return type === 'MCP'; +} + /** * Access level which the scopes of an access grant */ @@ -96,9 +106,16 @@ export function getScopesOfAccess({ }): string[] { const scopesToEvaluate = scopesOfAccess ?? []; + const permitsWriteAccess = + canGrantRestrictedWriteAccess({ type }) || + hasScope(scopesToEvaluate, scopes.portfolioReadValues); + // An unknown scope is dropped return SCOPES_OF_TYPE[type].filter((scope) => { - return scopesToEvaluate.includes(scope); + return ( + scopesToEvaluate.includes(scope) && + (permitsWriteAccess || !SCOPES_OF_WRITE_ACCESS.includes(scope)) + ); }); }