mirror of https://github.com/ghostfolio/ghostfolio
Browse Source
* Introduce lazy-loaded activities table * Add icon column * Emit paginator event * Add pagination logic * Integrate total items * Update changelogpull/2733/head
committed by
GitHub
13 changed files with 962 additions and 67 deletions
@ -0,0 +1,499 @@ |
|||
<div *ngIf="hasPermissionToCreateActivity" class="d-flex justify-content-end"> |
|||
<button |
|||
class="align-items-center d-flex" |
|||
mat-stroked-button |
|||
(click)="onImport()" |
|||
> |
|||
<ion-icon class="mr-2" name="cloud-upload-outline"></ion-icon> |
|||
<ng-container i18n>Import Activities</ng-container>... |
|||
</button> |
|||
<button |
|||
*ngIf="hasPermissionToExportActivities" |
|||
class="mx-1 no-min-width px-2" |
|||
mat-stroked-button |
|||
[matMenuTriggerFor]="activitiesMenu" |
|||
(click)="$event.stopPropagation()" |
|||
> |
|||
<ion-icon name="ellipsis-vertical"></ion-icon> |
|||
</button> |
|||
<mat-menu #activitiesMenu="matMenu" xPosition="before"> |
|||
<button |
|||
mat-menu-item |
|||
[disabled]="dataSource?.data.length === 0" |
|||
(click)="onImportDividends()" |
|||
> |
|||
<span class="align-items-center d-flex"> |
|||
<ion-icon class="mr-2" name="color-wand-outline"></ion-icon> |
|||
<ng-container i18n>Import Dividends</ng-container>... |
|||
</span> |
|||
</button> |
|||
<button |
|||
*ngIf="hasPermissionToExportActivities" |
|||
class="align-items-center d-flex" |
|||
mat-menu-item |
|||
[disabled]="dataSource?.data.length === 0" |
|||
(click)="onExport()" |
|||
> |
|||
<span class="align-items-center d-flex"> |
|||
<ion-icon class="mr-2" name="cloud-download-outline"></ion-icon> |
|||
<span i18n>Export Activities</span> |
|||
</span> |
|||
</button> |
|||
<button |
|||
*ngIf="hasPermissionToExportActivities" |
|||
class="align-items-center d-flex" |
|||
mat-menu-item |
|||
[disabled]="!hasDrafts" |
|||
(click)="onExportDrafts()" |
|||
> |
|||
<span class="align-items-center d-flex"> |
|||
<ion-icon class="mr-2" name="calendar-clear-outline"></ion-icon> |
|||
<span i18n>Export Drafts as ICS</span> |
|||
</span> |
|||
</button> |
|||
<button |
|||
class="align-items-center d-flex" |
|||
mat-menu-item |
|||
(click)="onDeleteAllActivities()" |
|||
> |
|||
<span class="align-items-center d-flex"> |
|||
<ion-icon class="mr-2" name="trash-outline"></ion-icon> |
|||
<span i18n>Delete all Activities</span> |
|||
</span> |
|||
</button> |
|||
</mat-menu> |
|||
</div> |
|||
|
|||
<div class="activities"> |
|||
<table class="gf-table w-100" mat-table [dataSource]="dataSource"> |
|||
<ng-container matColumnDef="select"> |
|||
<th *matHeaderCellDef class="px-1" mat-header-cell> |
|||
<mat-checkbox |
|||
color="primary" |
|||
[checked]=" |
|||
areAllRowsSelected() && !hasErrors && selectedRows.hasValue() |
|||
" |
|||
[disabled]="hasErrors" |
|||
[indeterminate]="selectedRows.hasValue() && !areAllRowsSelected()" |
|||
(change)="$event ? toggleAllRows() : null" |
|||
></mat-checkbox> |
|||
</th> |
|||
<td *matCellDef="let element" class="px-1" mat-cell> |
|||
<mat-checkbox |
|||
color="primary" |
|||
[checked]="element.error ? false : selectedRows.isSelected(element)" |
|||
[disabled]="element.error" |
|||
(change)="$event ? selectedRows.toggle(element) : null" |
|||
(click)="$event.stopPropagation()" |
|||
></mat-checkbox> |
|||
</td> |
|||
</ng-container> |
|||
|
|||
<ng-container matColumnDef="importStatus"> |
|||
<th *matHeaderCellDef class="px-1" mat-header-cell> |
|||
<ng-container i18n></ng-container> |
|||
</th> |
|||
<td *matCellDef="let element" class="px-1" mat-cell> |
|||
<div |
|||
*ngIf="element.error" |
|||
class="d-flex" |
|||
matTooltipPosition="above" |
|||
[matTooltip]="element.error.message" |
|||
> |
|||
<ion-icon class="text-danger" name="alert-circle-outline"></ion-icon> |
|||
</div> |
|||
</td> |
|||
</ng-container> |
|||
|
|||
<ng-container matColumnDef="icon"> |
|||
<th *matHeaderCellDef class="px-1" mat-header-cell></th> |
|||
<td *matCellDef="let element" class="px-1 text-center" mat-cell> |
|||
<gf-symbol-icon |
|||
[dataSource]="element.SymbolProfile?.dataSource" |
|||
[symbol]="element.SymbolProfile?.symbol" |
|||
[tooltip]="element.SymbolProfile?.name" |
|||
></gf-symbol-icon> |
|||
<div>{{ element.dataSource }}</div> |
|||
</td> |
|||
</ng-container> |
|||
|
|||
<ng-container matColumnDef="nameWithSymbol"> |
|||
<th |
|||
*matHeaderCellDef |
|||
class="px-1" |
|||
mat-header-cell |
|||
mat-sort-header="SymbolProfile.symbol" |
|||
> |
|||
<ng-container i18n>Name</ng-container> |
|||
</th> |
|||
<td *matCellDef="let element" class="line-height-1 px-1" mat-cell> |
|||
<div class="d-flex align-items-center"> |
|||
<div> |
|||
<span class="text-truncate">{{ element.SymbolProfile?.name }}</span> |
|||
<span |
|||
*ngIf="element.isDraft" |
|||
class="badge badge-secondary ml-1" |
|||
i18n |
|||
>Draft</span |
|||
> |
|||
</div> |
|||
</div> |
|||
<div *ngIf="!isUUID(element.SymbolProfile?.symbol)"> |
|||
<small class="text-muted">{{ |
|||
element.SymbolProfile?.symbol | gfSymbol |
|||
}}</small> |
|||
</div> |
|||
</td> |
|||
</ng-container> |
|||
|
|||
<ng-container matColumnDef="type"> |
|||
<th *matHeaderCellDef class="px-1" mat-header-cell mat-sort-header> |
|||
<ng-container i18n>Type</ng-container> |
|||
</th> |
|||
<td *matCellDef="let element" class="px-1" mat-cell> |
|||
<gf-activity-type [activityType]="element.type"></gf-activity-type> |
|||
</td> |
|||
</ng-container> |
|||
|
|||
<ng-container matColumnDef="date"> |
|||
<th *matHeaderCellDef class="px-1" mat-header-cell mat-sort-header> |
|||
<ng-container i18n>Date</ng-container> |
|||
</th> |
|||
<td *matCellDef="let element" class="px-1" mat-cell> |
|||
<div class="d-flex"> |
|||
{{ element.date | date: defaultDateFormat }} |
|||
</div> |
|||
</td> |
|||
</ng-container> |
|||
|
|||
<ng-container matColumnDef="quantity"> |
|||
<th |
|||
*matHeaderCellDef |
|||
class="d-none d-lg-table-cell justify-content-end px-1" |
|||
mat-header-cell |
|||
mat-sort-header |
|||
> |
|||
<ng-container i18n>Quantity</ng-container> |
|||
</th> |
|||
<td |
|||
*matCellDef="let element" |
|||
class="d-none d-lg-table-cell px-1" |
|||
mat-cell |
|||
> |
|||
<div class="d-flex justify-content-end"> |
|||
<gf-value |
|||
[isCurrency]="true" |
|||
[locale]="locale" |
|||
[value]="isLoading ? undefined : element.quantity" |
|||
></gf-value> |
|||
</div> |
|||
</td> |
|||
</ng-container> |
|||
|
|||
<ng-container matColumnDef="unitPrice"> |
|||
<th |
|||
*matHeaderCellDef |
|||
class="d-none d-lg-table-cell justify-content-end px-1" |
|||
mat-header-cell |
|||
mat-sort-header |
|||
> |
|||
<ng-container i18n>Unit Price</ng-container> |
|||
</th> |
|||
<td |
|||
*matCellDef="let element" |
|||
class="d-none d-lg-table-cell px-1" |
|||
mat-cell |
|||
> |
|||
<div class="d-flex justify-content-end"> |
|||
<gf-value |
|||
[isCurrency]="true" |
|||
[locale]="locale" |
|||
[value]="isLoading ? undefined : element.unitPrice" |
|||
></gf-value> |
|||
</div> |
|||
</td> |
|||
</ng-container> |
|||
|
|||
<ng-container matColumnDef="fee"> |
|||
<th |
|||
*matHeaderCellDef |
|||
class="d-none d-lg-table-cell justify-content-end px-1" |
|||
mat-header-cell |
|||
mat-sort-header |
|||
> |
|||
<ng-container i18n>Fee</ng-container> |
|||
</th> |
|||
<td |
|||
*matCellDef="let element" |
|||
class="d-none d-lg-table-cell px-1" |
|||
mat-cell |
|||
> |
|||
<div class="d-flex justify-content-end"> |
|||
<gf-value |
|||
[isCurrency]="true" |
|||
[locale]="locale" |
|||
[value]="isLoading ? undefined : element.fee" |
|||
></gf-value> |
|||
</div> |
|||
</td> |
|||
</ng-container> |
|||
|
|||
<ng-container matColumnDef="value"> |
|||
<th |
|||
*matHeaderCellDef |
|||
class="d-none d-lg-table-cell justify-content-end px-1" |
|||
mat-header-cell |
|||
mat-sort-header |
|||
> |
|||
<ng-container i18n>Value</ng-container> |
|||
</th> |
|||
<td |
|||
*matCellDef="let element" |
|||
class="d-none d-lg-table-cell px-1" |
|||
mat-cell |
|||
> |
|||
<div class="d-flex justify-content-end"> |
|||
<gf-value |
|||
[isCurrency]="true" |
|||
[locale]="locale" |
|||
[value]="isLoading ? undefined : element.value" |
|||
></gf-value> |
|||
</div> |
|||
</td> |
|||
</ng-container> |
|||
|
|||
<ng-container matColumnDef="currency"> |
|||
<th |
|||
*matHeaderCellDef |
|||
class="d-none d-lg-table-cell px-1" |
|||
mat-header-cell |
|||
mat-sort-header="SymbolProfile.currency" |
|||
> |
|||
<ng-container i18n>Currency</ng-container> |
|||
</th> |
|||
<td |
|||
*matCellDef="let element" |
|||
class="d-none d-lg-table-cell px-1" |
|||
mat-cell |
|||
> |
|||
{{ element.SymbolProfile?.currency }} |
|||
</td> |
|||
</ng-container> |
|||
|
|||
<ng-container matColumnDef="valueInBaseCurrency"> |
|||
<th |
|||
*matHeaderCellDef |
|||
class="d-lg-none d-xl-none justify-content-end px-1" |
|||
mat-header-cell |
|||
mat-sort-header |
|||
> |
|||
<ng-container i18n>Value</ng-container> |
|||
</th> |
|||
<td *matCellDef="let element" class="d-lg-none d-xl-none px-1" mat-cell> |
|||
<div class="d-flex justify-content-end"> |
|||
<gf-value |
|||
[isCurrency]="true" |
|||
[locale]="locale" |
|||
[value]="isLoading ? undefined : element.valueInBaseCurrency" |
|||
></gf-value> |
|||
</div> |
|||
</td> |
|||
</ng-container> |
|||
|
|||
<ng-container matColumnDef="account"> |
|||
<th |
|||
*matHeaderCellDef |
|||
class="px-1" |
|||
mat-header-cell |
|||
mat-sort-header="Account.name" |
|||
> |
|||
<span class="d-none d-lg-block" i18n>Account</span> |
|||
</th> |
|||
<td *matCellDef="let element" class="px-1" mat-cell> |
|||
<div class="d-flex"> |
|||
<gf-symbol-icon |
|||
*ngIf="element.Account?.Platform?.url" |
|||
class="mr-1" |
|||
[tooltip]="element.Account?.Platform?.name" |
|||
[url]="element.Account?.Platform?.url" |
|||
></gf-symbol-icon> |
|||
<span class="d-none d-lg-block">{{ element.Account?.name }}</span> |
|||
</div> |
|||
</td> |
|||
</ng-container> |
|||
|
|||
<ng-container matColumnDef="comment"> |
|||
<th |
|||
*matHeaderCellDef |
|||
class="d-none d-lg-table-cell px-1" |
|||
mat-header-cell |
|||
></th> |
|||
<td |
|||
*matCellDef="let element" |
|||
class="d-none d-lg-table-cell px-1" |
|||
mat-cell |
|||
> |
|||
<button |
|||
*ngIf="element.comment" |
|||
class="mx-1 no-min-width px-2" |
|||
mat-button |
|||
title="Note" |
|||
(click)="onOpenComment(element.comment); $event.stopPropagation()" |
|||
> |
|||
<ion-icon name="document-text-outline"></ion-icon> |
|||
</button> |
|||
</td> |
|||
</ng-container> |
|||
|
|||
<ng-container matColumnDef="actions" stickyEnd> |
|||
<th *matHeaderCellDef class="px-1 text-center" mat-header-cell> |
|||
<button |
|||
*ngIf=" |
|||
!hasPermissionToCreateActivity && hasPermissionToExportActivities |
|||
" |
|||
class="mx-1 no-min-width px-2" |
|||
mat-button |
|||
[matMenuTriggerFor]="activitiesMenu" |
|||
(click)="$event.stopPropagation()" |
|||
> |
|||
<ion-icon name="ellipsis-vertical"></ion-icon> |
|||
</button> |
|||
<mat-menu #activitiesMenu="matMenu" xPosition="before"> |
|||
<button |
|||
*ngIf="hasPermissionToCreateActivity" |
|||
class="align-items-center d-flex" |
|||
mat-menu-item |
|||
(click)="onImport()" |
|||
> |
|||
<span class="align-items-center d-flex"> |
|||
<ion-icon class="mr-2" name="cloud-upload-outline"></ion-icon> |
|||
<ng-container i18n>Import Activities</ng-container>... |
|||
</span> |
|||
</button> |
|||
<button |
|||
*ngIf="hasPermissionToCreateActivity" |
|||
mat-menu-item |
|||
[disabled]="dataSource?.data.length === 0" |
|||
(click)="onImportDividends()" |
|||
> |
|||
<span class="align-items-center d-flex"> |
|||
<ion-icon class="mr-2" name="color-wand-outline"></ion-icon> |
|||
<ng-container i18n>Import Dividends</ng-container>... |
|||
</span> |
|||
</button> |
|||
<button |
|||
*ngIf="hasPermissionToExportActivities" |
|||
class="align-items-center d-flex" |
|||
mat-menu-item |
|||
[disabled]="dataSource?.data.length === 0" |
|||
(click)="onExport()" |
|||
> |
|||
<span class="align-items-center d-flex"> |
|||
<ion-icon class="mr-2" name="cloud-download-outline"></ion-icon> |
|||
<span i18n>Export Activities</span> |
|||
</span> |
|||
</button> |
|||
<button |
|||
*ngIf="hasPermissionToExportActivities" |
|||
class="align-items-center d-flex" |
|||
mat-menu-item |
|||
[disabled]="!hasDrafts" |
|||
(click)="onExportDrafts()" |
|||
> |
|||
<span class="align-items-center d-flex"> |
|||
<ion-icon class="mr-2" name="calendar-clear-outline"></ion-icon> |
|||
<span i18n>Export Drafts as ICS</span> |
|||
</span> |
|||
</button> |
|||
</mat-menu> |
|||
</th> |
|||
<td *matCellDef="let element" class="px-1 text-center" mat-cell> |
|||
<button |
|||
*ngIf="showActions" |
|||
class="mx-1 no-min-width px-2" |
|||
mat-button |
|||
[matMenuTriggerFor]="activityMenu" |
|||
(click)="$event.stopPropagation()" |
|||
> |
|||
<ion-icon name="ellipsis-horizontal"></ion-icon> |
|||
</button> |
|||
<mat-menu #activityMenu="matMenu" xPosition="before"> |
|||
<button mat-menu-item (click)="onUpdateActivity(element)"> |
|||
<span class="align-items-center d-flex"> |
|||
<ion-icon class="mr-2" name="create-outline"></ion-icon> |
|||
<span i18n>Edit</span> |
|||
</span> |
|||
</button> |
|||
<button mat-menu-item (click)="onCloneActivity(element)"> |
|||
<span class="align-items-center d-flex"> |
|||
<ion-icon class="mr-2" name="copy-outline"></ion-icon> |
|||
<span i18n>Clone</span> |
|||
</span> |
|||
</button> |
|||
<button |
|||
mat-menu-item |
|||
[disabled]="!element.isDraft" |
|||
(click)="onExportDraft(element.id)" |
|||
> |
|||
<span class="align-items-center d-flex"> |
|||
<ion-icon class="mr-2" name="calendar-clear-outline"></ion-icon> |
|||
<span i18n>Export Draft as ICS</span> |
|||
</span> |
|||
</button> |
|||
<button mat-menu-item (click)="onDeleteActivity(element.id)"> |
|||
<span class="align-items-center d-flex"> |
|||
<ion-icon class="mr-2" name="trash-outline"></ion-icon> |
|||
<span i18n>Delete</span> |
|||
</span> |
|||
</button> |
|||
</mat-menu> |
|||
</td> |
|||
</ng-container> |
|||
|
|||
<tr *matHeaderRowDef="displayedColumns" mat-header-row></tr> |
|||
<tr |
|||
*matRowDef="let row; columns: displayedColumns" |
|||
mat-row |
|||
[ngClass]="{ |
|||
'cursor-pointer': |
|||
hasPermissionToOpenDetails && |
|||
!row.isDraft && |
|||
row.type !== 'FEE' && |
|||
row.type !== 'INTEREST' && |
|||
row.type !== 'ITEM' && |
|||
row.type !== 'LIABILITY' |
|||
}" |
|||
(click)="onClickActivity(row)" |
|||
></tr> |
|||
</table> |
|||
</div> |
|||
|
|||
<mat-paginator |
|||
[length]="totalItems" |
|||
[ngClass]="{ |
|||
'd-none': (isLoading && totalItems === 0) || totalItems <= pageSize |
|||
}" |
|||
[pageSize]="pageSize" |
|||
(page)="onChangePage($event)" |
|||
></mat-paginator> |
|||
|
|||
<ngx-skeleton-loader |
|||
*ngIf="isLoading" |
|||
animation="pulse" |
|||
class="px-4 py-3" |
|||
[theme]="{ |
|||
height: '1.5rem', |
|||
width: '100%' |
|||
}" |
|||
></ngx-skeleton-loader> |
|||
|
|||
<div |
|||
*ngIf=" |
|||
dataSource?.data.length === 0 && hasPermissionToCreateActivity && !isLoading |
|||
" |
|||
class="p-3 text-center" |
|||
> |
|||
<gf-no-transactions-info-indicator |
|||
[hasBorder]="false" |
|||
></gf-no-transactions-info-indicator> |
|||
</div> |
@ -0,0 +1,9 @@ |
|||
@import 'apps/client/src/styles/ghostfolio-style'; |
|||
|
|||
:host { |
|||
display: block; |
|||
|
|||
.activities { |
|||
overflow-x: auto; |
|||
} |
|||
} |
@ -0,0 +1,237 @@ |
|||
import { SelectionModel } from '@angular/cdk/collections'; |
|||
import { |
|||
ChangeDetectionStrategy, |
|||
Component, |
|||
EventEmitter, |
|||
Input, |
|||
OnChanges, |
|||
OnDestroy, |
|||
OnInit, |
|||
Output, |
|||
ViewChild |
|||
} from '@angular/core'; |
|||
import { MatPaginator, PageEvent } from '@angular/material/paginator'; |
|||
import { MatTableDataSource } from '@angular/material/table'; |
|||
import { Router } from '@angular/router'; |
|||
import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface'; |
|||
import { DEFAULT_PAGE_SIZE } from '@ghostfolio/common/config'; |
|||
import { getDateFormatString } from '@ghostfolio/common/helper'; |
|||
import { UniqueAsset } from '@ghostfolio/common/interfaces'; |
|||
import { OrderWithAccount } from '@ghostfolio/common/types'; |
|||
import { isUUID } from 'class-validator'; |
|||
import { endOfToday, isAfter } from 'date-fns'; |
|||
import { Subject, Subscription, takeUntil } from 'rxjs'; |
|||
|
|||
@Component({ |
|||
changeDetection: ChangeDetectionStrategy.OnPush, |
|||
selector: 'gf-activities-table-lazy', |
|||
styleUrls: ['./activities-table-lazy.component.scss'], |
|||
templateUrl: './activities-table-lazy.component.html' |
|||
}) |
|||
export class ActivitiesTableLazyComponent |
|||
implements OnChanges, OnDestroy, OnInit |
|||
{ |
|||
@Input() baseCurrency: string; |
|||
@Input() dataSource: MatTableDataSource<Activity>; |
|||
@Input() deviceType: string; |
|||
@Input() hasPermissionToCreateActivity: boolean; |
|||
@Input() hasPermissionToExportActivities: boolean; |
|||
@Input() hasPermissionToOpenDetails = true; |
|||
@Input() locale: string; |
|||
@Input() pageIndex: number; |
|||
@Input() pageSize = DEFAULT_PAGE_SIZE; |
|||
@Input() showActions = true; |
|||
@Input() showCheckbox = false; |
|||
@Input() showFooter = true; |
|||
@Input() showNameColumn = true; |
|||
@Input() totalItems = Number.MAX_SAFE_INTEGER; |
|||
|
|||
@Output() activityDeleted = new EventEmitter<string>(); |
|||
@Output() activityToClone = new EventEmitter<OrderWithAccount>(); |
|||
@Output() activityToUpdate = new EventEmitter<OrderWithAccount>(); |
|||
@Output() deleteAllActivities = new EventEmitter<void>(); |
|||
@Output() export = new EventEmitter<string[]>(); |
|||
@Output() exportDrafts = new EventEmitter<string[]>(); |
|||
@Output() import = new EventEmitter<void>(); |
|||
@Output() importDividends = new EventEmitter<UniqueAsset>(); |
|||
@Output() pageChanged = new EventEmitter<PageEvent>(); |
|||
@Output() selectedActivities = new EventEmitter<Activity[]>(); |
|||
|
|||
@ViewChild(MatPaginator) paginator: MatPaginator; |
|||
|
|||
public defaultDateFormat: string; |
|||
public displayedColumns = []; |
|||
public endOfToday = endOfToday(); |
|||
public hasDrafts = false; |
|||
public hasErrors = false; |
|||
public isAfter = isAfter; |
|||
public isLoading = true; |
|||
public isUUID = isUUID; |
|||
public routeQueryParams: Subscription; |
|||
public searchKeywords: string[] = []; |
|||
public selectedRows = new SelectionModel<Activity>(true, []); |
|||
|
|||
private unsubscribeSubject = new Subject<void>(); |
|||
|
|||
public constructor(private router: Router) {} |
|||
|
|||
public ngOnInit() { |
|||
if (this.showCheckbox) { |
|||
this.toggleAllRows(); |
|||
this.selectedRows.changed |
|||
.pipe(takeUntil(this.unsubscribeSubject)) |
|||
.subscribe((selectedRows) => { |
|||
this.selectedActivities.emit(selectedRows.source.selected); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
public areAllRowsSelected() { |
|||
const numSelectedRows = this.selectedRows.selected.length; |
|||
const numTotalRows = this.dataSource.data.length; |
|||
return numSelectedRows === numTotalRows; |
|||
} |
|||
|
|||
public ngOnChanges() { |
|||
this.defaultDateFormat = getDateFormatString(this.locale); |
|||
|
|||
this.displayedColumns = [ |
|||
'select', |
|||
'importStatus', |
|||
'icon', |
|||
'nameWithSymbol', |
|||
'type', |
|||
'date', |
|||
'quantity', |
|||
'unitPrice', |
|||
'fee', |
|||
'value', |
|||
'currency', |
|||
'valueInBaseCurrency', |
|||
'account', |
|||
'comment', |
|||
'actions' |
|||
]; |
|||
|
|||
if (!this.showCheckbox) { |
|||
this.displayedColumns = this.displayedColumns.filter((column) => { |
|||
return column !== 'importStatus' && column !== 'select'; |
|||
}); |
|||
} |
|||
|
|||
if (!this.showNameColumn) { |
|||
this.displayedColumns = this.displayedColumns.filter((column) => { |
|||
return column !== 'nameWithSymbol'; |
|||
}); |
|||
} |
|||
|
|||
if (this.dataSource) { |
|||
this.isLoading = false; |
|||
} |
|||
} |
|||
|
|||
public onChangePage(page: PageEvent) { |
|||
this.pageChanged.emit(page); |
|||
} |
|||
|
|||
public onClickActivity(activity: Activity) { |
|||
if (this.showCheckbox) { |
|||
if (!activity.error) { |
|||
this.selectedRows.toggle(activity); |
|||
} |
|||
} else if ( |
|||
this.hasPermissionToOpenDetails && |
|||
!activity.isDraft && |
|||
activity.type !== 'FEE' && |
|||
activity.type !== 'INTEREST' && |
|||
activity.type !== 'ITEM' && |
|||
activity.type !== 'LIABILITY' |
|||
) { |
|||
this.onOpenPositionDialog({ |
|||
dataSource: activity.SymbolProfile.dataSource, |
|||
symbol: activity.SymbolProfile.symbol |
|||
}); |
|||
} |
|||
} |
|||
|
|||
public onCloneActivity(aActivity: OrderWithAccount) { |
|||
this.activityToClone.emit(aActivity); |
|||
} |
|||
|
|||
public onDeleteActivity(aId: string) { |
|||
const confirmation = confirm( |
|||
$localize`Do you really want to delete this activity?` |
|||
); |
|||
|
|||
if (confirmation) { |
|||
this.activityDeleted.emit(aId); |
|||
} |
|||
} |
|||
|
|||
public onExport() { |
|||
if (this.searchKeywords.length > 0) { |
|||
this.export.emit( |
|||
this.dataSource.filteredData.map((activity) => { |
|||
return activity.id; |
|||
}) |
|||
); |
|||
} else { |
|||
this.export.emit(); |
|||
} |
|||
} |
|||
|
|||
public onExportDraft(aActivityId: string) { |
|||
this.exportDrafts.emit([aActivityId]); |
|||
} |
|||
|
|||
public onExportDrafts() { |
|||
this.exportDrafts.emit( |
|||
this.dataSource.filteredData |
|||
.filter((activity) => { |
|||
return activity.isDraft; |
|||
}) |
|||
.map((activity) => { |
|||
return activity.id; |
|||
}) |
|||
); |
|||
} |
|||
|
|||
public onDeleteAllActivities() { |
|||
this.deleteAllActivities.emit(); |
|||
} |
|||
|
|||
public onImport() { |
|||
this.import.emit(); |
|||
} |
|||
|
|||
public onImportDividends() { |
|||
this.importDividends.emit(); |
|||
} |
|||
|
|||
public onOpenComment(aComment: string) { |
|||
alert(aComment); |
|||
} |
|||
|
|||
public onOpenPositionDialog({ dataSource, symbol }: UniqueAsset): void { |
|||
this.router.navigate([], { |
|||
queryParams: { dataSource, symbol, positionDetailDialog: true } |
|||
}); |
|||
} |
|||
|
|||
public onUpdateActivity(aActivity: OrderWithAccount) { |
|||
this.activityToUpdate.emit(aActivity); |
|||
} |
|||
|
|||
public toggleAllRows() { |
|||
this.areAllRowsSelected() |
|||
? this.selectedRows.clear() |
|||
: this.dataSource.data.forEach((row) => this.selectedRows.select(row)); |
|||
|
|||
this.selectedActivities.emit(this.selectedRows.selected); |
|||
} |
|||
|
|||
public ngOnDestroy() { |
|||
this.unsubscribeSubject.next(); |
|||
this.unsubscribeSubject.complete(); |
|||
} |
|||
} |
@ -0,0 +1,41 @@ |
|||
import { CommonModule } from '@angular/common'; |
|||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; |
|||
import { MatButtonModule } from '@angular/material/button'; |
|||
import { MatCheckboxModule } from '@angular/material/checkbox'; |
|||
import { MatMenuModule } from '@angular/material/menu'; |
|||
import { MatPaginatorModule } from '@angular/material/paginator'; |
|||
import { MatSortModule } from '@angular/material/sort'; |
|||
import { MatTableModule } from '@angular/material/table'; |
|||
import { MatTooltipModule } from '@angular/material/tooltip'; |
|||
import { RouterModule } from '@angular/router'; |
|||
import { GfSymbolIconModule } from '@ghostfolio/client/components/symbol-icon/symbol-icon.module'; |
|||
import { GfSymbolModule } from '@ghostfolio/client/pipes/symbol/symbol.module'; |
|||
import { GfActivityTypeModule } from '@ghostfolio/ui/activity-type'; |
|||
import { GfNoTransactionsInfoModule } from '@ghostfolio/ui/no-transactions-info'; |
|||
import { GfValueModule } from '@ghostfolio/ui/value'; |
|||
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; |
|||
|
|||
import { ActivitiesTableLazyComponent } from './activities-table-lazy.component'; |
|||
|
|||
@NgModule({ |
|||
declarations: [ActivitiesTableLazyComponent], |
|||
exports: [ActivitiesTableLazyComponent], |
|||
imports: [ |
|||
CommonModule, |
|||
GfActivityTypeModule, |
|||
GfNoTransactionsInfoModule, |
|||
GfSymbolIconModule, |
|||
GfSymbolModule, |
|||
GfValueModule, |
|||
MatButtonModule, |
|||
MatCheckboxModule, |
|||
MatMenuModule, |
|||
MatPaginatorModule, |
|||
MatTableModule, |
|||
MatTooltipModule, |
|||
NgxSkeletonLoaderModule, |
|||
RouterModule |
|||
], |
|||
schemas: [CUSTOM_ELEMENTS_SCHEMA] |
|||
}) |
|||
export class GfActivitiesTableLazyModule {} |
Loading…
Reference in new issue