Browse Source

Feature/support delete activities with filtering (#3394)

* Support delete activities with filtering

* Update changelog

---------

Co-authored-by: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
pull/3355/head
Gerard Du Pre 5 months ago
committed by GitHub
parent
commit
8319b216bb
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 16
      apps/api/src/app/order/order.controller.ts
  3. 30
      apps/api/src/app/order/order.service.ts
  4. 27
      apps/client/src/app/pages/portfolio/activities/activities-page.component.ts
  5. 2
      apps/client/src/app/pages/portfolio/activities/activities-page.html
  6. 10
      apps/client/src/app/services/data.service.ts
  7. 4
      libs/ui/src/lib/activities-table/activities-table.component.html
  8. 16
      libs/ui/src/lib/activities-table/activities-table.component.ts

2
CHANGELOG.md

@ -13,7 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Disabled the button to delete all activities on the portfolio activities page if there are active filters
- Improved the delete all activities functionality on the portfolio activities page to work with the filters of the assistant
- Upgraded `Nx` from version `18.3.3` to `19.0.2`
### Fixed

16
apps/api/src/app/order/order.controller.ts

@ -11,7 +11,7 @@ import {
DATA_GATHERING_QUEUE_PRIORITY_HIGH,
HEADER_KEY_IMPERSONATION
} from '@ghostfolio/common/config';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { permissions } from '@ghostfolio/common/permissions';
import type { DateRange, RequestWithUser } from '@ghostfolio/common/types';
import {
@ -53,8 +53,20 @@ export class OrderController {
@Delete()
@HasPermission(permissions.deleteOrder)
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
public async deleteOrders(): Promise<number> {
public async deleteOrders(
@Query('accounts') filterByAccounts?: string,
@Query('assetClasses') filterByAssetClasses?: string,
@Query('tags') filterByTags?: string
): Promise<number> {
const filters = this.apiService.buildFiltersFromQueryParams({
filterByAccounts,
filterByAssetClasses,
filterByTags
});
return this.orderService.deleteOrders({
filters,
userCurrency: this.request.user.Settings.settings.baseCurrency,
userId: this.request.user.id
});
}

30
apps/api/src/app/order/order.service.ts

@ -194,16 +194,36 @@ export class OrderService {
return order;
}
public async deleteOrders(where: Prisma.OrderWhereInput): Promise<number> {
public async deleteOrders({
filters,
userCurrency,
userId
}: {
filters?: Filter[];
userCurrency: string;
userId: string;
}): Promise<number> {
const { activities } = await this.getOrders({
filters,
userId,
userCurrency,
includeDrafts: true,
withExcludedAccounts: true
});
const { count } = await this.prismaService.order.deleteMany({
where
where: {
id: {
in: activities.map(({ id }) => {
return id;
})
}
}
});
this.eventEmitter.emit(
PortfolioChangedEvent.getName(),
new PortfolioChangedEvent({
userId: <string>where.userId
})
new PortfolioChangedEvent({ userId })
);
return count;

27
apps/client/src/app/pages/portfolio/activities/activities-page.component.ts

@ -142,33 +142,25 @@ export class ActivitiesPageComponent implements OnDestroy, OnInit {
this.openCreateActivityDialog(aActivity);
}
public onDeleteActivity(aId: string) {
public onDeleteActivities() {
this.dataService
.deleteActivity(aId)
.deleteActivities({
filters: this.userService.getFilters()
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe({
next: () => {
.subscribe(() => {
this.fetchActivities();
}
});
}
public onDeleteAllActivities() {
const confirmation = confirm(
$localize`Do you really want to delete all your activities?`
);
if (confirmation) {
public onDeleteActivity(aId: string) {
this.dataService
.deleteAllActivities()
.deleteActivity(aId)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe({
next: () => {
.subscribe(() => {
this.fetchActivities();
}
});
}
}
public onExport(activityIds?: string[]) {
let fetchExportParams: any = { activityIds };
@ -348,7 +340,6 @@ export class ActivitiesPageComponent implements OnDestroy, OnInit {
hasPermission(this.user.permissions, permissions.createOrder);
this.hasPermissionToDeleteActivity =
!this.hasImpersonationId &&
hasPermission(this.user.permissions, permissions.deleteOrder) &&
!this.userService.hasFilters();
hasPermission(this.user.permissions, permissions.deleteOrder);
}
}

2
apps/client/src/app/pages/portfolio/activities/activities-page.html

@ -20,10 +20,10 @@
[sortColumn]="sortColumn"
[sortDirection]="sortDirection"
[totalItems]="totalItems"
(activitiesDeleted)="onDeleteActivities()"
(activityDeleted)="onDeleteActivity($event)"
(activityToClone)="onCloneActivity($event)"
(activityToUpdate)="onUpdateActivity($event)"
(deleteAllActivities)="onDeleteAllActivities()"
(export)="onExport()"
(exportDrafts)="onExportDrafts($event)"
(import)="onImport()"

10
apps/client/src/app/services/data.service.ts

@ -256,12 +256,14 @@ export class DataService {
return this.http.delete<any>(`/api/v1/account-balance/${aId}`);
}
public deleteActivity(aId: string) {
return this.http.delete<any>(`/api/v1/order/${aId}`);
public deleteActivities({ filters }) {
let params = this.buildFiltersAsQueryParams({ filters });
return this.http.delete<any>(`/api/v1/order`, { params });
}
public deleteAllActivities() {
return this.http.delete<any>(`/api/v1/order`);
public deleteActivity(aId: string) {
return this.http.delete<any>(`/api/v1/order/${aId}`);
}
public deleteBenchmark({ dataSource, symbol }: UniqueAsset) {

4
libs/ui/src/lib/activities-table/activities-table.component.html

@ -59,11 +59,11 @@
class="align-items-center d-flex"
mat-menu-item
[disabled]="!hasPermissionToDeleteActivity"
(click)="onDeleteAllActivities()"
(click)="onDeleteActivities()"
>
<span class="align-items-center d-flex">
<ion-icon class="mr-2" name="trash-outline" />
<span i18n>Delete all Activities</span>
<span i18n>Delete Activities</span>
</span>
</button>
</mat-menu>

16
libs/ui/src/lib/activities-table/activities-table.component.ts

@ -92,10 +92,10 @@ export class GfActivitiesTableComponent
@Input() sortDisabled = false;
@Input() totalItems = Number.MAX_SAFE_INTEGER;
@Output() activitiesDeleted = new EventEmitter<void>();
@Output() activityDeleted = new EventEmitter<string>();
@Output() activityToClone = new EventEmitter<OrderWithAccount>();
@Output() activityToUpdate = new EventEmitter<OrderWithAccount>();
@Output() deleteAllActivities = new EventEmitter<void>();
@Output() export = new EventEmitter<void>();
@Output() exportDrafts = new EventEmitter<string[]>();
@Output() import = new EventEmitter<void>();
@ -211,6 +211,16 @@ export class GfActivitiesTableComponent
this.activityToClone.emit(aActivity);
}
public onDeleteActivities() {
const confirmation = confirm(
$localize`Do you really want to delete these activities?`
);
if (confirmation) {
this.activitiesDeleted.emit();
}
}
public onDeleteActivity(aId: string) {
const confirmation = confirm(
$localize`Do you really want to delete this activity?`
@ -241,10 +251,6 @@ export class GfActivitiesTableComponent
);
}
public onDeleteAllActivities() {
this.deleteAllActivities.emit();
}
public onImport() {
this.import.emit();
}

Loading…
Cancel
Save