Browse Source

Support sorting

pull/2108/head
Thomas 2 years ago
parent
commit
2f16f9255f
  1. 6
      apps/api/src/app/admin/admin.controller.ts
  2. 12
      apps/api/src/app/admin/admin.service.ts
  3. 47
      apps/client/src/app/components/admin-market-data/admin-market-data.component.ts
  4. 6
      apps/client/src/app/components/admin-market-data/admin-market-data.html
  5. 14
      apps/client/src/app/services/admin.service.ts

6
apps/api/src/app/admin/admin.controller.ts

@ -33,7 +33,7 @@ import {
} from '@nestjs/common'; } from '@nestjs/common';
import { REQUEST } from '@nestjs/core'; import { REQUEST } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport'; import { AuthGuard } from '@nestjs/passport';
import { DataSource, MarketData, SymbolProfile } from '@prisma/client'; import { DataSource, MarketData, Prisma, SymbolProfile } from '@prisma/client';
import { isDate } from 'date-fns'; import { isDate } from 'date-fns';
import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { StatusCodes, getReasonPhrase } from 'http-status-codes';
@ -250,6 +250,8 @@ export class AdminController {
public async getMarketData( public async getMarketData(
@Query('assetSubClasses') filterByAssetSubClasses?: string, @Query('assetSubClasses') filterByAssetSubClasses?: string,
@Query('skip') skip?: number, @Query('skip') skip?: number,
@Query('sortColumn') sortColumn?: string,
@Query('sortDirection') sortDirection?: Prisma.SortOrder,
@Query('take') take?: number @Query('take') take?: number
): Promise<AdminMarketData> { ): Promise<AdminMarketData> {
if ( if (
@ -277,6 +279,8 @@ export class AdminController {
return this.adminService.getMarketData({ return this.adminService.getMarketData({
filters, filters,
sortColumn,
sortDirection,
skip: isNaN(skip) ? undefined : skip, skip: isNaN(skip) ? undefined : skip,
take: isNaN(take) ? undefined : take take: isNaN(take) ? undefined : take
}); });

12
apps/api/src/app/admin/admin.service.ts

@ -103,13 +103,19 @@ export class AdminService {
public async getMarketData({ public async getMarketData({
filters, filters,
sortColumn,
sortDirection,
skip, skip,
take = DEFAULT_PAGE_SIZE take = DEFAULT_PAGE_SIZE
}: { }: {
filters?: Filter[]; filters?: Filter[];
skip?: number; skip?: number;
sortColumn?: string;
sortDirection?: Prisma.SortOrder;
take?: number; take?: number;
}): Promise<AdminMarketData> { }): Promise<AdminMarketData> {
let orderBy: Prisma.Enumerable<Prisma.SymbolProfileOrderByWithRelationInput> =
[{ symbol: 'asc' }];
const where: Prisma.SymbolProfileWhereInput = {}; const where: Prisma.SymbolProfileWhereInput = {};
const { ASSET_SUB_CLASS: filtersByAssetSubClass } = groupBy( const { ASSET_SUB_CLASS: filtersByAssetSubClass } = groupBy(
@ -128,12 +134,16 @@ export class AdminService {
where.assetSubClass = AssetSubClass[filtersByAssetSubClass[0].id]; where.assetSubClass = AssetSubClass[filtersByAssetSubClass[0].id];
} }
if (sortColumn) {
orderBy = [{ [sortColumn]: sortDirection }];
}
const [assetProfiles, count] = await Promise.all([ const [assetProfiles, count] = await Promise.all([
this.prismaService.symbolProfile.findMany({ this.prismaService.symbolProfile.findMany({
orderBy,
skip, skip,
take, take,
where, where,
orderBy: [{ symbol: 'asc' }],
select: { select: {
_count: { _count: {
select: { Order: true } select: { Order: true }

47
apps/client/src/app/components/admin-market-data/admin-market-data.component.ts

@ -1,4 +1,5 @@
import { import {
AfterViewInit,
ChangeDetectionStrategy, ChangeDetectionStrategy,
ChangeDetectorRef, ChangeDetectorRef,
Component, Component,
@ -7,7 +8,7 @@ import {
ViewChild ViewChild
} from '@angular/core'; } from '@angular/core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { MatSort } from '@angular/material/sort'; import { MatSort, Sort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table'; import { MatTableDataSource } from '@angular/material/table';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { AdminService } from '@ghostfolio/client/services/admin.service'; import { AdminService } from '@ghostfolio/client/services/admin.service';
@ -16,7 +17,7 @@ import { getDateFormatString } from '@ghostfolio/common/helper';
import { Filter, UniqueAsset, User } from '@ghostfolio/common/interfaces'; import { Filter, UniqueAsset, User } from '@ghostfolio/common/interfaces';
import { AdminMarketDataItem } from '@ghostfolio/common/interfaces/admin-market-data.interface'; import { AdminMarketDataItem } from '@ghostfolio/common/interfaces/admin-market-data.interface';
import { translate } from '@ghostfolio/ui/i18n'; import { translate } from '@ghostfolio/ui/i18n';
import { AssetSubClass, DataSource } from '@prisma/client'; import { AssetSubClass, DataSource, Prisma } from '@prisma/client';
import { DeviceDetectorService } from 'ngx-device-detector'; import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { distinctUntilChanged, switchMap, takeUntil } from 'rxjs/operators'; import { distinctUntilChanged, switchMap, takeUntil } from 'rxjs/operators';
@ -34,7 +35,9 @@ import { MatPaginator, PageEvent } from '@angular/material/paginator';
styleUrls: ['./admin-market-data.scss'], styleUrls: ['./admin-market-data.scss'],
templateUrl: './admin-market-data.html' templateUrl: './admin-market-data.html'
}) })
export class AdminMarketDataComponent implements OnDestroy, OnInit { export class AdminMarketDataComponent
implements AfterViewInit, OnDestroy, OnInit
{
@ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort; @ViewChild(MatSort) sort: MatSort;
@ -130,12 +133,30 @@ export class AdminMarketDataComponent implements OnDestroy, OnInit {
}); });
} }
public ngAfterViewInit() {
this.sort.sortChange.subscribe(
({ active: sortColumn, direction }: Sort) => {
this.paginator.pageIndex = 0;
this.loadData({
sortColumn,
sortDirection: <Prisma.SortOrder>direction,
pageIndex: this.paginator.pageIndex
});
}
);
}
public ngOnInit() { public ngOnInit() {
this.deviceType = this.deviceService.getDeviceInfo().deviceType; this.deviceType = this.deviceService.getDeviceInfo().deviceType;
} }
public onChangePage(page: PageEvent) { public onChangePage(page: PageEvent) {
this.loadData(page.pageIndex); this.loadData({
pageIndex: page.pageIndex,
sortColumn: this.sort.active,
sortDirection: <Prisma.SortOrder>this.sort.direction
});
} }
public onDeleteProfileData({ dataSource, symbol }: UniqueAsset) { public onDeleteProfileData({ dataSource, symbol }: UniqueAsset) {
@ -203,10 +224,20 @@ export class AdminMarketDataComponent implements OnDestroy, OnInit {
this.unsubscribeSubject.complete(); this.unsubscribeSubject.complete();
} }
private loadData(aPageIndex = 0) { private loadData(
{
pageIndex,
sortColumn,
sortDirection
}: {
pageIndex: number;
sortColumn?: string;
sortDirection?: Prisma.SortOrder;
} = { pageIndex: 0 }
) {
this.isLoading = true; this.isLoading = true;
if (aPageIndex === 0 && this.paginator) { if (pageIndex === 0 && this.paginator) {
this.paginator.pageIndex = 0; this.paginator.pageIndex = 0;
} }
@ -215,8 +246,10 @@ export class AdminMarketDataComponent implements OnDestroy, OnInit {
this.adminService this.adminService
.fetchAdminMarketData({ .fetchAdminMarketData({
sortColumn,
sortDirection,
filters: this.activeFilters, filters: this.activeFilters,
skip: aPageIndex * this.pageSize, skip: pageIndex * this.pageSize,
take: this.pageSize take: this.pageSize
}) })
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))

6
apps/client/src/app/components/admin-market-data/admin-market-data.html

@ -29,7 +29,7 @@
</ng-container> </ng-container>
<ng-container matColumnDef="dataSource"> <ng-container matColumnDef="dataSource">
<th *matHeaderCellDef class="px-1" mat-header-cell> <th *matHeaderCellDef class="px-1" mat-header-cell mat-sort-header>
<ng-container i18n>Data Source</ng-container> <ng-container i18n>Data Source</ng-container>
</th> </th>
<td *matCellDef="let element" class="px-1" mat-cell> <td *matCellDef="let element" class="px-1" mat-cell>
@ -38,7 +38,7 @@
</ng-container> </ng-container>
<ng-container matColumnDef="assetClass"> <ng-container matColumnDef="assetClass">
<th *matHeaderCellDef class="px-1" mat-header-cell> <th *matHeaderCellDef class="px-1" mat-header-cell mat-sort-header>
<ng-container i18n>Asset Class</ng-container> <ng-container i18n>Asset Class</ng-container>
</th> </th>
<td *matCellDef="let element" class="px-1" mat-cell> <td *matCellDef="let element" class="px-1" mat-cell>
@ -47,7 +47,7 @@
</ng-container> </ng-container>
<ng-container matColumnDef="assetSubClass"> <ng-container matColumnDef="assetSubClass">
<th *matHeaderCellDef class="px-1" mat-header-cell> <th *matHeaderCellDef class="px-1" mat-header-cell mat-sort-header>
<ng-container i18n>Asset Sub Class</ng-container> <ng-container i18n>Asset Sub Class</ng-container>
</th> </th>
<td *matCellDef="let element" class="px-1" mat-cell> <td *matCellDef="let element" class="px-1" mat-cell>

14
apps/client/src/app/services/admin.service.ts

@ -15,7 +15,7 @@ import {
Filter, Filter,
UniqueAsset UniqueAsset
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { DataSource, MarketData, Platform } from '@prisma/client'; import { DataSource, MarketData, Platform, Prisma } from '@prisma/client';
import { JobStatus } from 'bull'; import { JobStatus } from 'bull';
import { format, parseISO } from 'date-fns'; import { format, parseISO } from 'date-fns';
import { Observable, map } from 'rxjs'; import { Observable, map } from 'rxjs';
@ -70,10 +70,14 @@ export class AdminService {
public fetchAdminMarketData({ public fetchAdminMarketData({
filters, filters,
skip, skip,
sortColumn,
sortDirection,
take take
}: { }: {
filters?: Filter[]; filters?: Filter[];
skip?: number; skip?: number;
sortColumn?: string;
sortDirection?: Prisma.SortOrder;
take: number; take: number;
}) { }) {
let params = this.dataService.buildFiltersAsQueryParams({ filters }); let params = this.dataService.buildFiltersAsQueryParams({ filters });
@ -82,6 +86,14 @@ export class AdminService {
params = params.append('skip', skip); params = params.append('skip', skip);
} }
if (sortColumn) {
params = params.append('sortColumn', sortColumn);
}
if (sortDirection) {
params = params.append('sortDirection', sortDirection);
}
params = params.append('take', take); params = params.append('take', take);
return this.http.get<AdminMarketData>('/api/v1/admin/market-data', { return this.http.get<AdminMarketData>('/api/v1/admin/market-data', {

Loading…
Cancel
Save