diff --git a/CHANGELOG.md b/CHANGELOG.md index 0344f8d47..61b8fcc72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Added a filter by data source for the asset profiles in the admin control panel - Extended the data providers management of the admin control panel by every data provider in use ### Changed diff --git a/apps/api/src/app/admin/admin.controller.ts b/apps/api/src/app/admin/admin.controller.ts index e473813e9..27cc088d1 100644 --- a/apps/api/src/app/admin/admin.controller.ts +++ b/apps/api/src/app/admin/admin.controller.ts @@ -197,6 +197,7 @@ export class AdminController { @UseGuards(AuthGuard('jwt'), HasPermissionGuard) public async getMarketData( @Query('assetSubClasses') filterByAssetSubClasses?: string, + @Query('dataSource') filterByDataSource?: string, @Query('presetId') presetId?: MarketDataPreset, @Query('query') filterBySearchQuery?: string, @Query('skip') skip?: number, @@ -206,6 +207,7 @@ export class AdminController { ): Promise { const filters = this.apiService.buildFiltersFromQueryParams({ filterByAssetSubClasses, + filterByDataSource, filterBySearchQuery }); diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts index bce603289..d07e74013 100644 --- a/apps/api/src/app/admin/admin.service.ts +++ b/apps/api/src/app/admin/admin.service.ts @@ -218,12 +218,12 @@ export class AdminService { return type === 'SEARCH_QUERY'; })?.id; - const { ASSET_SUB_CLASS: filtersByAssetSubClass } = groupBy( - filters, - ({ type }) => { - return type; - } - ); + const { + ASSET_SUB_CLASS: filtersByAssetSubClass, + DATA_SOURCE: filtersByDataSource + } = groupBy(filters, ({ type }) => { + return type; + }); const marketDataItems = await this.prismaService.marketData.groupBy({ _count: true, @@ -234,6 +234,10 @@ export class AdminService { where.assetSubClass = AssetSubClass[filtersByAssetSubClass[0].id]; } + if (filtersByDataSource) { + where.dataSource = DataSource[filtersByDataSource[0].id]; + } + if (searchQuery) { where.OR = [ { id: { mode: 'insensitive', startsWith: searchQuery } }, diff --git a/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts b/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts index 6a809a10f..4e410c3a0 100644 --- a/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts +++ b/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts @@ -103,39 +103,46 @@ export class GfAdminMarketDataComponent @ViewChild(MatSort) sort: MatSort; public activeFilters: Filter[] = []; - public allFilters: Filter[] = Object.keys(AssetSubClass) - .filter((assetSubClass) => { - return assetSubClass !== 'CASH'; - }) - .map((assetSubClass) => { + public allFilters: Filter[] = [ + ...Object.keys(AssetSubClass) + .filter((assetSubClass) => { + return assetSubClass !== 'CASH'; + }) + .map((assetSubClass) => { + return { + id: assetSubClass.toString(), + label: translate(assetSubClass), + type: 'ASSET_SUB_CLASS' as Filter['type'] + }; + }), + ...Object.keys(DataSource).map((dataSource) => { return { - id: assetSubClass.toString(), - label: translate(assetSubClass), - type: 'ASSET_SUB_CLASS' as Filter['type'] + id: dataSource.toString(), + label: dataSource, + type: 'DATA_SOURCE' as Filter['type'] }; - }) - .concat([ - { - id: 'BENCHMARKS', - label: $localize`Benchmarks`, - type: 'PRESET_ID' as Filter['type'] - }, - { - id: 'CURRENCIES', - label: $localize`Currencies`, - type: 'PRESET_ID' as Filter['type'] - }, - { - id: 'ETF_WITHOUT_COUNTRIES', - label: $localize`ETFs without Countries`, - type: 'PRESET_ID' as Filter['type'] - }, - { - id: 'ETF_WITHOUT_SECTORS', - label: $localize`ETFs without Sectors`, - type: 'PRESET_ID' as Filter['type'] - } - ]); + }), + { + id: 'BENCHMARKS', + label: $localize`Benchmarks`, + type: 'PRESET_ID' as Filter['type'] + }, + { + id: 'CURRENCIES', + label: $localize`Currencies`, + type: 'PRESET_ID' as Filter['type'] + }, + { + id: 'ETF_WITHOUT_COUNTRIES', + label: $localize`ETFs without Countries`, + type: 'PRESET_ID' as Filter['type'] + }, + { + id: 'ETF_WITHOUT_SECTORS', + label: $localize`ETFs without Sectors`, + type: 'PRESET_ID' as Filter['type'] + } + ]; public benchmarks: Partial[]; public currentDataSource: DataSource; public currentSymbol: string; diff --git a/libs/ui/src/lib/i18n.ts b/libs/ui/src/lib/i18n.ts index 8007dc53e..e17cc6771 100644 --- a/libs/ui/src/lib/i18n.ts +++ b/libs/ui/src/lib/i18n.ts @@ -12,6 +12,7 @@ const locales = { DATA_IMPORT_AND_EXPORT_TOOLTIP_BASIC: $localize`Switch to Ghostfolio Premium or Ghostfolio Open Source easily`, DATA_IMPORT_AND_EXPORT_TOOLTIP_OSS: $localize`Switch to Ghostfolio Premium easily`, DATA_IMPORT_AND_EXPORT_TOOLTIP_PREMIUM: $localize`Switch to Ghostfolio Open Source or Ghostfolio Basic easily`, + DATA_SOURCE: $localize`Data Source`, EMERGENCY_FUND: $localize`Emergency Fund`, EXCLUDE_FROM_ANALYSIS: $localize`Exclude from Analysis`, Global: $localize`Global`,