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))
+ );
});
}