From d7abce03dfc34d79d1f7f4f59233e61df31af156 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 5 Jul 2026 18:57:45 +0200 Subject: [PATCH 1/2] Remove deprecated attribute isExcluded from account --- apps/api/src/app/export/export.service.ts | 2 -- apps/api/src/app/import/import.service.ts | 20 ++++++++++++++++-- .../roai/portfolio-calculator-cash.spec.ts | 1 - .../app/portfolio/portfolio.service.spec.ts | 3 --- apps/api/src/helper/account.helper.ts | 1 - .../pages/accounts/accounts-page.component.ts | 3 --- ...eate-or-update-account-dialog.component.ts | 4 ---- .../create-or-update-account-dialog.html | 19 ++++++----------- .../dtos/create-account-with-balances.dto.ts | 10 ++++++++- .../common/src/lib/dtos/create-account.dto.ts | 8 ------- .../common/src/lib/dtos/update-account.dto.ts | 8 ------- libs/common/src/lib/helper.ts | 6 +----- .../accounts-table.component.stories.ts | 3 --- .../activities-table.component.stories.ts | 5 ----- .../migration.sql | 21 +++++++++++++++++++ prisma/schema.prisma | 3 --- 16 files changed, 55 insertions(+), 62 deletions(-) create mode 100644 prisma/migrations/20260705120000_removed_is_excluded_from_account/migration.sql diff --git a/apps/api/src/app/export/export.service.ts b/apps/api/src/app/export/export.service.ts index 8ebfde13d..f820d29b3 100644 --- a/apps/api/src/app/export/export.service.ts +++ b/apps/api/src/app/export/export.service.ts @@ -94,7 +94,6 @@ export class ExportService { comment, currency, id, - isExcluded, name, platform, platformId, @@ -112,7 +111,6 @@ export class ExportService { comment, currency, id, - isExcluded, name, platformId, tags: tags.map(({ id: tagId }) => { diff --git a/apps/api/src/app/import/import.service.ts b/apps/api/src/app/import/import.service.ts index 9b1aa417c..948c478e2 100644 --- a/apps/api/src/app/import/import.service.ts +++ b/apps/api/src/app/import/import.service.ts @@ -9,7 +9,10 @@ import { MarketDataService } from '@ghostfolio/api/services/market-data/market-d import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; import { TagService } from '@ghostfolio/api/services/tag/tag.service'; -import { DATA_GATHERING_QUEUE_PRIORITY_HIGH } from '@ghostfolio/common/config'; +import { + DATA_GATHERING_QUEUE_PRIORITY_HIGH, + TAG_ID_EXCLUDE_FROM_ANALYSIS +} from '@ghostfolio/common/config'; import { CreateAssetProfileDto, CreateOrderDto } from '@ghostfolio/common/dtos'; import { getAssetProfileIdentifier, @@ -272,7 +275,11 @@ export class ImportService { // If there is no account or if the account belongs to a different user then create a new account if (!accountWithSameId || accountWithSameId.userId !== user.id) { - const account = omit(accountWithBalances, ['balances', 'tags']); + const account = omit(accountWithBalances, [ + 'balances', + 'isExcluded', + 'tags' + ]); let oldAccountId: string; const platformId = account.platformId; @@ -292,6 +299,15 @@ export class ImportService { return existingTagIds.has(tagId); }); + // Map the legacy isExcluded attribute of old export files to + // the "Exclude from Analysis" tag + if ( + accountWithBalances.isExcluded && + !tagIds.includes(TAG_ID_EXCLUDE_FROM_ANALYSIS) + ) { + tagIds.push(TAG_ID_EXCLUDE_FROM_ANALYSIS); + } + let accountObject: Prisma.AccountCreateInput = { ...account, balances: { diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts index 7774ee629..771bd7a88 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts @@ -171,7 +171,6 @@ describe('PortfolioCalculator', () => { createdAt: parseDate('2023-12-31'), currency: 'USD', id: accountId, - isExcluded: false, name: 'USD', platformId: null, updatedAt: parseDate('2023-12-31'), diff --git a/apps/api/src/app/portfolio/portfolio.service.spec.ts b/apps/api/src/app/portfolio/portfolio.service.spec.ts index 04142c92b..99834809a 100644 --- a/apps/api/src/app/portfolio/portfolio.service.spec.ts +++ b/apps/api/src/app/portfolio/portfolio.service.spec.ts @@ -185,7 +185,6 @@ describe('PortfolioService', () => { createdAt: parseDate('2024-01-01'), currency: 'USD', id: randomUUID(), - isExcluded: false, name: 'USD', platformId: null, updatedAt: parseDate('2024-01-01'), @@ -219,7 +218,6 @@ describe('PortfolioService', () => { createdAt: parseDate('2024-01-01'), currency: 'USD', id: accountId, - isExcluded: false, name: 'USD', platformId: null, updatedAt: parseDate('2024-01-01'), @@ -351,7 +349,6 @@ describe('PortfolioService', () => { balance: 100, currency: 'USD', id: randomUUID(), - isExcluded: false, name: 'Account 1', platform: { name: 'Platform 1' }, platformId: randomUUID() diff --git a/apps/api/src/helper/account.helper.ts b/apps/api/src/helper/account.helper.ts index 0800c022e..df848b812 100644 --- a/apps/api/src/helper/account.helper.ts +++ b/apps/api/src/helper/account.helper.ts @@ -3,7 +3,6 @@ import { TAG_ID_EXCLUDE_FROM_ANALYSIS } from '@ghostfolio/common/config'; import { Prisma } from '@prisma/client'; export const WHERE_ACCOUNT_NOT_EXCLUDED: Prisma.AccountWhereInput = { - isExcluded: false, tags: { none: { tagId: TAG_ID_EXCLUDE_FROM_ANALYSIS diff --git a/apps/client/src/app/pages/accounts/accounts-page.component.ts b/apps/client/src/app/pages/accounts/accounts-page.component.ts index 907b39d37..1f2ffe401 100644 --- a/apps/client/src/app/pages/accounts/accounts-page.component.ts +++ b/apps/client/src/app/pages/accounts/accounts-page.component.ts @@ -186,7 +186,6 @@ export class GfAccountsPageComponent implements OnInit { comment, currency, id, - isExcluded, name, platformId, tags @@ -201,7 +200,6 @@ export class GfAccountsPageComponent implements OnInit { comment, currency, id, - isExcluded, name, platformId, tags @@ -278,7 +276,6 @@ export class GfAccountsPageComponent implements OnInit { comment: null, currency: this.user?.settings?.baseCurrency ?? null, id: null, - isExcluded: false, name: null, platformId: null, tags: [] diff --git a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts index ca88120ca..dec6b57d8 100644 --- a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts +++ b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts @@ -27,7 +27,6 @@ import { } from '@angular/forms'; import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatButtonModule } from '@angular/material/button'; -import { MatCheckboxModule } from '@angular/material/checkbox'; import { MAT_DIALOG_DATA, MatDialogModule, @@ -51,7 +50,6 @@ import { CreateOrUpdateAccountDialogParams } from './interfaces/interfaces'; GfTagsSelectorComponent, MatAutocompleteModule, MatButtonModule, - MatCheckboxModule, MatDialogModule, MatFormFieldModule, MatInputModule, @@ -105,7 +103,6 @@ export class GfCreateOrUpdateAccountDialogComponent { balance: [this.data.account.balance, Validators.required], comment: [this.data.account.comment], currency: [this.data.account.currency, Validators.required], - isExcluded: [this.data.account.isExcluded], name: [this.data.account.name, Validators.required], platformId: [null, this.autocompleteObjectValidator()], tags: [ @@ -203,7 +200,6 @@ export class GfCreateOrUpdateAccountDialogComponent { comment: this.accountForm.get('comment')?.value || null, currency: this.accountForm.get('currency')?.value, id: this.accountForm.get('accountId')?.value, - isExcluded: this.accountForm.get('isExcluded')?.value, name: this.accountForm.get('name')?.value, platformId: this.accountForm.get('platformId')?.value?.id || null, tags: this.accountForm diff --git a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html index c707a9402..4e4c62b6f 100644 --- a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html +++ b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -85,19 +85,12 @@ > - @if (data.user?.settings?.isExperimentalFeatures) { -
- -
- } -
- Exclude from Analysis +
+
@if (data.account.id) {
diff --git a/libs/common/src/lib/dtos/create-account-with-balances.dto.ts b/libs/common/src/lib/dtos/create-account-with-balances.dto.ts index 2d1d3ed2a..8fc6f78e4 100644 --- a/libs/common/src/lib/dtos/create-account-with-balances.dto.ts +++ b/libs/common/src/lib/dtos/create-account-with-balances.dto.ts @@ -1,6 +1,6 @@ import { AccountBalance } from '@ghostfolio/common/interfaces'; -import { IsArray, IsOptional } from 'class-validator'; +import { IsArray, IsBoolean, IsOptional } from 'class-validator'; import { CreateAccountDto } from './create-account.dto'; @@ -8,4 +8,12 @@ export class CreateAccountWithBalancesDto extends CreateAccountDto { @IsArray() @IsOptional() balances?: AccountBalance[]; + + /** + * @deprecated Accepted for backward compatibility with old export files + * and mapped to the "Exclude from Analysis" tag (`TAG_ID_EXCLUDE_FROM_ANALYSIS`) + */ + @IsBoolean() + @IsOptional() + isExcluded?: boolean; } diff --git a/libs/common/src/lib/dtos/create-account.dto.ts b/libs/common/src/lib/dtos/create-account.dto.ts index b04193020..e4a0c64fe 100644 --- a/libs/common/src/lib/dtos/create-account.dto.ts +++ b/libs/common/src/lib/dtos/create-account.dto.ts @@ -4,7 +4,6 @@ import { Transform, TransformFnParams } from 'class-transformer'; import { ArrayUnique, IsArray, - IsBoolean, IsNumber, IsOptional, IsString, @@ -30,13 +29,6 @@ export class CreateAccountDto { @IsString() id?: string; - /** - * @deprecated Use the "Exclude from Analysis" tag (`TAG_ID_EXCLUDE_FROM_ANALYSIS`) instead - */ - @IsBoolean() - @IsOptional() - isExcluded?: boolean; - @IsString() name: string; diff --git a/libs/common/src/lib/dtos/update-account.dto.ts b/libs/common/src/lib/dtos/update-account.dto.ts index 7a33da2df..a6a3e6ac6 100644 --- a/libs/common/src/lib/dtos/update-account.dto.ts +++ b/libs/common/src/lib/dtos/update-account.dto.ts @@ -4,7 +4,6 @@ import { Transform, TransformFnParams } from 'class-transformer'; import { ArrayUnique, IsArray, - IsBoolean, IsNumber, IsOptional, IsString, @@ -29,13 +28,6 @@ export class UpdateAccountDto { @IsString() id: string; - /** - * @deprecated Use the "Exclude from Analysis" tag (`TAG_ID_EXCLUDE_FROM_ANALYSIS`) instead - */ - @IsBoolean() - @IsOptional() - isExcluded?: boolean; - @IsString() name: string; diff --git a/libs/common/src/lib/helper.ts b/libs/common/src/lib/helper.ts index f9dcd52cf..5d1321678 100644 --- a/libs/common/src/lib/helper.ts +++ b/libs/common/src/lib/helper.ts @@ -420,12 +420,8 @@ export function interpolate(template: string, context: any) { }); } -export function isAccountExcluded(account: { - isExcluded: boolean; - tags?: { id: string }[]; -}) { +export function isAccountExcluded(account: { tags?: { id: string }[] }) { return ( - account.isExcluded || account.tags?.some(({ id }) => { return id === TAG_ID_EXCLUDE_FROM_ANALYSIS; }) === true diff --git a/libs/ui/src/lib/accounts-table/accounts-table.component.stories.ts b/libs/ui/src/lib/accounts-table/accounts-table.component.stories.ts index 62a01164f..a38ca826c 100644 --- a/libs/ui/src/lib/accounts-table/accounts-table.component.stories.ts +++ b/libs/ui/src/lib/accounts-table/accounts-table.component.stories.ts @@ -24,7 +24,6 @@ const accounts = [ createdAt: new Date('2025-06-01T06:52:49.063Z'), currency: 'USD', id: '460d7401-ca43-4ed4-b08e-349f1822e9db', - isExcluded: false, name: 'Coinbase Account', platform: { id: '8dc24b88-bb92-4152-af25-fe6a31643e26', @@ -46,7 +45,6 @@ const accounts = [ createdAt: new Date('2025-06-01T06:48:53.055Z'), currency: 'USD', id: '6d773e31-0583-4c85-a247-e69870b4f1ee', - isExcluded: false, name: 'Private Banking Account', platform: { id: '43e8fcd1-5b79-4100-b678-d2229bd1660d', @@ -68,7 +66,6 @@ const accounts = [ createdAt: new Date('2025-05-31T13:00:13.940Z'), currency: 'USD', id: '776bd1e9-b2f6-4f7e-933d-18756c2f0625', - isExcluded: false, name: 'Trading Account', platform: { id: '9da3a8a7-4795-43e3-a6db-ccb914189737', diff --git a/libs/ui/src/lib/activities-table/activities-table.component.stories.ts b/libs/ui/src/lib/activities-table/activities-table.component.stories.ts index 25463e576..8fa11639c 100644 --- a/libs/ui/src/lib/activities-table/activities-table.component.stories.ts +++ b/libs/ui/src/lib/activities-table/activities-table.component.stories.ts @@ -45,7 +45,6 @@ const activities: Activity[] = [ createdAt: new Date('2025-05-31T13:00:13.940Z'), currency: 'USD', id: '776bd1e9-b2f6-4f7e-933d-18756c2f0625', - isExcluded: false, name: 'Trading Account', platformId: '9da3a8a7-4795-43e3-a6db-ccb914189737', updatedAt: new Date('2025-06-01T06:53:10.569Z'), @@ -112,7 +111,6 @@ const activities: Activity[] = [ createdAt: new Date('2025-05-31T13:00:13.940Z'), currency: 'USD', id: '776bd1e9-b2f6-4f7e-933d-18756c2f0625', - isExcluded: false, name: 'Trading Account', platformId: '9da3a8a7-4795-43e3-a6db-ccb914189737', updatedAt: new Date('2025-06-01T06:53:10.569Z'), @@ -179,7 +177,6 @@ const activities: Activity[] = [ createdAt: new Date('2025-05-31T13:00:13.940Z'), currency: 'USD', id: '776bd1e9-b2f6-4f7e-933d-18756c2f0625', - isExcluded: false, name: 'Trading Account', platformId: '9da3a8a7-4795-43e3-a6db-ccb914189737', updatedAt: new Date('2025-06-01T06:53:10.569Z'), @@ -246,7 +243,6 @@ const activities: Activity[] = [ createdAt: new Date('2025-05-31T13:00:13.940Z'), currency: 'USD', id: '776bd1e9-b2f6-4f7e-933d-18756c2f0625', - isExcluded: false, name: 'Trading Account', platformId: '9da3a8a7-4795-43e3-a6db-ccb914189737', updatedAt: new Date('2025-06-01T06:53:10.569Z'), @@ -313,7 +309,6 @@ const activities: Activity[] = [ createdAt: new Date('2025-05-31T13:00:13.940Z'), currency: 'USD', id: '776bd1e9-b2f6-4f7e-933d-18756c2f0625', - isExcluded: false, name: 'Trading Account', platformId: '9da3a8a7-4795-43e3-a6db-ccb914189737', updatedAt: new Date('2025-06-01T06:53:10.569Z'), diff --git a/prisma/migrations/20260705120000_removed_is_excluded_from_account/migration.sql b/prisma/migrations/20260705120000_removed_is_excluded_from_account/migration.sql new file mode 100644 index 000000000..5fb01f5d2 --- /dev/null +++ b/prisma/migrations/20260705120000_removed_is_excluded_from_account/migration.sql @@ -0,0 +1,21 @@ +-- Create the "EXCLUDE_FROM_ANALYSIS" tag if it does not exist yet +INSERT INTO "Tag" ("id", "name") +VALUES ('f2e868af-8333-459f-b161-cbc6544c24bd', 'EXCLUDE_FROM_ANALYSIS') +ON CONFLICT DO NOTHING; + +-- Migrate accounts with "isExcluded" to the "EXCLUDE_FROM_ANALYSIS" tag +INSERT INTO "TagsOnAccounts" ("accountId", "tagId", "updatedAt", "userId") +SELECT + "id", + 'f2e868af-8333-459f-b161-cbc6544c24bd', + CURRENT_TIMESTAMP, + "userId" +FROM "Account" +WHERE "isExcluded" = true +ON CONFLICT DO NOTHING; + +-- DropIndex +DROP INDEX "Account_isExcluded_idx"; + +-- AlterTable +ALTER TABLE "Account" DROP COLUMN "isExcluded"; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 233a63688..185437b89 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -33,8 +33,6 @@ model Account { createdAt DateTime @default(now()) currency String? id String @default(uuid()) - /// @deprecated Use the "Exclude from Analysis" tag (`TAG_ID_EXCLUDE_FROM_ANALYSIS`) instead - isExcluded Boolean @default(false) name String? platform Platform? @relation(fields: [platformId], references: [id]) platformId String? @@ -46,7 +44,6 @@ model Account { @@id([id, userId]) @@index([currency]) @@index([id]) - @@index([isExcluded]) @@index([name]) @@index([userId]) } From 82085ff22908358079a20d9ad6ea0391ec6ddd0f Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 5 Jul 2026 19:00:13 +0200 Subject: [PATCH 2/2] Update changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index df95d849b..234aef536 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Changed + +- Moved the support for tags in the account from experimental to general availability +- Removed the deprecated `isExcluded` attribute of the account in favor of the _Exclude from Analysis_ tag including a data migration + ## 3.21.0 - 2026-07-05 ### Added