Browse Source

Merge remote-tracking branch 'origin/main' into feature/extend-holdings-endpoint-for-cash

pull/5650/head
Kenrick Tandrian 3 weeks ago
parent
commit
9048b67778
  1. 12
      CHANGELOG.md
  2. 10
      apps/api/src/services/symbol-profile/symbol-profile.service.ts
  3. 7
      apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts
  4. 6
      apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html
  5. 5
      apps/client/src/app/components/user-account-settings/user-account-settings.component.ts
  6. 2
      apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html
  7. 1
      libs/common/src/lib/interfaces/enhanced-symbol-profile.interface.ts
  8. 25
      libs/common/src/lib/personal-finance-tools.ts
  9. 193
      package-lock.json
  10. 2
      package.json

12
CHANGELOG.md

@ -5,6 +5,18 @@ 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/), 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). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Changed
- Lifted the asset profile identifier editing restriction for `MANUAL` data sources in the asset profile details dialog of the admin control panel
- Upgraded `shx` from version `0.3.4` to `0.4.0`
### Fixed
- Added the missing currency suffix to the cash balance field in the create or update account dialog
- Fixed the delete button in the asset profile details dialog of the admin control panel by providing the missing `watchedByCount` parameter
## 2.224.2 - 2025-12-20 ## 2.224.2 - 2025-12-20
### Added ### Added

10
apps/api/src/services/symbol-profile/symbol-profile.service.ts

