Browse Source

Task/apply review

pull/6622/head
Airthee 5 days ago
parent
commit
12a8080a5c
No known key found for this signature in database GPG Key ID: C7EADC5599E355EC
  1. 2
      apps/api/src/app/activities/activities.controller.ts
  2. 10
      apps/api/src/app/export/export.controller.ts
  3. 6
      apps/api/src/app/export/export.service.ts
  4. 22
      apps/client/src/app/pages/portfolio/activities/activities-page.component.ts
  5. 2
      apps/client/src/app/pages/portfolio/activities/activities-page.html
  6. 8
      libs/common/src/lib/helper.ts
  7. 4
      libs/ui/src/lib/activities-table/activities-table.component.html
  8. 20
      libs/ui/src/lib/activities-table/activities-table.component.ts
  9. 18
      libs/ui/src/lib/services/data.service.ts
  10. 0
      prisma/migrations/20260321200654_added_index_for_type_to_order/migration.sql

2
apps/api/src/app/activities/activities.controller.ts

@ -122,7 +122,7 @@ export class ActivitiesController {
@Query('symbol') filterBySymbol?: string, @Query('symbol') filterBySymbol?: string,
@Query('tags') filterByTags?: string, @Query('tags') filterByTags?: string,
@Query('take') take?: number, @Query('take') take?: number,
@Query('types') filterByTypes?: string @Query('activityTypes') filterByTypes?: string
): Promise<ActivitiesResponse> { ): Promise<ActivitiesResponse> {
const types = filterByTypes const types = filterByTypes
? (splitStringToArray(filterByTypes) as ActivityType[]) ? (splitStringToArray(filterByTypes) as ActivityType[])

10
apps/api/src/app/export/export.controller.ts

@ -39,9 +39,12 @@ export class ExportController {
@Query('dataSource') filterByDataSource?: string, @Query('dataSource') filterByDataSource?: string,
@Query('symbol') filterBySymbol?: string, @Query('symbol') filterBySymbol?: string,
@Query('tags') filterByTags?: string, @Query('tags') filterByTags?: string,
@Query('types') filterByTypes?: string @Query('activityTypes') filterByTypes?: string
): Promise<ExportResponse> { ): Promise<ExportResponse> {
const activityIds = filterByActivityIds?.split(',') ?? []; const activityIds = filterByActivityIds?.split(',') ?? [];
const activityTypes = filterByTypes
? (splitStringToArray(filterByTypes) as ActivityType[])
: undefined;
const filters = this.apiService.buildFiltersFromQueryParams({ const filters = this.apiService.buildFiltersFromQueryParams({
filterByAccounts, filterByAccounts,
filterByAssetClasses, filterByAssetClasses,
@ -49,14 +52,11 @@ export class ExportController {
filterBySymbol, filterBySymbol,
filterByTags filterByTags
}); });
const types = filterByTypes
? (splitStringToArray(filterByTypes) as ActivityType[])
: undefined;
return this.exportService.export({ return this.exportService.export({
activityIds, activityIds,
filters, filters,
types, activityTypes: activityTypes,
userId: this.request.user.id, userId: this.request.user.id,
userSettings: this.request.user.settings.settings userSettings: this.request.user.settings.settings
}); });

6
apps/api/src/app/export/export.service.ts

@ -24,14 +24,14 @@ export class ExportService {
public async export({ public async export({
activityIds, activityIds,
activityTypes,
filters, filters,
types,
userId, userId,
userSettings userSettings
}: { }: {
activityIds?: string[]; activityIds?: string[];
filters?: Filter[]; filters?: Filter[];
types?: ActivityType[]; activityTypes?: ActivityType[];
userId: string; userId: string;
userSettings: UserSettings; userSettings: UserSettings;
}): Promise<ExportResponse> { }): Promise<ExportResponse> {
@ -42,7 +42,7 @@ export class ExportService {
let { activities } = await this.activitiesService.getActivities({ let { activities } = await this.activitiesService.getActivities({
filters, filters,
types, types: activityTypes,
userId, userId,
includeDrafts: true, includeDrafts: true,
sortColumn: 'date', sortColumn: 'date',

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

@ -54,13 +54,12 @@ import { ImportActivitiesDialogParams } from './import-activities-dialog/interfa
templateUrl: './activities-page.html' templateUrl: './activities-page.html'
}) })
export class GfActivitiesPageComponent implements OnInit { export class GfActivitiesPageComponent implements OnInit {
public activityTypeFilter: string[] = []; public activityTypesFilter: string[] = [];
public dataSource: MatTableDataSource<Activity>; public dataSource: MatTableDataSource<Activity>;
public deviceType: string; public deviceType: string;
public hasImpersonationId: boolean; public hasImpersonationId: boolean;
public hasPermissionToCreateActivity: boolean; public hasPermissionToCreateActivity: boolean;
public hasPermissionToDeleteActivity: boolean; public hasPermissionToDeleteActivity: boolean;
public hasPermissionToFilterByType = true;
public pageIndex = 0; public pageIndex = 0;
public pageSize = DEFAULT_PAGE_SIZE; public pageSize = DEFAULT_PAGE_SIZE;
public routeQueryParams: Subscription; public routeQueryParams: Subscription;
@ -148,8 +147,8 @@ export class GfActivitiesPageComponent implements OnInit {
sortColumn: this.sortColumn, sortColumn: this.sortColumn,
sortDirection: this.sortDirection, sortDirection: this.sortDirection,
take: this.pageSize, take: this.pageSize,
types: this.activityTypeFilter.length activityTypes: this.activityTypesFilter.length
? this.activityTypeFilter ? this.activityTypesFilter
: undefined : undefined
}) })
.pipe(takeUntilDestroyed(this.destroyRef)) .pipe(takeUntilDestroyed(this.destroyRef))
@ -224,8 +223,8 @@ export class GfActivitiesPageComponent implements OnInit {
if (!activityIds) { if (!activityIds) {
fetchExportParams = { fetchExportParams = {
filters: this.userService.getFilters(), filters: this.userService.getFilters(),
types: this.activityTypeFilter.length activityTypes: this.activityTypesFilter.length
? this.activityTypeFilter ? this.activityTypesFilter
: undefined : undefined
}; };
} }
@ -320,16 +319,17 @@ export class GfActivitiesPageComponent implements OnInit {
}); });
} }
public onTypesFilterChanged(types: string[]) { public onSortChanged({ active, direction }: Sort) {
this.activityTypeFilter = types;
this.pageIndex = 0; this.pageIndex = 0;
this.sortColumn = active;
this.sortDirection = direction;
this.fetchActivities(); this.fetchActivities();
} }
public onSortChanged({ active, direction }: Sort) { public onTypesFilterChanged(types: string[]) {
this.activityTypesFilter = types;
this.pageIndex = 0; this.pageIndex = 0;
this.sortColumn = active;
this.sortDirection = direction;
this.fetchActivities(); this.fetchActivities();
} }

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

@ -10,7 +10,7 @@
[hasPermissionToCreateActivity]="hasPermissionToCreateActivity" [hasPermissionToCreateActivity]="hasPermissionToCreateActivity"
[hasPermissionToDeleteActivity]="hasPermissionToDeleteActivity" [hasPermissionToDeleteActivity]="hasPermissionToDeleteActivity"
[hasPermissionToExportActivities]="!hasImpersonationId" [hasPermissionToExportActivities]="!hasImpersonationId"
[hasPermissionToFilterByType]="hasPermissionToFilterByType" [hasPermissionToFilterByType]="user?.settings?.isExperimentalFeatures"
[locale]="user?.settings?.locale" [locale]="user?.settings?.locale"
[pageIndex]="pageIndex" [pageIndex]="pageIndex"
[pageSize]="pageSize" [pageSize]="pageSize"

8
libs/common/src/lib/helper.ts

@ -463,10 +463,6 @@ export function resolveFearAndGreedIndex(aValue: number) {
} }
} }
export function splitStringToArray(aString?: string): string[] {
return aString?.split(',') ?? [];
}
export function resolveMarketCondition( export function resolveMarketCondition(
aMarketCondition: Benchmark['marketCondition'] aMarketCondition: Benchmark['marketCondition']
) { ) {
@ -478,3 +474,7 @@ export function resolveMarketCondition(
return { emoji: undefined }; return { emoji: undefined };
} }
} }
export function splitStringToArray(aString?: string): string[] {
return aString?.split(',') ?? [];
}

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

