Merge branch 'main' of github.com:ghostfolio/ghostfolio
All checks were successful
Docker image CD / build_and_push (push) Successful in 21m24s

This commit is contained in:
sudacode 2025-04-30 13:16:56 -07:00
commit 575615b972
26 changed files with 290 additions and 49 deletions

View File

@ -5,6 +5,21 @@ 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).
## 2.158.0 - 2025-04-30
### Added
- Added support to delete an asset from the watchlist (experimental)
### Changed
- Renamed `Order` to `activities` in the `Account` database schema
- Improved the language localization for German (`de`)
### Fixed
- Fixed an issue with the saving of activities with type `INTEREST`, `ITEM` and `LIABILITY`
## 2.157.1 - 2025-04-29 ## 2.157.1 - 2025-04-29
### Added ### Added

View File

@ -57,17 +57,17 @@ export class AccountController {
@HasPermission(permissions.deleteAccount) @HasPermission(permissions.deleteAccount)
@UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseGuards(AuthGuard('jwt'), HasPermissionGuard)
public async deleteAccount(@Param('id') id: string): Promise<AccountModel> { public async deleteAccount(@Param('id') id: string): Promise<AccountModel> {
const account = await this.accountService.accountWithOrders( const account = await this.accountService.accountWithActivities(
{ {
id_userId: { id_userId: {
id, id,
userId: this.request.user.id userId: this.request.user.id
} }
}, },
{ Order: true } { activities: true }
); );
if (!account || account?.Order.length > 0) { if (!account || account?.activities.length > 0) {
throw new HttpException( throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN), getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN StatusCodes.FORBIDDEN

View File

@ -39,12 +39,12 @@ export class AccountService {
return account; return account;
} }
public async accountWithOrders( public async accountWithActivities(
accountWhereUniqueInput: Prisma.AccountWhereUniqueInput, accountWhereUniqueInput: Prisma.AccountWhereUniqueInput,
accountInclude: Prisma.AccountInclude accountInclude: Prisma.AccountInclude
): Promise< ): Promise<
Account & { Account & {
Order?: Order[]; activities?: Order[];
} }
> { > {
return this.prismaService.account.findUnique({ return this.prismaService.account.findUnique({
@ -62,8 +62,8 @@ export class AccountService {
orderBy?: Prisma.AccountOrderByWithRelationInput; orderBy?: Prisma.AccountOrderByWithRelationInput;
}): Promise< }): Promise<
(Account & { (Account & {
activities?: Order[];
balances?: AccountBalance[]; balances?: AccountBalance[];
Order?: Order[];
Platform?: Platform; Platform?: Platform;
})[] })[]
> { > {
@ -140,7 +140,7 @@ export class AccountService {
public async getAccounts(aUserId: string): Promise<Account[]> { public async getAccounts(aUserId: string): Promise<Account[]> {
const accounts = await this.accounts({ const accounts = await this.accounts({
include: { Order: true, Platform: true }, include: { activities: true, Platform: true },
orderBy: { name: 'asc' }, orderBy: { name: 'asc' },
where: { userId: aUserId } where: { userId: aUserId }
}); });
@ -148,15 +148,15 @@ export class AccountService {
return accounts.map((account) => { return accounts.map((account) => {
let transactionCount = 0; let transactionCount = 0;
for (const order of account.Order) { for (const { isDraft } of account.activities) {
if (!order.isDraft) { if (!isDraft) {
transactionCount += 1; transactionCount += 1;
} }
} }
const result = { ...account, transactionCount }; const result = { ...account, transactionCount };
delete result.Order; delete result.activities;
return result; return result;
}); });

View File

@ -100,7 +100,7 @@ export class OrderService {
userId: string; userId: string;
} }
): Promise<Order> { ): Promise<Order> {
let Account: Prisma.AccountCreateNestedOneWithoutOrderInput; let Account: Prisma.AccountCreateNestedOneWithoutActivitiesInput;
if (data.accountId) { if (data.accountId) {
Account = { Account = {

View File

@ -139,7 +139,7 @@ export class PortfolioService {
} }
if (filterByDataSource && filterBySymbol) { if (filterByDataSource && filterBySymbol) {
where.Order = { where.activities = {
some: { some: {
SymbolProfile: { SymbolProfile: {
AND: [ AND: [
@ -154,7 +154,7 @@ export class PortfolioService {
const [accounts, details] = await Promise.all([ const [accounts, details] = await Promise.all([
this.accountService.accounts({ this.accountService.accounts({
where, where,
include: { Order: true, Platform: true }, include: { activities: true, Platform: true },
orderBy: { name: 'asc' } orderBy: { name: 'asc' }
}), }),
this.getDetails({ this.getDetails({
@ -170,8 +170,8 @@ export class PortfolioService {
return accounts.map((account) => { return accounts.map((account) => {
let transactionCount = 0; let transactionCount = 0;
for (const order of account.Order) { for (const { isDraft } of account.activities) {
if (!order.isDraft) { if (!isDraft) {
transactionCount += 1; transactionCount += 1;
} }
} }
@ -195,7 +195,7 @@ export class PortfolioService {
) )
}; };
delete result.Order; delete result.activities;
return result; return result;
}); });

View File

@ -1,6 +1,10 @@
import { DataService } from '@ghostfolio/client/services/data.service'; import { DataService } from '@ghostfolio/client/services/data.service';
import { UserService } from '@ghostfolio/client/services/user/user.service'; import { UserService } from '@ghostfolio/client/services/user/user.service';
import { Benchmark, User } from '@ghostfolio/common/interfaces'; import {
AssetProfileIdentifier,
Benchmark,
User
} from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { GfBenchmarkComponent } from '@ghostfolio/ui/benchmark'; import { GfBenchmarkComponent } from '@ghostfolio/ui/benchmark';
import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator';
@ -41,6 +45,7 @@ import { CreateWatchlistItemDialogParams } from './create-watchlist-item-dialog/
export class HomeWatchlistComponent implements OnDestroy, OnInit { export class HomeWatchlistComponent implements OnDestroy, OnInit {
public deviceType: string; public deviceType: string;
public hasPermissionToCreateWatchlistItem: boolean; public hasPermissionToCreateWatchlistItem: boolean;
public hasPermissionToDeleteWatchlistItem: boolean;
public user: User; public user: User;
public watchlist: Benchmark[]; public watchlist: Benchmark[];
@ -75,6 +80,10 @@ export class HomeWatchlistComponent implements OnDestroy, OnInit {
this.user.permissions, this.user.permissions,
permissions.createWatchlistItem permissions.createWatchlistItem
); );
this.hasPermissionToDeleteWatchlistItem = hasPermission(
this.user.permissions,
permissions.deleteWatchlistItem
);
this.changeDetectorRef.markForCheck(); this.changeDetectorRef.markForCheck();
} }
@ -85,6 +94,20 @@ export class HomeWatchlistComponent implements OnDestroy, OnInit {
this.loadWatchlistData(); this.loadWatchlistData();
} }
public onWatchlistItemDeleted({
dataSource,
symbol
}: AssetProfileIdentifier) {
this.dataService
.deleteWatchlistItem({ dataSource, symbol })
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe({
next: () => {
return this.loadWatchlistData();
}
});
}
public ngOnDestroy() { public ngOnDestroy() {
this.unsubscribeSubject.next(); this.unsubscribeSubject.next();
this.unsubscribeSubject.complete(); this.unsubscribeSubject.complete();

View File

@ -12,8 +12,10 @@
<gf-benchmark <gf-benchmark
[benchmarks]="watchlist" [benchmarks]="watchlist"
[deviceType]="deviceType" [deviceType]="deviceType"
[hasPermissionToDeleteItem]="hasPermissionToDeleteWatchlistItem"
[locale]="user?.settings?.locale || undefined" [locale]="user?.settings?.locale || undefined"
[user]="user" [user]="user"
(itemDeleted)="onWatchlistItemDeleted($event)"
/> />
</div> </div>
</div> </div>

View File

@ -238,7 +238,7 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
.get('dataSource') .get('dataSource')
.removeValidators(Validators.required); .removeValidators(Validators.required);
this.activityForm.get('dataSource').updateValueAndValidity(); this.activityForm.get('dataSource').updateValueAndValidity();
this.activityForm.get('fee').reset(); this.activityForm.get('fee').setValue(0);
this.activityForm.get('name').setValidators(Validators.required); this.activityForm.get('name').setValidators(Validators.required);
this.activityForm.get('name').updateValueAndValidity(); this.activityForm.get('name').updateValueAndValidity();
this.activityForm.get('quantity').setValue(1); this.activityForm.get('quantity').setValue(1);
@ -248,11 +248,7 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
this.activityForm.get('searchSymbol').updateValueAndValidity(); this.activityForm.get('searchSymbol').updateValueAndValidity();
this.activityForm.get('updateAccountBalance').disable(); this.activityForm.get('updateAccountBalance').disable();
this.activityForm.get('updateAccountBalance').setValue(false); this.activityForm.get('updateAccountBalance').setValue(false);
} else if ( } else if (['FEE', 'INTEREST', 'LIABILITY'].includes(type)) {
type === 'FEE' ||
type === 'INTEREST' ||
type === 'LIABILITY'
) {
this.activityForm this.activityForm
.get('accountId') .get('accountId')
.removeValidators(Validators.required); .removeValidators(Validators.required);
@ -271,12 +267,8 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
.removeValidators(Validators.required); .removeValidators(Validators.required);
this.activityForm.get('dataSource').updateValueAndValidity(); this.activityForm.get('dataSource').updateValueAndValidity();
if ( if (['INTEREST', 'LIABILITY'].includes(type)) {
(type === 'FEE' && this.activityForm.get('fee').value === 0) || this.activityForm.get('fee').setValue(0);
type === 'INTEREST' ||
type === 'LIABILITY'
) {
this.activityForm.get('fee').reset();
} }
this.activityForm.get('name').setValidators(Validators.required); this.activityForm.get('name').setValidators(Validators.required);
@ -284,7 +276,7 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
if (type === 'FEE') { if (type === 'FEE') {
this.activityForm.get('quantity').setValue(0); this.activityForm.get('quantity').setValue(0);
} else if (type === 'INTEREST' || type === 'LIABILITY') { } else if (['INTEREST', 'LIABILITY'].includes(type)) {
this.activityForm.get('quantity').setValue(1); this.activityForm.get('quantity').setValue(1);
} }

View File

@ -327,6 +327,10 @@ export class DataService {
return this.http.delete<any>(`/api/v1/user/${aId}`); return this.http.delete<any>(`/api/v1/user/${aId}`);
} }
public deleteWatchlistItem({ dataSource, symbol }: AssetProfileIdentifier) {
return this.http.delete<any>(`/api/v1/watchlist/${dataSource}/${symbol}`);
}
public fetchAccesses() { public fetchAccesses() {
return this.http.get<Access[]>('/api/v1/access'); return this.http.get<Access[]>('/api/v1/access');
} }

View File

@ -1237,6 +1237,10 @@
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context>
<context context-type="linenumber">457</context> <context context-type="linenumber">457</context>
</context-group> </context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit> </trans-unit>
<trans-unit id="8280212421112607879" datatype="html"> <trans-unit id="8280212421112607879" datatype="html">
<source>Do you really want to delete this account?</source> <source>Do you really want to delete this account?</source>
@ -4959,7 +4963,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">141</context> <context context-type="linenumber">174</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context>
@ -7961,6 +7965,14 @@
<context context-type="linenumber">29</context> <context context-type="linenumber">29</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="627795342008207050" datatype="html">
<source>Do you really want to delete this item?</source>
<target state="new">Do you really want to delete this item?</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.ts</context>
<context context-type="linenumber">122</context>
</context-group>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -300,6 +300,10 @@
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context>
<context context-type="linenumber">457</context> <context context-type="linenumber">457</context>
</context-group> </context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit> </trans-unit>
<trans-unit id="8280212421112607879" datatype="html"> <trans-unit id="8280212421112607879" datatype="html">
<source>Do you really want to delete this account?</source> <source>Do you really want to delete this account?</source>
@ -4686,7 +4690,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">141</context> <context context-type="linenumber">174</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context>
@ -7961,6 +7965,14 @@
<context context-type="linenumber">29</context> <context context-type="linenumber">29</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="627795342008207050" datatype="html">
<source>Do you really want to delete this item?</source>
<target state="translated">Möchtest du diesen Eintrag wirklich löschen?</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.ts</context>
<context context-type="linenumber">122</context>
</context-group>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -301,6 +301,10 @@
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context>
<context context-type="linenumber">457</context> <context context-type="linenumber">457</context>
</context-group> </context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit> </trans-unit>
<trans-unit id="8280212421112607879" datatype="html"> <trans-unit id="8280212421112607879" datatype="html">
<source>Do you really want to delete this account?</source> <source>Do you really want to delete this account?</source>
@ -4663,7 +4667,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">141</context> <context context-type="linenumber">174</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context>
@ -7962,6 +7966,14 @@
<context context-type="linenumber">29</context> <context context-type="linenumber">29</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="627795342008207050" datatype="html">
<source>Do you really want to delete this item?</source>
<target state="new">Do you really want to delete this item?</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.ts</context>
<context context-type="linenumber">122</context>
</context-group>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -356,6 +356,10 @@
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context>
<context context-type="linenumber">457</context> <context context-type="linenumber">457</context>
</context-group> </context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit> </trans-unit>
<trans-unit id="8280212421112607879" datatype="html"> <trans-unit id="8280212421112607879" datatype="html">
<source>Do you really want to delete this account?</source> <source>Do you really want to delete this account?</source>
@ -4662,7 +4666,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">141</context> <context context-type="linenumber">174</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context>
@ -7961,6 +7965,14 @@
<context context-type="linenumber">29</context> <context context-type="linenumber">29</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="627795342008207050" datatype="html">
<source>Do you really want to delete this item?</source>
<target state="new">Do you really want to delete this item?</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.ts</context>
<context context-type="linenumber">122</context>
</context-group>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -301,6 +301,10 @@
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context>
<context context-type="linenumber">457</context> <context context-type="linenumber">457</context>
</context-group> </context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit> </trans-unit>
<trans-unit id="8280212421112607879" datatype="html"> <trans-unit id="8280212421112607879" datatype="html">
<source>Do you really want to delete this account?</source> <source>Do you really want to delete this account?</source>
@ -4663,7 +4667,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">141</context> <context context-type="linenumber">174</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context>
@ -7962,6 +7966,14 @@
<context context-type="linenumber">29</context> <context context-type="linenumber">29</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="627795342008207050" datatype="html">
<source>Do you really want to delete this item?</source>
<target state="new">Do you really want to delete this item?</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.ts</context>
<context context-type="linenumber">122</context>
</context-group>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -300,6 +300,10 @@
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context>
<context context-type="linenumber">457</context> <context context-type="linenumber">457</context>
</context-group> </context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit> </trans-unit>
<trans-unit id="8280212421112607879" datatype="html"> <trans-unit id="8280212421112607879" datatype="html">
<source>Do you really want to delete this account?</source> <source>Do you really want to delete this account?</source>
@ -4662,7 +4666,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">141</context> <context context-type="linenumber">174</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context>
@ -7961,6 +7965,14 @@
<context context-type="linenumber">29</context> <context context-type="linenumber">29</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="627795342008207050" datatype="html">
<source>Do you really want to delete this item?</source>
<target state="new">Do you really want to delete this item?</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.ts</context>
<context context-type="linenumber">122</context>
</context-group>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -1165,6 +1165,10 @@
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context>
<context context-type="linenumber">457</context> <context context-type="linenumber">457</context>
</context-group> </context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit> </trans-unit>
<trans-unit id="8280212421112607879" datatype="html"> <trans-unit id="8280212421112607879" datatype="html">
<source>Do you really want to delete this account?</source> <source>Do you really want to delete this account?</source>
@ -4571,7 +4575,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">141</context> <context context-type="linenumber">174</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context>
@ -7961,6 +7965,14 @@
<context context-type="linenumber">29</context> <context context-type="linenumber">29</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="627795342008207050" datatype="html">
<source>Do you really want to delete this item?</source>
<target state="new">Do you really want to delete this item?</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.ts</context>
<context context-type="linenumber">122</context>
</context-group>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -356,6 +356,10 @@
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context>
<context context-type="linenumber">457</context> <context context-type="linenumber">457</context>
</context-group> </context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit> </trans-unit>
<trans-unit id="8280212421112607879" datatype="html"> <trans-unit id="8280212421112607879" datatype="html">
<source>Do you really want to delete this account?</source> <source>Do you really want to delete this account?</source>
@ -4662,7 +4666,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">141</context> <context context-type="linenumber">174</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context>
@ -7961,6 +7965,14 @@
<context context-type="linenumber">29</context> <context context-type="linenumber">29</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="627795342008207050" datatype="html">
<source>Do you really want to delete this item?</source>
<target state="new">Do you really want to delete this item?</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.ts</context>
<context context-type="linenumber">122</context>
</context-group>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -1125,6 +1125,10 @@
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context>
<context context-type="linenumber">457</context> <context context-type="linenumber">457</context>
</context-group> </context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit> </trans-unit>
<trans-unit id="8280212421112607879" datatype="html"> <trans-unit id="8280212421112607879" datatype="html">
<source>Do you really want to delete this account?</source> <source>Do you really want to delete this account?</source>
@ -4059,7 +4063,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">141</context> <context context-type="linenumber">174</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context>
@ -7961,6 +7965,14 @@
<context context-type="linenumber">29</context> <context context-type="linenumber">29</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="627795342008207050" datatype="html">
<source>Do you really want to delete this item?</source>
<target state="new">Do you really want to delete this item?</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.ts</context>
<context context-type="linenumber">122</context>
</context-group>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -1253,6 +1253,10 @@
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context>
<context context-type="linenumber">457</context> <context context-type="linenumber">457</context>
</context-group> </context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit> </trans-unit>
<trans-unit id="8280212421112607879" datatype="html"> <trans-unit id="8280212421112607879" datatype="html">
<source>Do you really want to delete this account?</source> <source>Do you really want to delete this account?</source>
@ -5211,7 +5215,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">141</context> <context context-type="linenumber">174</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context>
@ -7961,6 +7965,14 @@
<context context-type="linenumber">29</context> <context context-type="linenumber">29</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="627795342008207050" datatype="html">
<source>Do you really want to delete this item?</source>
<target state="new">Do you really want to delete this item?</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.ts</context>
<context context-type="linenumber">122</context>
</context-group>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -1132,6 +1132,10 @@
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context>
<context context-type="linenumber">457</context> <context context-type="linenumber">457</context>
</context-group> </context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit> </trans-unit>
<trans-unit id="8280212421112607879" datatype="html"> <trans-unit id="8280212421112607879" datatype="html">
<source>Do you really want to delete this account?</source> <source>Do you really want to delete this account?</source>
@ -4225,7 +4229,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">141</context> <context context-type="linenumber">174</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context>
@ -7199,6 +7203,13 @@
<context context-type="linenumber">29</context> <context context-type="linenumber">29</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="627795342008207050" datatype="html">
<source>Do you really want to delete this item?</source>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.ts</context>
<context context-type="linenumber">122</context>
</context-group>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -1174,6 +1174,10 @@
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.html</context>
<context context-type="linenumber">457</context> <context context-type="linenumber">457</context>
</context-group> </context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">142</context>
</context-group>
</trans-unit> </trans-unit>
<trans-unit id="8280212421112607879" datatype="html"> <trans-unit id="8280212421112607879" datatype="html">
<source>Do you really want to delete this account?</source> <source>Do you really want to delete this account?</source>
@ -4580,7 +4584,7 @@
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.html</context>
<context context-type="linenumber">141</context> <context context-type="linenumber">174</context>
</context-group> </context-group>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/top-holdings/top-holdings.component.html</context>
@ -7962,6 +7966,14 @@
<context context-type="linenumber">29</context> <context context-type="linenumber">29</context>
</context-group> </context-group>
</trans-unit> </trans-unit>
<trans-unit id="627795342008207050" datatype="html">
<source>Do you really want to delete this item?</source>
<target state="new">Do you really want to delete this item?</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/benchmark/benchmark.component.ts</context>
<context context-type="linenumber">122</context>
</context-group>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -113,6 +113,39 @@
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="actions" stickyEnd>
<th *matHeaderCellDef class="px-1 text-center" mat-header-cell></th>
<td *matCellDef="let element" class="px-1 text-center" mat-cell>
@if (hasPermissionToDeleteItem) {
<button
class="mx-1 no-min-width px-2"
mat-button
[matMenuTriggerFor]="benchmarkMenu"
(click)="$event.stopPropagation()"
>
<ion-icon name="ellipsis-horizontal" />
</button>
}
<mat-menu #benchmarkMenu="matMenu" xPosition="before">
<button
mat-menu-item
[disabled]="!hasPermissionToDeleteItem"
(click)="
onDeleteItem({
dataSource: element.dataSource,
symbol: element.symbol
})
"
>
<span class="align-items-center d-flex">
<ion-icon class="mr-2" name="trash-outline" />
<span i18n>Delete</span>
</span>
</button>
</mat-menu>
</td>
</ng-container>
<tr *matHeaderRowDef="displayedColumns" mat-header-row></tr> <tr *matHeaderRowDef="displayedColumns" mat-header-row></tr>
<tr <tr
*matRowDef="let row; columns: displayedColumns" *matRowDef="let row; columns: displayedColumns"

View File

@ -1,3 +1,5 @@
import { ConfirmationDialogType } from '@ghostfolio/client/core/notification/confirmation-dialog/confirmation-dialog.type';
import { NotificationService } from '@ghostfolio/client/core/notification/notification.service';
import { getLocale, resolveMarketCondition } from '@ghostfolio/common/helper'; import { getLocale, resolveMarketCondition } from '@ghostfolio/common/helper';
import { import {
AssetProfileIdentifier, AssetProfileIdentifier,
@ -13,11 +15,15 @@ import {
CUSTOM_ELEMENTS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA,
ChangeDetectionStrategy, ChangeDetectionStrategy,
Component, Component,
EventEmitter,
Input, Input,
OnChanges, OnChanges,
OnDestroy OnDestroy,
Output
} from '@angular/core'; } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { MatMenuModule } from '@angular/material/menu';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { ActivatedRoute, Router, RouterModule } from '@angular/router'; import { ActivatedRoute, Router, RouterModule } from '@angular/router';
import { isNumber } from 'lodash'; import { isNumber } from 'lodash';
@ -33,6 +39,8 @@ import { BenchmarkDetailDialogParams } from './benchmark-detail-dialog/interface
CommonModule, CommonModule,
GfTrendIndicatorComponent, GfTrendIndicatorComponent,
GfValueComponent, GfValueComponent,
MatButtonModule,
MatMenuModule,
MatTableModule, MatTableModule,
NgxSkeletonLoaderModule, NgxSkeletonLoaderModule,
RouterModule RouterModule
@ -45,10 +53,19 @@ import { BenchmarkDetailDialogParams } from './benchmark-detail-dialog/interface
export class GfBenchmarkComponent implements OnChanges, OnDestroy { export class GfBenchmarkComponent implements OnChanges, OnDestroy {
@Input() benchmarks: Benchmark[]; @Input() benchmarks: Benchmark[];
@Input() deviceType: string; @Input() deviceType: string;
@Input() hasPermissionToDeleteItem: boolean;
@Input() locale = getLocale(); @Input() locale = getLocale();
@Input() user: User; @Input() user: User;
public displayedColumns = ['name', 'date', 'change', 'marketCondition']; @Output() itemDeleted = new EventEmitter<AssetProfileIdentifier>();
public displayedColumns = [
'name',
'date',
'change',
'marketCondition',
'actions'
];
public isLoading = true; public isLoading = true;
public isNumber = isNumber; public isNumber = isNumber;
public resolveMarketCondition = resolveMarketCondition; public resolveMarketCondition = resolveMarketCondition;
@ -58,6 +75,7 @@ export class GfBenchmarkComponent implements OnChanges, OnDestroy {
public constructor( public constructor(
private dialog: MatDialog, private dialog: MatDialog,
private notificationService: NotificationService,
private route: ActivatedRoute, private route: ActivatedRoute,
private router: Router private router: Router
) { ) {
@ -89,11 +107,22 @@ export class GfBenchmarkComponent implements OnChanges, OnDestroy {
'trend200d', 'trend200d',
'date', 'date',
'change', 'change',
'marketCondition' 'marketCondition',
'actions'
]; ];
} }
} }
public onDeleteItem({ dataSource, symbol }: AssetProfileIdentifier) {
this.notificationService.confirm({
confirmFn: () => {
this.itemDeleted.emit({ dataSource, symbol });
},
confirmType: ConfirmationDialogType.Warn,
title: $localize`Do you really want to delete this item?`
});
}
public onOpenBenchmarkDialog({ dataSource, symbol }: AssetProfileIdentifier) { public onOpenBenchmarkDialog({ dataSource, symbol }: AssetProfileIdentifier) {
this.router.navigate([], { this.router.navigate([], {
queryParams: { dataSource, symbol, benchmarkDetailDialog: true } queryParams: { dataSource, symbol, benchmarkDetailDialog: true }

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "ghostfolio", "name": "ghostfolio",
"version": "2.157.1", "version": "2.158.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "ghostfolio", "name": "ghostfolio",
"version": "2.157.1", "version": "2.158.0",
"hasInstallScript": true, "hasInstallScript": true,
"license": "AGPL-3.0", "license": "AGPL-3.0",
"dependencies": { "dependencies": {

View File

@ -1,6 +1,6 @@
{ {
"name": "ghostfolio", "name": "ghostfolio",
"version": "2.157.1", "version": "2.158.0",
"homepage": "https://ghostfol.io", "homepage": "https://ghostfol.io",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"repository": "https://github.com/ghostfolio/ghostfolio", "repository": "https://github.com/ghostfolio/ghostfolio",

View File

@ -26,6 +26,7 @@ model Access {
} }
model Account { model Account {
activities Order[]
balance Float @default(0) balance Float @default(0)
balances AccountBalance[] balances AccountBalance[]
comment String? comment String?
@ -39,7 +40,6 @@ model Account {
userId String userId String
Platform Platform? @relation(fields: [platformId], references: [id]) Platform Platform? @relation(fields: [platformId], references: [id])
User User @relation(fields: [userId], onDelete: Cascade, references: [id]) User User @relation(fields: [userId], onDelete: Cascade, references: [id])
Order Order[]
@@id([id, userId]) @@id([id, userId])
@@index([currency]) @@index([currency])