@ -77,7 +77,7 @@ export class SymbolProfileService {
.findMany({ .findMany({
include: { include: {
_count: { _count: {
select: { activities: true } select: { activities: true, watchedBy: true }
}, },
activities: { activities: {
orderBy: { orderBy: {
@ -109,7 +109,7 @@ export class SymbolProfileService {
.findMany({ .findMany({
include: { include: {
_count: { _count: {
select: { activities: true } select: { activities: true, watchedBy: true }
}, },
SymbolProfileOverrides: true SymbolProfileOverrides: true
}, },
@ -184,7 +184,7 @@ export class SymbolProfileService {
private enhanceSymbolProfiles( private enhanceSymbolProfiles(
symbolProfiles: (SymbolProfile & { symbolProfiles: (SymbolProfile & {
_count: { activities: number }; _count: { activities: number; watchedBy?: number };
activities?: { activities?: {
date: Date; date: Date;
}[]; }[];
@ -206,10 +206,12 @@ export class SymbolProfileService {
sectors: this.getSectors( sectors: this.getSectors(
symbolProfile?.sectors as unknown as Prisma.JsonArray symbolProfile?.sectors as unknown as Prisma.JsonArray
), ),
symbolMapping: this.getSymbolMapping(symbolProfile) symbolMapping: this.getSymbolMapping(symbolProfile),
watchedByCount: 0
}; };
item.activitiesCount = symbolProfile._count.activities; item.activitiesCount = symbolProfile._count.activities;
item.watchedByCount = symbolProfile._count.watchedBy ?? 0;
delete item._count; delete item._count;
item.dateOfFirstActivity = symbolProfile.activities?.[0]?.date; item.dateOfFirstActivity = symbolProfile.activities?.[0]?.date;

7
apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts

@ -260,13 +260,6 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit {
addIcons({ createOutline, ellipsisVertical, readerOutline, serverOutline }); addIcons({ createOutline, ellipsisVertical, readerOutline, serverOutline });
} }
public get canEditAssetProfileIdentifier() {
return (
this.assetProfile?.assetClass &&
!['MANUAL'].includes(this.assetProfile?.dataSource)
);
}
public get canSaveAssetProfileIdentifier() { public get canSaveAssetProfileIdentifier() {
return !this.assetProfileForm.dirty; return !this.assetProfileForm.dirty;
} }

6
apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html

@ -73,7 +73,8 @@
!adminMarketDataService.hasPermissionToDeleteAssetProfile({ !adminMarketDataService.hasPermissionToDeleteAssetProfile({
activitiesCount: assetProfile?.activitiesCount, activitiesCount: assetProfile?.activitiesCount,
isBenchmark: isBenchmark, isBenchmark: isBenchmark,
symbol: data.symbol symbol: data.symbol,
watchedByCount: assetProfile?.watchedByCount
}) })
" "
(click)=" (click)="
@ -186,9 +187,6 @@
mat-button mat-button
type="button" type="button"
[disabled]="!canSaveAssetProfileIdentifier" [disabled]="!canSaveAssetProfileIdentifier"
[ngClass]="{
'd-none': !canEditAssetProfileIdentifier
}"
(click)="onSetEditAssetProfileIdentifierMode()" (click)="onSetEditAssetProfileIdentifierMode()"
> >
<ion-icon name="create-outline" /> <ion-icon name="create-outline" />

5
apps/client/src/app/components/user-account-settings/user-account-settings.component.ts

@ -11,6 +11,7 @@ import { ConfirmationDialogType } from '@ghostfolio/common/enums';
import { downloadAsFile } from '@ghostfolio/common/helper'; import { downloadAsFile } from '@ghostfolio/common/helper';
import { User } from '@ghostfolio/common/interfaces'; import { User } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { internalRoutes } from '@ghostfolio/common/routes/routes';
import { NotificationService } from '@ghostfolio/ui/notifications'; import { NotificationService } from '@ghostfolio/ui/notifications';
import { import {
@ -169,9 +170,9 @@ export class GfUserAccountSettingsComponent implements OnDestroy, OnInit {
if (aKey === 'language') { if (aKey === 'language') {
if (aValue) { if (aValue) {
window.location.href = `../${aValue}/account`; window.location.href = `../${aValue}/${internalRoutes.account.path}`;
} else { } else {
window.location.href = `../`; window.location.href = '../';
} }
} }
}); });

2
apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html

@ -39,7 +39,7 @@
(keydown.enter)="$event.stopPropagation()" (keydown.enter)="$event.stopPropagation()"
/> />
<span class="ml-2" matTextSuffix>{{ <span class="ml-2" matTextSuffix>{{
accountForm.get('currency')?.value?.value accountForm.get('currency')?.value
}}</span> }}</span>
</mat-form-field> </mat-form-field>
</div> </div>

1
libs/common/src/lib/interfaces/enhanced-symbol-profile.interface.ts

@ -33,4 +33,5 @@ export interface EnhancedSymbolProfile {
updatedAt: Date; updatedAt: Date;
url?: string; url?: string;
userId?: string; userId?: string;
watchedByCount?: number;
} }

25
libs/common/src/lib/personal-finance-tools.ts

@ -107,6 +107,15 @@ export const personalFinanceTools: Product[] = [
pricingPerYear: '$100', pricingPerYear: '$100',
slogan: 'Stock Portfolio Tracker for Smart Investors' slogan: 'Stock Portfolio Tracker for Smart Investors'
}, },
{
founded: 2024,
hasSelfHostingAbility: false,
key: 'bluebudget',
languages: ['Deutsch', 'English', 'Français', 'Italiano'],
name: 'BlueBudget',
origin: 'Switzerland',
slogan: 'Schweizer Budget App für einfache & smarte Budgetplanung'
},
{ {
key: 'budgetpulse', key: 'budgetpulse',
name: 'BudgetPulse', name: 'BudgetPulse',
@ -641,6 +650,15 @@ export const personalFinanceTools: Product[] = [
origin: 'Germany', origin: 'Germany',
slogan: 'Dein smarter Finance Assistant' slogan: 'Dein smarter Finance Assistant'
}, },
{
founded: 2007,
key: 'moneyspire',
name: 'Moneyspire',
note: 'License is a perpetual license',
origin: 'United States',
pricingPerYear: '$59.99',
slogan: 'Have total control of your financial life'
},
{ {
key: 'moneywiz', key: 'moneywiz',
name: 'MoneyWiz', name: 'MoneyWiz',
@ -716,6 +734,13 @@ export const personalFinanceTools: Product[] = [
origin: 'Singapore', origin: 'Singapore',
slogan: 'Feel in control of your money without spreadsheets or shame' slogan: 'Feel in control of your money without spreadsheets or shame'
}, },
{
key: 'pennies',
name: 'Pennies',
origin: 'United States',
pricingPerYear: '$39.99',
slogan: 'Your money. Made simple.'
},
{ {
founded: 2022, founded: 2022,
hasFreePlan: true, hasFreePlan: true,

193
package-lock.json

@ -148,7 +148,7 @@
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"replace-in-file": "8.3.0", "replace-in-file": "8.3.0",
"shx": "0.3.4", "shx": "0.4.0",
"storybook": "9.1.5", "storybook": "9.1.5",
"ts-jest": "29.4.0", "ts-jest": "29.4.0",
"ts-node": "10.9.2", "ts-node": "10.9.2",
@ -32982,6 +32982,13 @@
"@stripe/stripe-js": ">=7.0.0 <8.0.0" "@stripe/stripe-js": ">=7.0.0 <8.0.0"
} }
}, },
"node_modules/nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"dev": true,
"license": "MIT"
},
"node_modules/no-case": { "node_modules/no-case": {
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
@ -34294,6 +34301,16 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/p-finally": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
"integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/p-limit": { "node_modules/p-limit": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@ -36030,8 +36047,6 @@
"integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"optional": true,
"peer": true,
"dependencies": { "dependencies": {
"end-of-stream": "^1.1.0", "end-of-stream": "^1.1.0",
"once": "^1.3.1" "once": "^1.3.1"
@ -38033,60 +38048,174 @@
} }
}, },
"node_modules/shelljs": { "node_modules/shelljs": {
"version": "0.8.5", "version": "0.9.2",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.9.2.tgz",
"integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", "integrity": "sha512-S3I64fEiKgTZzKCC46zT/Ib9meqofLrQVbpSswtjFfAVDW+AZ54WTnAM/3/yENoxz/V1Cy6u3kiiEbQ4DNphvw==",
"dev": true, "dev": true,
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"glob": "^7.0.0", "execa": "^1.0.0",
"fast-glob": "^3.3.2",
"interpret": "^1.0.0", "interpret": "^1.0.0",
"rechoir": "^0.6.2" "rechoir": "^0.6.2"
}, },
"bin": { "bin": {
"shjs": "bin/shjs" "shjs": "bin/shjs"
}, },
"engines": {
"node": ">=18"
}
},
"node_modules/shelljs/node_modules/cross-spawn": {
"version": "6.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz",
"integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==",
"dev": true,
"license": "MIT",
"dependencies": {
"nice-try": "^1.0.4",
"path-key": "^2.0.1",
"semver": "^5.5.0",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
},
"engines": {
"node": ">=4.8"
}
},
"node_modules/shelljs/node_modules/execa": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
"integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
"dev": true,
"license": "MIT",
"dependencies": {
"cross-spawn": "^6.0.0",
"get-stream": "^4.0.0",
"is-stream": "^1.1.0",
"npm-run-path": "^2.0.0",
"p-finally": "^1.0.0",
"signal-exit": "^3.0.0",
"strip-eof": "^1.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/shelljs/node_modules/get-stream": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
"integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
"dev": true,
"license": "MIT",
"dependencies": {
"pump": "^3.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/shelljs/node_modules/is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
"integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/shelljs/node_modules/npm-run-path": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
"integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==",
"dev": true,
"license": "MIT",
"dependencies": {
"path-key": "^2.0.0"
},
"engines": { "engines": {
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/shelljs/node_modules/glob": { "node_modules/shelljs/node_modules/path-key": {
"version": "7.2.3", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
"deprecated": "Glob versions prior to v9 are no longer supported", "dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/shelljs/node_modules/semver": {
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true, "dev": true,
"license": "ISC", "license": "ISC",
"bin": {
"semver": "bin/semver"
}
},
"node_modules/shelljs/node_modules/shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
"integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
"dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"fs.realpath": "^1.0.0", "shebang-regex": "^1.0.0"
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}, },
"engines": { "engines": {
"node": "*" "node": ">=0.10.0"
}
},
"node_modules/shelljs/node_modules/shebang-regex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
"integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/shelljs/node_modules/signal-exit": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"dev": true,
"license": "ISC"
},
"node_modules/shelljs/node_modules/which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"dev": true,
"license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
}, },
"funding": { "bin": {
"url": "https://github.com/sponsors/isaacs" "which": "bin/which"
} }
}, },
"node_modules/shx": { "node_modules/shx": {
"version": "0.3.4", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", "resolved": "https://registry.npmjs.org/shx/-/shx-0.4.0.tgz",
"integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", "integrity": "sha512-Z0KixSIlGPpijKgcH6oCMCbltPImvaKy0sGH8AkLRXw1KyzpKtaCTizP2xen+hNDqVF4xxgvA0KXSb9o4Q6hnA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"minimist": "^1.2.3", "minimist": "^1.2.8",
"shelljs": "^0.8.5" "shelljs": "^0.9.2"
}, },
"bin": { "bin": {
"shx": "lib/cli.js" "shx": "lib/cli.js"
}, },
"engines": { "engines": {
"node": ">=6" "node": ">=18"
} }
}, },
"node_modules/side-channel": { "node_modules/side-channel": {
@ -38910,6 +39039,16 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/strip-eof": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
"integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/strip-final-newline": { "node_modules/strip-final-newline": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",

2
package.json

@ -192,7 +192,7 @@
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"replace-in-file": "8.3.0", "replace-in-file": "8.3.0",
"shx": "0.3.4", "shx": "0.4.0",
"storybook": "9.1.5", "storybook": "9.1.5",
"ts-jest": "29.4.0", "ts-jest": "29.4.0",
"ts-node": "10.9.2", "ts-node": "10.9.2",

Loading…
Cancel
Save