@ -1,4 +1,4 @@
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-end justify-content-lg-between">
<div class="d-none d-lg-flex"> <div class="d-none d-lg-flex">
@if (hasPermissionToFilterByType) { @if (hasPermissionToFilterByType) {
<mat-form-field appearance="outline" class="without-hint"> <mat-form-field appearance="outline" class="without-hint">
@ -18,7 +18,7 @@
</div> </div>
@if (hasPermissionToCreateActivity) { @if (hasPermissionToCreateActivity) {
<div class="d-flex justify-content-end"> <div class="d-flex">
<button <button
class="align-items-center d-flex" class="align-items-center d-flex"
mat-stroked-button mat-stroked-button

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

@ -10,6 +10,7 @@ import {
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { GfSymbolPipe } from '@ghostfolio/common/pipes'; import { GfSymbolPipe } from '@ghostfolio/common/pipes';
import { OrderWithAccount } from '@ghostfolio/common/types'; import { OrderWithAccount } from '@ghostfolio/common/types';
import { translate } from '@ghostfolio/ui/i18n';
import { NotificationService } from '@ghostfolio/ui/notifications'; import { NotificationService } from '@ghostfolio/ui/notifications';
import { SelectionModel } from '@angular/cdk/collections'; import { SelectionModel } from '@angular/cdk/collections';
@ -93,8 +94,8 @@ import { GfValueComponent } from '../value/value.component';
MatSortModule, MatSortModule,
MatTableModule, MatTableModule,
MatTooltipModule, MatTooltipModule,
ReactiveFormsModule, NgxSkeletonLoaderModule,
NgxSkeletonLoaderModule ReactiveFormsModule
], ],
schemas: [CUSTOM_ELEMENTS_SCHEMA], schemas: [CUSTOM_ELEMENTS_SCHEMA],
selector: 'gf-activities-table', selector: 'gf-activities-table',
@ -110,7 +111,7 @@ export class GfActivitiesTableComponent
@Input() hasPermissionToCreateActivity: boolean; @Input() hasPermissionToCreateActivity: boolean;
@Input() hasPermissionToDeleteActivity: boolean; @Input() hasPermissionToDeleteActivity: boolean;
@Input() hasPermissionToExportActivities: boolean; @Input() hasPermissionToExportActivities: boolean;
@Input() hasPermissionToFilterByType = false; @Input() hasPermissionToFilterByType: boolean;
@Input() hasPermissionToOpenDetails = true; @Input() hasPermissionToOpenDetails = true;
@Input() locale = getLocale(); @Input() locale = getLocale();
@Input() pageIndex: number; @Input() pageIndex: number;
@ -138,14 +139,7 @@ export class GfActivitiesTableComponent
@ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort; @ViewChild(MatSort) sort: MatSort;
public readonly activityTypes: Record<ActivityType, string> = { public readonly activityTypes = new Map<ActivityType, string>();
[ActivityType.BUY]: $localize`Buy`,
[ActivityType.DIVIDEND]: $localize`Dividend`,
[ActivityType.FEE]: $localize`Fee`,
[ActivityType.INTEREST]: $localize`Interest`,
[ActivityType.LIABILITY]: $localize`Liability`,
[ActivityType.SELL]: $localize`Sell`
};
public hasDrafts = false; public hasDrafts = false;
public hasErrors = false; public hasErrors = false;
public isUUID = isUUID; public isUUID = isUUID;
@ -207,6 +201,10 @@ export class GfActivitiesTableComponent
private readonly unsubscribeSubject = new Subject<void>(); private readonly unsubscribeSubject = new Subject<void>();
public constructor() { public constructor() {
for (const type of Object.keys(ActivityType) as ActivityType[]) {
this.activityTypes.set(ActivityType[type], translate(ActivityType[type]));
}
addIcons({ addIcons({
alertCircleOutline, alertCircleOutline,
calendarClearOutline, calendarClearOutline,

18
libs/ui/src/lib/services/data.service.ts

@ -215,15 +215,15 @@ export class DataService {
sortColumn, sortColumn,
sortDirection, sortDirection,
take, take,
types activityTypes
}: { }: {
activityTypes?: string[];
filters?: Filter[]; filters?: Filter[];
range?: DateRange; range?: DateRange;
skip?: number; skip?: number;
sortColumn?: string; sortColumn?: string;
sortDirection?: SortDirection; sortDirection?: SortDirection;
take?: number; take?: number;
types?: string[];
}): Observable<ActivitiesResponse> { }): Observable<ActivitiesResponse> {
let params = this.buildFiltersAsQueryParams({ filters }); let params = this.buildFiltersAsQueryParams({ filters });
@ -247,8 +247,8 @@ export class DataService {
params = params.append('take', take); params = params.append('take', take);
} }
if (types?.length) { if (activityTypes?.length) {
params = params.append('types', types.join(',')); params = params.append('activityTypes', activityTypes.join(','));
} }
return this.http.get<any>('/api/v1/activities', { params }).pipe( return this.http.get<any>('/api/v1/activities', { params }).pipe(
@ -417,12 +417,12 @@ export class DataService {
public fetchExport({ public fetchExport({
activityIds, activityIds,
filters, activityTypes,
types filters
}: { }: {
activityIds?: string[]; activityIds?: string[];
activityTypes?: string[];
filters?: Filter[]; filters?: Filter[];
types?: string[];
} = {}) { } = {}) {
let params = this.buildFiltersAsQueryParams({ filters }); let params = this.buildFiltersAsQueryParams({ filters });
@ -430,8 +430,8 @@ export class DataService {
params = params.append('activityIds', activityIds.join(',')); params = params.append('activityIds', activityIds.join(','));
} }
if (types?.length) { if (activityTypes?.length) {
params = params.append('types', types.join(',')); params = params.append('activityTypes', activityTypes.join(','));
} }
return this.http.get<ExportResponse>('/api/v1/export', { return this.http.get<ExportResponse>('/api/v1/export', {

0
prisma/migrations/20260321200654_add_index_on_order_type/migration.sql → prisma/migrations/20260321200654_added_index_for_type_to_order/migration.sql

Loading…
Cancel
Save