Feature/support filtering by asset class on the allocations page (#926)
* Support filtering by asset class * Update changelog
This commit is contained in:
parent
4a123c38f2
commit
5cb6e5dec6
@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Added groups to the activities filter component
|
- Added groups to the activities filter component
|
||||||
|
- Added support for filtering by asset class on the allocations page
|
||||||
|
|
||||||
## 1.148.0 - 14.05.2022
|
## 1.148.0 - 14.05.2022
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import { Filter } from '@ghostfolio/common/interfaces';
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { Account, Order, Platform, Prisma } from '@prisma/client';
|
import { Account, Order, Platform, Prisma } from '@prisma/client';
|
||||||
import Big from 'big.js';
|
import Big from 'big.js';
|
||||||
|
import { groupBy } from 'lodash';
|
||||||
|
|
||||||
import { CashDetails } from './interfaces/cash-details.interface';
|
import { CashDetails } from './interfaces/cash-details.interface';
|
||||||
|
|
||||||
@ -116,15 +117,19 @@ export class AccountService {
|
|||||||
|
|
||||||
const where: Prisma.AccountWhereInput = { userId };
|
const where: Prisma.AccountWhereInput = { userId };
|
||||||
|
|
||||||
if (filters?.length > 0) {
|
const {
|
||||||
|
ACCOUNT: filtersByAccount,
|
||||||
|
ASSET_CLASS: filtersByAssetClass,
|
||||||
|
TAG: filtersByTag
|
||||||
|
} = groupBy(filters, (filter) => {
|
||||||
|
return filter.type;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (filtersByAccount?.length > 0) {
|
||||||
where.id = {
|
where.id = {
|
||||||
in: filters
|
in: filtersByAccount.map(({ id }) => {
|
||||||
.filter(({ type }) => {
|
return id;
|
||||||
return type === 'ACCOUNT';
|
})
|
||||||
})
|
|
||||||
.map(({ id }) => {
|
|
||||||
return id;
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,12 +188,13 @@ export class OrderService {
|
|||||||
}): Promise<Activity[]> {
|
}): Promise<Activity[]> {
|
||||||
const where: Prisma.OrderWhereInput = { userId };
|
const where: Prisma.OrderWhereInput = { userId };
|
||||||
|
|
||||||
const { ACCOUNT: filtersByAccount, TAG: filtersByTag } = groupBy(
|
const {
|
||||||
filters,
|
ACCOUNT: filtersByAccount,
|
||||||
(filter) => {
|
ASSET_CLASS: filtersByAssetClass,
|
||||||
return filter.type;
|
TAG: filtersByTag
|
||||||
}
|
} = groupBy(filters, (filter) => {
|
||||||
);
|
return filter.type;
|
||||||
|
});
|
||||||
|
|
||||||
if (filtersByAccount?.length > 0) {
|
if (filtersByAccount?.length > 0) {
|
||||||
where.accountId = {
|
where.accountId = {
|
||||||
@ -207,6 +208,34 @@ export class OrderService {
|
|||||||
where.isDraft = false;
|
where.isDraft = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filtersByAssetClass?.length > 0) {
|
||||||
|
where.SymbolProfile = {
|
||||||
|
OR: [
|
||||||
|
{
|
||||||
|
AND: [
|
||||||
|
{
|
||||||
|
OR: filtersByAssetClass.map(({ id }) => {
|
||||||
|
return { assetClass: AssetClass[id] };
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SymbolProfileOverrides: {
|
||||||
|
is: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SymbolProfileOverrides: {
|
||||||
|
OR: filtersByAssetClass.map(({ id }) => {
|
||||||
|
return { assetClass: AssetClass[id] };
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (filtersByTag?.length > 0) {
|
if (filtersByTag?.length > 0) {
|
||||||
where.tags = {
|
where.tags = {
|
||||||
some: {
|
some: {
|
||||||
|
@ -107,12 +107,14 @@ export class PortfolioController {
|
|||||||
public async getDetails(
|
public async getDetails(
|
||||||
@Headers('impersonation-id') impersonationId: string,
|
@Headers('impersonation-id') impersonationId: string,
|
||||||
@Query('accounts') filterByAccounts?: string,
|
@Query('accounts') filterByAccounts?: string,
|
||||||
|
@Query('assetClasses') filterByAssetClasses?: string,
|
||||||
@Query('range') range?: DateRange,
|
@Query('range') range?: DateRange,
|
||||||
@Query('tags') filterByTags?: string
|
@Query('tags') filterByTags?: string
|
||||||
): Promise<PortfolioDetails & { hasError: boolean }> {
|
): Promise<PortfolioDetails & { hasError: boolean }> {
|
||||||
let hasError = false;
|
let hasError = false;
|
||||||
|
|
||||||
const accountIds = filterByAccounts?.split(',') ?? [];
|
const accountIds = filterByAccounts?.split(',') ?? [];
|
||||||
|
const assetClasses = filterByAssetClasses?.split(',') ?? [];
|
||||||
const tagIds = filterByTags?.split(',') ?? [];
|
const tagIds = filterByTags?.split(',') ?? [];
|
||||||
|
|
||||||
const filters: Filter[] = [
|
const filters: Filter[] = [
|
||||||
@ -122,6 +124,12 @@ export class PortfolioController {
|
|||||||
type: 'ACCOUNT'
|
type: 'ACCOUNT'
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
|
...assetClasses.map((assetClass) => {
|
||||||
|
return <Filter>{
|
||||||
|
id: assetClass,
|
||||||
|
type: 'ASSET_CLASS'
|
||||||
|
};
|
||||||
|
}),
|
||||||
...tagIds.map((tagId) => {
|
...tagIds.map((tagId) => {
|
||||||
return <Filter>{
|
return <Filter>{
|
||||||
id: tagId,
|
id: tagId,
|
||||||
|
@ -441,7 +441,12 @@ export class PortfolioService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aFilters?.length === 0) {
|
if (
|
||||||
|
aFilters?.length === 0 ||
|
||||||
|
(aFilters?.length === 1 &&
|
||||||
|
aFilters[0].type === 'ASSET_CLASS' &&
|
||||||
|
aFilters[0].id === 'CASH')
|
||||||
|
) {
|
||||||
const cashPositions = await this.getCashPositions({
|
const cashPositions = await this.getCashPositions({
|
||||||
cashDetails,
|
cashDetails,
|
||||||
emergencyFund,
|
emergencyFund,
|
||||||
|
@ -172,6 +172,15 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const assetClassFilters: Filter[] = [];
|
||||||
|
for (const assetClass of Object.keys(AssetClass)) {
|
||||||
|
assetClassFilters.push({
|
||||||
|
id: assetClass,
|
||||||
|
label: assetClass,
|
||||||
|
type: 'ASSET_CLASS'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const tagFilters: Filter[] = this.user.tags.map(({ id, name }) => {
|
const tagFilters: Filter[] = this.user.tags.map(({ id, name }) => {
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
@ -180,7 +189,11 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
this.allFilters = [...accountFilters, ...tagFilters];
|
this.allFilters = [
|
||||||
|
...accountFilters,
|
||||||
|
...assetClassFilters,
|
||||||
|
...tagFilters
|
||||||
|
];
|
||||||
|
|
||||||
this.changeDetectorRef.markForCheck();
|
this.changeDetectorRef.markForCheck();
|
||||||
}
|
}
|
||||||
|
@ -187,12 +187,13 @@ export class DataService {
|
|||||||
let params = new HttpParams();
|
let params = new HttpParams();
|
||||||
|
|
||||||
if (filters?.length > 0) {
|
if (filters?.length > 0) {
|
||||||
const { ACCOUNT: filtersByAccount, TAG: filtersByTag } = groupBy(
|
const {
|
||||||
filters,
|
ACCOUNT: filtersByAccount,
|
||||||
(filter) => {
|
ASSET_CLASS: filtersByAssetClass,
|
||||||
return filter.type;
|
TAG: filtersByTag
|
||||||
}
|
} = groupBy(filters, (filter) => {
|
||||||
);
|
return filter.type;
|
||||||
|
});
|
||||||
|
|
||||||
if (filtersByAccount) {
|
if (filtersByAccount) {
|
||||||
params = params.append(
|
params = params.append(
|
||||||
@ -205,6 +206,17 @@ export class DataService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filtersByAssetClass) {
|
||||||
|
params = params.append(
|
||||||
|
'assetClasses',
|
||||||
|
filtersByAssetClass
|
||||||
|
.map(({ id }) => {
|
||||||
|
return id;
|
||||||
|
})
|
||||||
|
.join(',')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (filtersByTag) {
|
if (filtersByTag) {
|
||||||
params = params.append(
|
params = params.append(
|
||||||
'tags',
|
'tags',
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export interface Filter {
|
export interface Filter {
|
||||||
id: string;
|
id: string;
|
||||||
label?: string;
|
label?: string;
|
||||||
type: 'ACCOUNT' | 'SYMBOL' | 'TAG';
|
type: 'ACCOUNT' | 'ASSET_CLASS' | 'SYMBOL' | 'TAG';
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user