Browse Source

Task/improve activities table type safety (#6295)

* Improve activities table type safety
pull/6264/head^2
Kenrick Tandrian 1 day ago
committed by GitHub
parent
commit
753804c011
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      libs/common/src/lib/interfaces/activities.interface.ts
  2. 36
      libs/ui/src/lib/activities-table/activities-table.component.html
  3. 138
      libs/ui/src/lib/activities-table/activities-table.component.ts

2
libs/common/src/lib/interfaces/activities.interface.ts

@ -8,7 +8,7 @@ export interface Activity extends Order {
error?: ActivityError;
feeInAssetProfileCurrency: number;
feeInBaseCurrency: number;
SymbolProfile?: EnhancedSymbolProfile;
SymbolProfile: EnhancedSymbolProfile;
tagIds?: string[];
tags?: Tag[];
unitPriceInAssetProfileCurrency: number;

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

@ -21,7 +21,7 @@
<mat-menu #activitiesMenu="matMenu" class="no-max-width" xPosition="before">
<button
mat-menu-item
[disabled]="dataSource?.data.length === 0"
[disabled]="dataSource()?.data.length === 0"
(click)="onImportDividends()"
>
<span class="align-items-center d-flex">
@ -33,7 +33,7 @@
<button
class="align-items-center d-flex"
mat-menu-item
[disabled]="dataSource?.data.length === 0"
[disabled]="dataSource()?.data.length === 0"
(click)="onExport()"
>
<span class="align-items-center d-flex">
@ -60,7 +60,7 @@
class="align-items-center d-flex"
mat-menu-item
[disabled]="
dataSource?.data.length === 0 || !hasPermissionToDeleteActivity
dataSource()?.data.length === 0 || !hasPermissionToDeleteActivity
"
(click)="onDeleteActivities()"
>
@ -78,7 +78,7 @@
class="gf-table w-100"
mat-table
matSort
[dataSource]="dataSource"
[dataSource]="dataSource()"
[matSortActive]="sortColumn"
[matSortDirection]="sortDirection"
[matSortDisabled]="sortDisabled"
@ -177,7 +177,7 @@
[deviceType]="deviceType"
[isDate]="true"
[locale]="locale"
[value]="isLoading ? undefined : element.date"
[value]="isLoading() ? undefined : element.date"
/>
</div>
</td>
@ -201,7 +201,7 @@
<gf-value
[isCurrency]="true"
[locale]="locale"
[value]="isLoading ? undefined : element.quantity"
[value]="isLoading() ? undefined : element.quantity"
/>
</div>
</td>
@ -225,7 +225,7 @@
<gf-value
[isCurrency]="true"
[locale]="locale"
[value]="isLoading ? undefined : element.unitPrice"
[value]="isLoading() ? undefined : element.unitPrice"
/>
</div>
</td>
@ -249,7 +249,7 @@
<gf-value
[isCurrency]="true"
[locale]="locale"
[value]="isLoading ? undefined : element.fee"
[value]="isLoading() ? undefined : element.fee"
/>
</div>
</td>
@ -272,7 +272,7 @@
<gf-value
[isCurrency]="true"
[locale]="locale"
[value]="isLoading ? undefined : element.value"
[value]="isLoading() ? undefined : element.value"
/>
</div>
</td>
@ -304,7 +304,7 @@
<gf-value
[isCurrency]="true"
[locale]="locale"
[value]="isLoading ? undefined : element.valueInBaseCurrency"
[value]="isLoading() ? undefined : element.valueInBaseCurrency"
/>
</div>
</td>
@ -388,7 +388,7 @@
@if (hasPermissionToCreateActivity) {
<button
mat-menu-item
[disabled]="dataSource?.data.length === 0"
[disabled]="dataSource()?.data.length === 0"
(click)="onImportDividends()"
>
<span class="align-items-center d-flex">
@ -403,7 +403,7 @@
<button
class="align-items-center d-flex"
mat-menu-item
[disabled]="dataSource?.data.length === 0"
[disabled]="dataSource()?.data.length === 0"
(click)="onExport()"
>
<span class="align-items-center d-flex">
@ -488,9 +488,9 @@
</td>
</ng-container>
<tr *matHeaderRowDef="displayedColumns" mat-header-row></tr>
<tr *matHeaderRowDef="displayedColumns()" mat-header-row></tr>
<tr
*matRowDef="let row; columns: displayedColumns"
*matRowDef="let row; columns: displayedColumns()"
mat-row
[ngClass]="{
'cursor-pointer': canClickActivity(row)
@ -500,7 +500,7 @@
</table>
</div>
@if (isLoading) {
@if (isLoading()) {
<ngx-skeleton-loader
animation="pulse"
class="px-4 py-3"
@ -514,7 +514,7 @@
<mat-paginator
[length]="totalItems"
[ngClass]="{
'd-none': (isLoading && !totalItems) || totalItems <= pageSize
'd-none': (isLoading() && !totalItems) || totalItems <= pageSize
}"
[pageIndex]="pageIndex"
[pageSize]="pageSize"
@ -524,9 +524,9 @@
@if (
!hasActivities &&
dataSource?.data.length === 0 &&
dataSource()?.data.length === 0 &&
hasPermissionToCreateActivity &&
!isLoading
!isLoading()
) {
<div class="p-3 text-center">
<gf-no-transactions-info-indicator [hasBorder]="false" />

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

@ -21,11 +21,13 @@ import {
Component,
EventEmitter,
Input,
OnChanges,
OnDestroy,
OnInit,
Output,
ViewChild
ViewChild,
computed,
inject,
input
} from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox';
@ -45,7 +47,6 @@ import { MatTableDataSource, MatTableModule } from '@angular/material/table';
import { MatTooltipModule } from '@angular/material/tooltip';
import { IonIcon } from '@ionic/angular/standalone';
import { isUUID } from 'class-validator';
import { endOfToday, isAfter } from 'date-fns';
import { addIcons } from 'ionicons';
import {
alertCircleOutline,
@ -62,7 +63,7 @@ import {
trashOutline
} from 'ionicons/icons';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { Subject, Subscription, takeUntil } from 'rxjs';
import { Subject, takeUntil } from 'rxjs';
import { GfActivityTypeComponent } from '../activity-type/activity-type.component';
import { GfEntityLogoComponent } from '../entity-logo/entity-logo.component';
@ -94,10 +95,9 @@ import { GfValueComponent } from '../value/value.component';
templateUrl: './activities-table.component.html'
})
export class GfActivitiesTableComponent
implements AfterViewInit, OnChanges, OnDestroy, OnInit
implements AfterViewInit, OnDestroy, OnInit
{
@Input() baseCurrency: string;
@Input() dataSource: MatTableDataSource<Activity>;
@Input() deviceType: string;
@Input() hasActivities: boolean;
@Input() hasPermissionToCreateActivity: boolean;
@ -107,10 +107,7 @@ export class GfActivitiesTableComponent
@Input() locale = getLocale();
@Input() pageIndex: number;
@Input() pageSize = DEFAULT_PAGE_SIZE;
@Input() showAccountColumn = true;
@Input() showActions = true;
@Input() showCheckbox = false;
@Input() showNameColumn = true;
@Input() sortColumn: string;
@Input() sortDirection: SortDirection;
@Input() sortDisabled = false;
@ -132,19 +129,66 @@ export class GfActivitiesTableComponent
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
public displayedColumns = [];
public endOfToday = endOfToday();
public hasDrafts = false;
public hasErrors = false;
public isAfter = isAfter;
public isLoading = true;
public isUUID = isUUID;
public routeQueryParams: Subscription;
public selectedRows = new SelectionModel<Activity>(true, []);
private unsubscribeSubject = new Subject<void>();
public readonly dataSource = input.required<
MatTableDataSource<Activity> | undefined
>();
public readonly showAccountColumn = input(true);
public readonly showCheckbox = input(false);
public readonly showNameColumn = input(true);
public constructor(private notificationService: NotificationService) {
protected readonly displayedColumns = computed(() => {
let columns = [
'select',
'importStatus',
'icon',
'nameWithSymbol',
'type',
'date',
'quantity',
'unitPrice',
'fee',
'value',
'currency',
'valueInBaseCurrency',
'account',
'comment',
'actions'
];
if (!this.showAccountColumn()) {
columns = columns.filter((column) => {
return column !== 'account';
});
}
if (!this.showCheckbox()) {
columns = columns.filter((column) => {
return column !== 'importStatus' && column !== 'select';
});
}
if (!this.showNameColumn()) {
columns = columns.filter((column) => {
return column !== 'nameWithSymbol';
});
}
return columns;
});
protected readonly isLoading = computed(() => {
return !this.dataSource();
});
private readonly notificationService = inject(NotificationService);
private readonly unsubscribeSubject = new Subject<void>();
public constructor() {
addIcons({
alertCircleOutline,
calendarClearOutline,
@ -162,7 +206,7 @@ export class GfActivitiesTableComponent
}
public ngOnInit() {
if (this.showCheckbox) {
if (this.showCheckbox()) {
this.toggleAllRows();
this.selectedRows.changed
.pipe(takeUntil(this.unsubscribeSubject))
@ -173,8 +217,10 @@ export class GfActivitiesTableComponent
}
public ngAfterViewInit() {
if (this.dataSource) {
this.dataSource.paginator = this.paginator;
const dataSource = this.dataSource();
if (dataSource) {
dataSource.paginator = this.paginator;
}
this.sort.sortChange.subscribe((value: Sort) => {
@ -182,51 +228,9 @@ export class GfActivitiesTableComponent
});
}
public ngOnChanges() {
this.displayedColumns = [
'select',
'importStatus',
'icon',
'nameWithSymbol',
'type',
'date',
'quantity',
'unitPrice',
'fee',
'value',
'currency',
'valueInBaseCurrency',
'account',
'comment',
'actions'
];
if (!this.showAccountColumn) {
this.displayedColumns = this.displayedColumns.filter((column) => {
return column !== 'account';
});
}
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 areAllRowsSelected() {
const numSelectedRows = this.selectedRows.selected.length;
const numTotalRows = this.dataSource.data.length;
const numTotalRows = this.dataSource()?.data.length;
return numSelectedRows === numTotalRows;
}
@ -241,7 +245,7 @@ export class GfActivitiesTableComponent
public isExcludedFromAnalysis(activity: Activity) {
return (
activity.account?.isExcluded ||
activity.account?.isExcluded ??
activity.tags?.some(({ id }) => {
return id === TAG_ID_EXCLUDE_FROM_ANALYSIS;
})
@ -253,7 +257,7 @@ export class GfActivitiesTableComponent
}
public onClickActivity(activity: Activity) {
if (this.showCheckbox) {
if (this.showCheckbox()) {
if (!activity.error) {
this.selectedRows.toggle(activity);
}
@ -299,8 +303,8 @@ export class GfActivitiesTableComponent
public onExportDrafts() {
this.exportDrafts.emit(
this.dataSource.filteredData
.filter((activity) => {
this.dataSource()
?.filteredData.filter((activity) => {
return activity.isDraft;
})
.map((activity) => {
@ -331,7 +335,7 @@ export class GfActivitiesTableComponent
if (this.areAllRowsSelected()) {
this.selectedRows.clear();
} else {
this.dataSource.data.forEach((row) => {
this.dataSource()?.data.forEach((row) => {
this.selectedRows.select(row);
});
}

Loading…
Cancel
Save