Browse Source

Merge branch 'main' into xray-subpage

pull/4037/head
Thomas Kaul 10 months ago
committed by GitHub
parent
commit
ca737a6525
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 25
      apps/api/src/app/portfolio/portfolio.controller.ts
  3. 8
      apps/api/src/app/user/update-user-setting.dto.ts
  4. 14
      apps/client/src/app/components/header/header.component.ts
  5. 2
      apps/client/src/app/services/data.service.ts
  6. 14
      apps/client/src/app/services/user/user.service.ts
  7. 108
      apps/client/src/locales/messages.it.xlf
  8. 2
      libs/common/src/lib/interfaces/user-settings.interface.ts
  9. 94
      libs/ui/src/lib/assistant/assistant.component.ts
  10. 28
      libs/ui/src/lib/assistant/assistant.html

2
CHANGELOG.md

@ -9,7 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- Extended the assistant by a holding selector
- Separated the _FIRE_ / _X-ray_ page - Separated the _FIRE_ / _X-ray_ page
- Improved the language localization for Italian (`it`)
## 2.122.0 - 2024-11-07 ## 2.122.0 - 2024-11-07

25
apps/api/src/app/portfolio/portfolio.controller.ts

@ -74,12 +74,15 @@ export class PortfolioController {
@Get('details') @Get('details')
@UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseGuards(AuthGuard('jwt'), HasPermissionGuard)
@UseInterceptors(RedactValuesInResponseInterceptor) @UseInterceptors(RedactValuesInResponseInterceptor)
@UseInterceptors(TransformDataSourceInRequestInterceptor)
@UseInterceptors(TransformDataSourceInResponseInterceptor) @UseInterceptors(TransformDataSourceInResponseInterceptor)
public async getDetails( public async getDetails(
@Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string,
@Query('accounts') filterByAccounts?: string, @Query('accounts') filterByAccounts?: string,
@Query('assetClasses') filterByAssetClasses?: string, @Query('assetClasses') filterByAssetClasses?: string,
@Query('dataSource') filterByDataSource?: string,
@Query('range') dateRange: DateRange = 'max', @Query('range') dateRange: DateRange = 'max',
@Query('symbol') filterBySymbol?: string,
@Query('tags') filterByTags?: string, @Query('tags') filterByTags?: string,
@Query('withMarkets') withMarketsParam = 'false' @Query('withMarkets') withMarketsParam = 'false'
): Promise<PortfolioDetails & { hasError: boolean }> { ): Promise<PortfolioDetails & { hasError: boolean }> {
@ -95,6 +98,8 @@ export class PortfolioController {
const filters = this.apiService.buildFiltersFromQueryParams({ const filters = this.apiService.buildFiltersFromQueryParams({
filterByAccounts, filterByAccounts,
filterByAssetClasses, filterByAssetClasses,
filterByDataSource,
filterBySymbol,
filterByTags filterByTags
}); });
@ -289,17 +294,22 @@ export class PortfolioController {
@Get('dividends') @Get('dividends')
@UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseGuards(AuthGuard('jwt'), HasPermissionGuard)
@UseInterceptors(TransformDataSourceInRequestInterceptor)
public async getDividends( public async getDividends(
@Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string,
@Query('accounts') filterByAccounts?: string, @Query('accounts') filterByAccounts?: string,
@Query('assetClasses') filterByAssetClasses?: string, @Query('assetClasses') filterByAssetClasses?: string,
@Query('dataSource') filterByDataSource?: string,
@Query('groupBy') groupBy?: GroupBy, @Query('groupBy') groupBy?: GroupBy,
@Query('range') dateRange: DateRange = 'max', @Query('range') dateRange: DateRange = 'max',
@Query('symbol') filterBySymbol?: string,
@Query('tags') filterByTags?: string @Query('tags') filterByTags?: string
): Promise<PortfolioDividends> { ): Promise<PortfolioDividends> {
const filters = this.apiService.buildFiltersFromQueryParams({ const filters = this.apiService.buildFiltersFromQueryParams({
filterByAccounts, filterByAccounts,
filterByAssetClasses, filterByAssetClasses,
filterByDataSource,
filterBySymbol,
filterByTags filterByTags
}); });
@ -356,21 +366,26 @@ export class PortfolioController {
@Get('holdings') @Get('holdings')
@UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseGuards(AuthGuard('jwt'), HasPermissionGuard)
@UseInterceptors(RedactValuesInResponseInterceptor) @UseInterceptors(RedactValuesInResponseInterceptor)
@UseInterceptors(TransformDataSourceInRequestInterceptor)
@UseInterceptors(TransformDataSourceInResponseInterceptor) @UseInterceptors(TransformDataSourceInResponseInterceptor)
public async getHoldings( public async getHoldings(
@Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string,
@Query('accounts') filterByAccounts?: string, @Query('accounts') filterByAccounts?: string,
@Query('assetClasses') filterByAssetClasses?: string, @Query('assetClasses') filterByAssetClasses?: string,
@Query('dataSource') filterByDataSource?: string,
@Query('holdingType') filterByHoldingType?: string, @Query('holdingType') filterByHoldingType?: string,
@Query('query') filterBySearchQuery?: string, @Query('query') filterBySearchQuery?: string,
@Query('range') dateRange: DateRange = 'max', @Query('range') dateRange: DateRange = 'max',
@Query('symbol') filterBySymbol?: string,
@Query('tags') filterByTags?: string @Query('tags') filterByTags?: string
): Promise<PortfolioHoldingsResponse> { ): Promise<PortfolioHoldingsResponse> {
const filters = this.apiService.buildFiltersFromQueryParams({ const filters = this.apiService.buildFiltersFromQueryParams({
filterByAccounts, filterByAccounts,
filterByAssetClasses, filterByAssetClasses,
filterByDataSource,
filterByHoldingType, filterByHoldingType,
filterBySearchQuery, filterBySearchQuery,
filterBySymbol,
filterByTags filterByTags
}); });
@ -386,17 +401,22 @@ export class PortfolioController {
@Get('investments') @Get('investments')
@UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseGuards(AuthGuard('jwt'), HasPermissionGuard)
@UseInterceptors(TransformDataSourceInRequestInterceptor)
public async getInvestments( public async getInvestments(
@Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string,
@Query('accounts') filterByAccounts?: string, @Query('accounts') filterByAccounts?: string,
@Query('assetClasses') filterByAssetClasses?: string, @Query('assetClasses') filterByAssetClasses?: string,
@Query('dataSource') filterByDataSource?: string,
@Query('groupBy') groupBy?: GroupBy, @Query('groupBy') groupBy?: GroupBy,
@Query('range') dateRange: DateRange = 'max', @Query('range') dateRange: DateRange = 'max',
@Query('symbol') filterBySymbol?: string,
@Query('tags') filterByTags?: string @Query('tags') filterByTags?: string
): Promise<PortfolioInvestments> { ): Promise<PortfolioInvestments> {
const filters = this.apiService.buildFiltersFromQueryParams({ const filters = this.apiService.buildFiltersFromQueryParams({
filterByAccounts, filterByAccounts,
filterByAssetClasses, filterByAssetClasses,
filterByDataSource,
filterBySymbol,
filterByTags filterByTags
}); });
@ -451,13 +471,16 @@ export class PortfolioController {
@Get('performance') @Get('performance')
@UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseGuards(AuthGuard('jwt'), HasPermissionGuard)
@UseInterceptors(PerformanceLoggingInterceptor) @UseInterceptors(PerformanceLoggingInterceptor)
@UseInterceptors(TransformDataSourceInRequestInterceptor)
@UseInterceptors(TransformDataSourceInResponseInterceptor) @UseInterceptors(TransformDataSourceInResponseInterceptor)
@Version('2') @Version('2')
public async getPerformanceV2( public async getPerformanceV2(
@Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string,
@Query('accounts') filterByAccounts?: string, @Query('accounts') filterByAccounts?: string,
@Query('assetClasses') filterByAssetClasses?: string, @Query('assetClasses') filterByAssetClasses?: string,
@Query('dataSource') filterByDataSource?: string,
@Query('range') dateRange: DateRange = 'max', @Query('range') dateRange: DateRange = 'max',
@Query('symbol') filterBySymbol?: string,
@Query('tags') filterByTags?: string, @Query('tags') filterByTags?: string,
@Query('withExcludedAccounts') withExcludedAccountsParam = 'false' @Query('withExcludedAccounts') withExcludedAccountsParam = 'false'
): Promise<PortfolioPerformanceResponse> { ): Promise<PortfolioPerformanceResponse> {
@ -466,6 +489,8 @@ export class PortfolioController {
const filters = this.apiService.buildFiltersFromQueryParams({ const filters = this.apiService.buildFiltersFromQueryParams({
filterByAccounts, filterByAccounts,
filterByAssetClasses, filterByAssetClasses,
filterByDataSource,
filterBySymbol,
filterByTags filterByTags
}); });

8
apps/api/src/app/user/update-user-setting.dto.ts

@ -64,6 +64,14 @@ export class UpdateUserSettingDto {
@IsOptional() @IsOptional()
'filters.assetClasses'?: string[]; 'filters.assetClasses'?: string[];
@IsString()
@IsOptional()
'filters.dataSource'?: string;
@IsString()
@IsOptional()
'filters.symbol'?: string;
@IsArray() @IsArray()
@IsOptional() @IsOptional()
'filters.tags'?: string[]; 'filters.tags'?: string[];

14
apps/client/src/app/components/header/header.component.ts

@ -175,17 +175,17 @@ export class HeaderComponent implements OnChanges {
const userSetting: UpdateUserSettingDto = {}; const userSetting: UpdateUserSettingDto = {};
for (const filter of filters) { for (const filter of filters) {
let filtersType: string;
if (filter.type === 'ACCOUNT') { if (filter.type === 'ACCOUNT') {
filtersType = 'accounts'; userSetting['filters.accounts'] = filter.id ? [filter.id] : null;
} else if (filter.type === 'ASSET_CLASS') { } else if (filter.type === 'ASSET_CLASS') {
filtersType = 'assetClasses'; userSetting['filters.assetClasses'] = filter.id ? [filter.id] : null;
} else if (filter.type === 'DATA_SOURCE') {
userSetting['filters.dataSource'] = filter.id ? filter.id : null;
} else if (filter.type === 'SYMBOL') {
userSetting['filters.symbol'] = filter.id ? filter.id : null;
} else if (filter.type === 'TAG') { } else if (filter.type === 'TAG') {
filtersType = 'tags'; userSetting['filters.tags'] = filter.id ? [filter.id] : null;
} }
userSetting[`filters.${filtersType}`] = filter.id ? [filter.id] : null;
} }
this.dataService this.dataService

2
apps/client/src/app/services/data.service.ts

@ -532,7 +532,7 @@ export class DataService {
}: { }: {
filters?: Filter[]; filters?: Filter[];
range?: DateRange; range?: DateRange;
}) { } = {}) {
let params = this.buildFiltersAsQueryParams({ filters }); let params = this.buildFiltersAsQueryParams({ filters });
if (range) { if (range) {

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

@ -65,6 +65,20 @@ export class UserService extends ObservableStore<UserStoreState> {
}); });
} }
if (user?.settings['filters.dataSource']) {
filters.push({
id: user.settings['filters.dataSource'],
type: 'DATA_SOURCE'
});
}
if (user?.settings['filters.symbol']) {
filters.push({
id: user.settings['filters.symbol'],
type: 'SYMBOL'
});
}
if (user?.settings['filters.tags']) { if (user?.settings['filters.tags']) {
filters.push({ filters.push({
id: user.settings['filters.tags'][0], id: user.settings['filters.tags'][0],

108
apps/client/src/locales/messages.it.xlf

@ -2872,7 +2872,7 @@
</trans-unit> </trans-unit>
<trans-unit id="82fe55446d3fad9db11eb79caaedf325587b9c0a" datatype="html"> <trans-unit id="82fe55446d3fad9db11eb79caaedf325587b9c0a" datatype="html">
<source> Hello, <x id="INTERPOLATION" equiv-text="{{ publicPortfolioDetails?.alias ?? &apos;someone&apos; }}"/> has shared a <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>Portfolio<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> with you! </source> <source> Hello, <x id="INTERPOLATION" equiv-text="{{ publicPortfolioDetails?.alias ?? &apos;someone&apos; }}"/> has shared a <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>Portfolio<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> with you! </source>
<target state="new">Salve, <x id="INTERPOLATION" equiv-text="{{ portfolioPublicDetails?.alias ?? &apos;someone&apos; }}"/> ha condiviso un <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>Portafoglio<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> con te! </target> <target state="translated">Salve, <x id="INTERPOLATION" equiv-text="{{ portfolioPublicDetails?.alias ?? &apos;someone&apos; }}"/> ha condiviso un <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>Portafoglio<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> con te! </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">4</context> <context context-type="linenumber">4</context>
@ -5881,7 +5881,7 @@
</trans-unit> </trans-unit>
<trans-unit id="50760c2140335b2324deaee120f40d9aa64b3238" datatype="html"> <trans-unit id="50760c2140335b2324deaee120f40d9aa64b3238" datatype="html">
<source>Currency Cluster Risks</source> <source>Currency Cluster Risks</source>
<target state="new">Currency Cluster Risks</target> <target state="translated">Rischio di Concentrazione Valutario</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/fire/fire-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/portfolio/fire/fire-page.html</context>
<context context-type="linenumber">141</context> <context context-type="linenumber">141</context>
@ -5889,7 +5889,7 @@
</trans-unit> </trans-unit>
<trans-unit id="c7b797e5df289241021db16010efb6ac3c6cfb86" datatype="html"> <trans-unit id="c7b797e5df289241021db16010efb6ac3c6cfb86" datatype="html">
<source>Account Cluster Risks</source> <source>Account Cluster Risks</source>
<target state="new">Account Cluster Risks</target> <target state="translated">Rischi di Concentrazione dei Conti</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/fire/fire-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/portfolio/fire/fire-page.html</context>
<context context-type="linenumber">160</context> <context context-type="linenumber">160</context>
@ -6237,7 +6237,7 @@
</trans-unit> </trans-unit>
<trans-unit id="97bad3b5e318e5c7c755cd99062f2973efcf17e5" datatype="html"> <trans-unit id="97bad3b5e318e5c7c755cd99062f2973efcf17e5" datatype="html">
<source>Restricted view</source> <source>Restricted view</source>
<target state="new">Restricted view</target> <target state="translated">Vista limitata</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/access-table/access-table.component.html</context> <context context-type="sourcefile">apps/client/src/app/components/access-table/access-table.component.html</context>
<context context-type="linenumber">26</context> <context context-type="linenumber">26</context>
@ -6357,7 +6357,7 @@
</trans-unit> </trans-unit>
<trans-unit id="7451343426685730864" datatype="html"> <trans-unit id="7451343426685730864" datatype="html">
<source>WTD</source> <source>WTD</source>
<target state="new">WTD</target> <target state="translated">Settimana corrente</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/assistant/assistant.component.ts</context> <context context-type="sourcefile">libs/ui/src/lib/assistant/assistant.component.ts</context>
<context context-type="linenumber">212</context> <context context-type="linenumber">212</context>
@ -6373,7 +6373,7 @@
</trans-unit> </trans-unit>
<trans-unit id="399380803601269035" datatype="html"> <trans-unit id="399380803601269035" datatype="html">
<source>MTD</source> <source>MTD</source>
<target state="new">MTD</target> <target state="translated">Mese corrente</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/assistant/assistant.component.ts</context> <context context-type="sourcefile">libs/ui/src/lib/assistant/assistant.component.ts</context>
<context context-type="linenumber">216</context> <context context-type="linenumber">216</context>
@ -6597,7 +6597,7 @@
</trans-unit> </trans-unit>
<trans-unit id="ebf471e68247ca2110cdc5c98538e2e2bbf6e56e" datatype="html"> <trans-unit id="ebf471e68247ca2110cdc5c98538e2e2bbf6e56e" datatype="html">
<source>{VAR_PLURAL, plural, =1 {activity} other {activities}}</source> <source>{VAR_PLURAL, plural, =1 {activity} other {activities}}</source>
<target state="new">{VAR_PLURAL, plural, =1 {activity} other {activities}}</target> <target state="translated">{VAR_PLURAL, plural, =1 {attivit&agrave;} other {attivit&agrave;}}</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html</context> <context context-type="sourcefile">apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html</context>
<context context-type="linenumber">14</context> <context context-type="linenumber">14</context>
@ -6781,7 +6781,7 @@
</trans-unit> </trans-unit>
<trans-unit id="4622218074144052433" datatype="html"> <trans-unit id="4622218074144052433" datatype="html">
<source>Family Office</source> <source>Family Office</source>
<target state="new">Family Office</target> <target state="translated">Ufficio familiare</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts</context>
<context context-type="linenumber">87</context> <context context-type="linenumber">87</context>
@ -6837,7 +6837,7 @@
</trans-unit> </trans-unit>
<trans-unit id="2657610384052021428" datatype="html"> <trans-unit id="2657610384052021428" datatype="html">
<source>User Experience</source> <source>User Experience</source>
<target state="new">User Experience</target> <target state="translated">Esperienza Utente</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts</context>
<context context-type="linenumber">98</context> <context context-type="linenumber">98</context>
@ -7061,7 +7061,7 @@
</trans-unit> </trans-unit>
<trans-unit id="665692df9ab12bc228c1276f7d04e97902ff9afc" datatype="html"> <trans-unit id="665692df9ab12bc228c1276f7d04e97902ff9afc" datatype="html">
<source>Copy link to clipboard</source> <source>Copy link to clipboard</source>
<target state="new">Copy link to clipboard</target> <target state="translated">Copia link negli appunti</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/access-table/access-table.component.html</context> <context context-type="sourcefile">apps/client/src/app/components/access-table/access-table.component.html</context>
<context context-type="linenumber">70</context> <context context-type="linenumber">70</context>
@ -7069,7 +7069,7 @@
</trans-unit> </trans-unit>
<trans-unit id="306e3758e5303c780f0984c003e6283d49796f79" datatype="html"> <trans-unit id="306e3758e5303c780f0984c003e6283d49796f79" datatype="html">
<source>Portfolio Snapshot</source> <source>Portfolio Snapshot</source>
<target state="new">Portfolio Snapshot</target> <target state="translated">Stato del Portfolio</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-jobs/admin-jobs.html</context> <context context-type="sourcefile">apps/client/src/app/components/admin-jobs/admin-jobs.html</context>
<context context-type="linenumber">39</context> <context context-type="linenumber">39</context>
@ -7077,7 +7077,7 @@
</trans-unit> </trans-unit>
<trans-unit id="76897e07c5670ce3b7710cc10c5e1c08b5f6a83a" datatype="html"> <trans-unit id="76897e07c5670ce3b7710cc10c5e1c08b5f6a83a" datatype="html">
<source><x id="START_BLOCK_IF" equiv-text="Currency !== SymbolProfile?.currency ) {"/> Change with currency effect <x id="CLOSE_BLOCK_IF" equiv-text="}"/><x id="START_BLOCK_ELSE" equiv-text="@else {"/> Change <x id="CLOSE_BLOCK_ELSE" equiv-text="}"/></source> <source><x id="START_BLOCK_IF" equiv-text="Currency !== SymbolProfile?.currency ) {"/> Change with currency effect <x id="CLOSE_BLOCK_IF" equiv-text="}"/><x id="START_BLOCK_ELSE" equiv-text="@else {"/> Change <x id="CLOSE_BLOCK_ELSE" equiv-text="}"/></source>
<target state="new"><x id="START_BLOCK_IF" equiv-text="Currency !== SymbolProfile?.currency ) {"/> Change with currency effect <x id="CLOSE_BLOCK_IF" equiv-text="}"/><x id="START_BLOCK_ELSE" equiv-text="@else {"/> Change <x id="CLOSE_BLOCK_ELSE" equiv-text="}"/></target> <target state="translated"><x id="START_BLOCK_IF" equiv-text="Currency !== SymbolProfile?.currency ) {"/> Cambio con effetto valuta <x id="CLOSE_BLOCK_IF" equiv-text="}"/><x id="START_BLOCK_ELSE" equiv-text="@else {"/> Cambia <x id="CLOSE_BLOCK_ELSE" equiv-text="}"/></target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html</context> <context context-type="sourcefile">apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html</context>
<context context-type="linenumber">50</context> <context context-type="linenumber">50</context>
@ -7085,7 +7085,7 @@
</trans-unit> </trans-unit>
<trans-unit id="65ff514a2e167229e1a34b3712f2cf2908576d0f" datatype="html"> <trans-unit id="65ff514a2e167229e1a34b3712f2cf2908576d0f" datatype="html">
<source><x id="START_BLOCK_IF" equiv-text="Currency !== SymbolProfile?.currency ) {"/> Performance with currency effect <x id="CLOSE_BLOCK_IF" equiv-text="}"/><x id="START_BLOCK_ELSE" equiv-text="@else {"/> Performance <x id="CLOSE_BLOCK_ELSE" equiv-text="}"/></source> <source><x id="START_BLOCK_IF" equiv-text="Currency !== SymbolProfile?.currency ) {"/> Performance with currency effect <x id="CLOSE_BLOCK_IF" equiv-text="}"/><x id="START_BLOCK_ELSE" equiv-text="@else {"/> Performance <x id="CLOSE_BLOCK_ELSE" equiv-text="}"/></source>
<target state="new"><x id="START_BLOCK_IF" equiv-text="Currency !== SymbolProfile?.currency ) {"/> Performance with currency effect <x id="CLOSE_BLOCK_IF" equiv-text="}"/><x id="START_BLOCK_ELSE" equiv-text="@else {"/> Performance <x id="CLOSE_BLOCK_ELSE" equiv-text="}"/></target> <target state="translated"><x id="START_BLOCK_IF" equiv-text="Currency !== SymbolProfile?.currency ) {"/> Prestazioni con effetto valuta <x id="CLOSE_BLOCK_IF" equiv-text="}"/><x id="START_BLOCK_ELSE" equiv-text="@else {"/> Prestazioni <x id="CLOSE_BLOCK_ELSE" equiv-text="}"/></target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html</context> <context context-type="sourcefile">apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html</context>
<context context-type="linenumber">69</context> <context context-type="linenumber">69</context>
@ -7093,7 +7093,7 @@
</trans-unit> </trans-unit>
<trans-unit id="5502bf2eace842803c7b3f5ce5f600e102d3424a" datatype="html"> <trans-unit id="5502bf2eace842803c7b3f5ce5f600e102d3424a" datatype="html">
<source>Threshold Min</source> <source>Threshold Min</source>
<target state="new">Threshold Min</target> <target state="translated">Soglia Minima</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html</context> <context context-type="sourcefile">apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html</context>
<context context-type="linenumber">9</context> <context context-type="linenumber">9</context>
@ -7101,7 +7101,7 @@
</trans-unit> </trans-unit>
<trans-unit id="012b48ee5281a77c66760b2007c3ccd7e34aa340" datatype="html"> <trans-unit id="012b48ee5281a77c66760b2007c3ccd7e34aa340" datatype="html">
<source>Threshold Max</source> <source>Threshold Max</source>
<target state="new">Threshold Max</target> <target state="translated">Soglia Massima</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html</context> <context context-type="sourcefile">apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html</context>
<context context-type="linenumber">44</context> <context context-type="linenumber">44</context>
@ -7109,7 +7109,7 @@
</trans-unit> </trans-unit>
<trans-unit id="f4e529ae5ffd73001d1ff4bbdeeb0a72e342e5c8" datatype="html"> <trans-unit id="f4e529ae5ffd73001d1ff4bbdeeb0a72e342e5c8" datatype="html">
<source>Close</source> <source>Close</source>
<target state="new">Close</target> <target state="translated">Chiudi</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html</context> <context context-type="sourcefile">apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html</context>
<context context-type="linenumber">77</context> <context context-type="linenumber">77</context>
@ -7117,7 +7117,7 @@
</trans-unit> </trans-unit>
<trans-unit id="072d4d4ec83a5a97345a1c13b90c213b47326d09" datatype="html"> <trans-unit id="072d4d4ec83a5a97345a1c13b90c213b47326d09" datatype="html">
<source>Customize</source> <source>Customize</source>
<target state="new">Customize</target> <target state="translated">Personalizza</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/rule/rule.component.html</context> <context context-type="sourcefile">apps/client/src/app/components/rule/rule.component.html</context>
<context context-type="linenumber">67</context> <context context-type="linenumber">67</context>
@ -7125,7 +7125,7 @@
</trans-unit> </trans-unit>
<trans-unit id="06296af0cdaf7bed02043379359ed1975fc22077" datatype="html"> <trans-unit id="06296af0cdaf7bed02043379359ed1975fc22077" datatype="html">
<source>No auto-renewal.</source> <source>No auto-renewal.</source>
<target state="new">No auto-renewal.</target> <target state="translated">No rinnovo automatico.</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/user-account-membership/user-account-membership.html</context> <context context-type="sourcefile">apps/client/src/app/components/user-account-membership/user-account-membership.html</context>
<context context-type="linenumber">62</context> <context context-type="linenumber">62</context>
@ -7133,7 +7133,7 @@
</trans-unit> </trans-unit>
<trans-unit id="7fb1099e29660162f9154d5b2feee7743a423df6" datatype="html"> <trans-unit id="7fb1099e29660162f9154d5b2feee7743a423df6" datatype="html">
<source>Today</source> <source>Today</source>
<target state="new">Today</target> <target state="translated">Oggi</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">24</context> <context context-type="linenumber">24</context>
@ -7141,7 +7141,7 @@
</trans-unit> </trans-unit>
<trans-unit id="65cefcc53d1f6445df7568e8a40c49165f1090ee" datatype="html"> <trans-unit id="65cefcc53d1f6445df7568e8a40c49165f1090ee" datatype="html">
<source>This year</source> <source>This year</source>
<target state="new">This year</target> <target state="translated">Anno corrente</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">42</context> <context context-type="linenumber">42</context>
@ -7149,7 +7149,7 @@
</trans-unit> </trans-unit>
<trans-unit id="5beadaafe995fa04343008b0ab57e579c9fc81b9" datatype="html"> <trans-unit id="5beadaafe995fa04343008b0ab57e579c9fc81b9" datatype="html">
<source>From the beginning</source> <source>From the beginning</source>
<target state="new">From the beginning</target> <target state="translated">Dall'inizio</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
<context context-type="linenumber">60</context> <context context-type="linenumber">60</context>
@ -7157,7 +7157,7 @@
</trans-unit> </trans-unit>
<trans-unit id="f7ed8f2e1ac78c5a63741ae684779bcf7a99ab16" datatype="html"> <trans-unit id="f7ed8f2e1ac78c5a63741ae684779bcf7a99ab16" datatype="html">
<source>Oops! Invalid currency.</source> <source>Oops! Invalid currency.</source>
<target state="new">Oops! Invalid currency.</target> <target state="translated">Oops! Valuta sbagliata.</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html</context> <context context-type="sourcefile">apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html</context>
<context context-type="linenumber">49</context> <context context-type="linenumber">49</context>
@ -7165,7 +7165,7 @@
</trans-unit> </trans-unit>
<trans-unit id="f1cc4a59110dd72517210565f76118df74336fec" datatype="html"> <trans-unit id="f1cc4a59110dd72517210565f76118df74336fec" datatype="html">
<source>This page has been archived.</source> <source>This page has been archived.</source>
<target state="new">This page has been archived.</target> <target state="translated">Questa pagina è stata archiviata.</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">14</context> <context context-type="linenumber">14</context>
@ -7173,7 +7173,7 @@
</trans-unit> </trans-unit>
<trans-unit id="ea66ce0bb1cb1dcee2bcb86a8876c5f2c2fa65f6" datatype="html"> <trans-unit id="ea66ce0bb1cb1dcee2bcb86a8876c5f2c2fa65f6" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> is Open Source Software</source> <source><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> is Open Source Software</source>
<target state="new"><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> is Open Source Software</target> <target state="translated"><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> è un programma Open Source</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">139</context> <context context-type="linenumber">139</context>
@ -7181,7 +7181,7 @@
</trans-unit> </trans-unit>
<trans-unit id="aa945d3772281b66851cc8b86d6de9726e65db70" datatype="html"> <trans-unit id="aa945d3772281b66851cc8b86d6de9726e65db70" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> is not Open Source Software</source> <source><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> is not Open Source Software</source>
<target state="new"><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> is not Open Source Software</target> <target state="translated"><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> non è un programma Open Source</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">146</context> <context context-type="linenumber">146</context>
@ -7189,7 +7189,7 @@
</trans-unit> </trans-unit>
<trans-unit id="942e46b94b9d9662c3c3b7b5e7f9005c7b9feab7" datatype="html"> <trans-unit id="942e46b94b9d9662c3c3b7b5e7f9005c7b9feab7" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> is Open Source Software</source> <source><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> is Open Source Software</source>
<target state="new"><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> is Open Source Software</target> <target state="translated"><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> è un programma Open Source</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">156</context> <context context-type="linenumber">156</context>
@ -7197,7 +7197,7 @@
</trans-unit> </trans-unit>
<trans-unit id="08beed5100360c242c0aec92e8706d92f0cb70f3" datatype="html"> <trans-unit id="08beed5100360c242c0aec92e8706d92f0cb70f3" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> is not Open Source Software</source> <source><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> is not Open Source Software</source>
<target state="new"><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> is not Open Source Software</target> <target state="translated"><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> non è un programma Open Source</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">163</context> <context context-type="linenumber">163</context>
@ -7205,7 +7205,7 @@
</trans-unit> </trans-unit>
<trans-unit id="1302d86668c92816f6e69a61fee77d573ace918b" datatype="html"> <trans-unit id="1302d86668c92816f6e69a61fee77d573ace918b" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> can be self-hosted</source> <source><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> can be self-hosted</source>
<target state="new"><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> can be self-hosted</target> <target state="translated"><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> pu&ograve; essere ospitato in proprio </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">178</context> <context context-type="linenumber">178</context>
@ -7213,7 +7213,7 @@
</trans-unit> </trans-unit>
<trans-unit id="2371f735292afd7ed2b6c90640068d33667933e7" datatype="html"> <trans-unit id="2371f735292afd7ed2b6c90640068d33667933e7" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> cannot be self-hosted</source> <source><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> cannot be self-hosted</source>
<target state="new"><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> cannot be self-hosted</target> <target state="translated"><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> non pu&ograve; essere ospitato in proprio</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">185</context> <context context-type="linenumber">185</context>
@ -7221,7 +7221,7 @@
</trans-unit> </trans-unit>
<trans-unit id="4803807735afa465179312a0094a432c7d8e1a55" datatype="html"> <trans-unit id="4803807735afa465179312a0094a432c7d8e1a55" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> can be self-hosted</source> <source><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> can be self-hosted</source>
<target state="new"><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> can be self-hosted</target> <target state="translated"><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> pu&ograve; essere ospitato in proprio</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">195</context> <context context-type="linenumber">195</context>
@ -7229,7 +7229,7 @@
</trans-unit> </trans-unit>
<trans-unit id="e44d1606f6b1c8b549b5bbc22c8f2d53b6626404" datatype="html"> <trans-unit id="e44d1606f6b1c8b549b5bbc22c8f2d53b6626404" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> cannot be self-hosted</source> <source><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> cannot be self-hosted</source>
<target state="new"><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> cannot be self-hosted</target> <target state="translated"><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> non pu&ograve; essere ospitato in proprio</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">202</context> <context context-type="linenumber">202</context>
@ -7237,7 +7237,7 @@
</trans-unit> </trans-unit>
<trans-unit id="575dc02bb1fbd579cb7ecca00198bbf2893d6115" datatype="html"> <trans-unit id="575dc02bb1fbd579cb7ecca00198bbf2893d6115" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> can be used anonymously</source> <source><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> can be used anonymously</source>
<target state="new"><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> can be used anonymously</target> <target state="translated"><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> pu&ograve; essere usato anonimamente</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">217</context> <context context-type="linenumber">217</context>
@ -7245,7 +7245,7 @@
</trans-unit> </trans-unit>
<trans-unit id="60bcadcc133112179baf414d6bca496616026ddf" datatype="html"> <trans-unit id="60bcadcc133112179baf414d6bca496616026ddf" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> cannot be used anonymously</source> <source><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> cannot be used anonymously</source>
<target state="new"><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> cannot be used anonymously</target> <target state="translated"><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> non pu&ograve; essere usato anonimamente</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">224</context> <context context-type="linenumber">224</context>
@ -7253,7 +7253,7 @@
</trans-unit> </trans-unit>
<trans-unit id="ea9dead7214d6e5e68bedcfc41ed92e6f331b476" datatype="html"> <trans-unit id="ea9dead7214d6e5e68bedcfc41ed92e6f331b476" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> can be used anonymously</source> <source><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> can be used anonymously</source>
<target state="new"><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> can be used anonymously</target> <target state="translated"><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> pu&ograve; essere usato anonimamente</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">234</context> <context context-type="linenumber">234</context>
@ -7261,7 +7261,7 @@
</trans-unit> </trans-unit>
<trans-unit id="d69adb6f3253a16368a171d0a5d998e9a6b95717" datatype="html"> <trans-unit id="d69adb6f3253a16368a171d0a5d998e9a6b95717" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> cannot be used anonymously</source> <source><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> cannot be used anonymously</source>
<target state="new"><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> cannot be used anonymously</target> <target state="translated"><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> non pu&ograve; essere usato anonimamente</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">241</context> <context context-type="linenumber">241</context>
@ -7269,7 +7269,7 @@
</trans-unit> </trans-unit>
<trans-unit id="0499b37a6ed7d654307685844b35684df638a95f" datatype="html"> <trans-unit id="0499b37a6ed7d654307685844b35684df638a95f" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> offers a free plan</source> <source><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> offers a free plan</source>
<target state="new"><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> offers a free plan</target> <target state="translated"><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> ha un piano gratuito</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">256</context> <context context-type="linenumber">256</context>
@ -7277,7 +7277,7 @@
</trans-unit> </trans-unit>
<trans-unit id="0a3bfda56ea7cd7ae419cb5091e3a68ade032c30" datatype="html"> <trans-unit id="0a3bfda56ea7cd7ae419cb5091e3a68ade032c30" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> does not offer a free plan</source> <source><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> does not offer a free plan</source>
<target state="new"><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> does not offer a free plan</target> <target state="translated"><x id="INTERPOLATION" equiv-text="{{ product1.name }}"/> non ha un piano gratuito</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">263</context> <context context-type="linenumber">263</context>
@ -7285,7 +7285,7 @@
</trans-unit> </trans-unit>
<trans-unit id="04eede9cafd81f04b01b6c7937e047824f78b05d" datatype="html"> <trans-unit id="04eede9cafd81f04b01b6c7937e047824f78b05d" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> offers a free plan</source> <source><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> offers a free plan</source>
<target state="new"><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> offers a free plan</target> <target state="translated"><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> ha un piano gratuito</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">273</context> <context context-type="linenumber">273</context>
@ -7293,7 +7293,7 @@
</trans-unit> </trans-unit>
<trans-unit id="2452ec985c64ade4904d93697e68d3846beb2bf4" datatype="html"> <trans-unit id="2452ec985c64ade4904d93697e68d3846beb2bf4" datatype="html">
<source><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> does not offer a free plan</source> <source><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> does not offer a free plan</source>
<target state="new"><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> does not offer a free plan</target> <target state="translated"><x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> non ha un piano gratuito</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">280</context> <context context-type="linenumber">280</context>
@ -7301,7 +7301,7 @@
</trans-unit> </trans-unit>
<trans-unit id="b225488f8b209e9704760dc9f5d99845a5d07bf6" datatype="html"> <trans-unit id="b225488f8b209e9704760dc9f5d99845a5d07bf6" datatype="html">
<source>Oops! Could not find any assets.</source> <source>Oops! Could not find any assets.</source>
<target state="new">Oops! Could not find any assets.</target> <target state="translated">Oops! Non ho trovato alcun asset.</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html</context> <context context-type="sourcefile">libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html</context>
<context context-type="linenumber">37</context> <context context-type="linenumber">37</context>
@ -7309,7 +7309,7 @@
</trans-unit> </trans-unit>
<trans-unit id="be839b9dc1563aec0f80f5b55c8bde1a1dd10ca1" datatype="html"> <trans-unit id="be839b9dc1563aec0f80f5b55c8bde1a1dd10ca1" datatype="html">
<source>Data Providers</source> <source>Data Providers</source>
<target state="new">Data Providers</target> <target state="translated">Fornitori di dati</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-settings/admin-settings.component.html</context> <context context-type="sourcefile">apps/client/src/app/components/admin-settings/admin-settings.component.html</context>
<context context-type="linenumber">4</context> <context context-type="linenumber">4</context>
@ -7317,7 +7317,7 @@
</trans-unit> </trans-unit>
<trans-unit id="b082171edef6d502186c4577e201b2ef7935e955" datatype="html"> <trans-unit id="b082171edef6d502186c4577e201b2ef7935e955" datatype="html">
<source>NEW</source> <source>NEW</source>
<target state="new">NEW</target> <target state="translated">NUOVO</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-settings/admin-settings.component.html</context> <context context-type="sourcefile">apps/client/src/app/components/admin-settings/admin-settings.component.html</context>
<context context-type="linenumber">14</context> <context context-type="linenumber">14</context>
@ -7325,7 +7325,7 @@
</trans-unit> </trans-unit>
<trans-unit id="66cbb0c1695dc25d22f824b62f0ffb9435ec8c4b" datatype="html"> <trans-unit id="66cbb0c1695dc25d22f824b62f0ffb9435ec8c4b" datatype="html">
<source>Set API Key</source> <source>Set API Key</source>
<target state="new">Set API Key</target> <target state="translated">Imposta API Key</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-settings/admin-settings.component.html</context> <context context-type="sourcefile">apps/client/src/app/components/admin-settings/admin-settings.component.html</context>
<context context-type="linenumber">29</context> <context context-type="linenumber">29</context>
@ -7333,7 +7333,7 @@
</trans-unit> </trans-unit>
<trans-unit id="2fcf96765ae87821e12fe4f6900ba1a218742cfc" datatype="html"> <trans-unit id="2fcf96765ae87821e12fe4f6900ba1a218742cfc" datatype="html">
<source> Want to stay updated? Click below to get notified as soon as it’s available. </source> <source> Want to stay updated? Click below to get notified as soon as it’s available. </source>
<target state="new"> Want to stay updated? Click below to get notified as soon as it’s available. </target> <target state="translated"> Vuoi seguire le novità? Clicca sotto per essere notificato appena è disponibile. </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html</context> <context context-type="sourcefile">apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html</context>
<context context-type="linenumber">23</context> <context context-type="linenumber">23</context>
@ -7341,7 +7341,7 @@
</trans-unit> </trans-unit>
<trans-unit id="3a0843b9fa08ab1d2294e2b5bd60042052ab8d10" datatype="html"> <trans-unit id="3a0843b9fa08ab1d2294e2b5bd60042052ab8d10" datatype="html">
<source> Notify me </source> <source> Notify me </source>
<target state="new"> Notify me </target> <target state="translated"> Notificami </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html</context> <context context-type="sourcefile">apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html</context>
<context context-type="linenumber">32</context> <context context-type="linenumber">32</context>
@ -7349,7 +7349,7 @@
</trans-unit> </trans-unit>
<trans-unit id="8908015589937012101" datatype="html"> <trans-unit id="8908015589937012101" datatype="html">
<source>Get access to 100’000+ tickers from over 50 exchanges</source> <source>Get access to 100’000+ tickers from over 50 exchanges</source>
<target state="new">Get access to 100’000+ tickers from over 50 exchanges</target> <target state="translated">Ottieni accesso a oltre 100’000+ titoli da oltre 50 borse</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context> <context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">24</context> <context context-type="linenumber">24</context>
@ -7357,7 +7357,7 @@
</trans-unit> </trans-unit>
<trans-unit id="4346283537747431562" datatype="html"> <trans-unit id="4346283537747431562" datatype="html">
<source>Ukraine</source> <source>Ukraine</source>
<target state="new">Ukraine</target> <target state="translated">Ucraina</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context> <context context-type="sourcefile">libs/ui/src/lib/i18n.ts</context>
<context context-type="linenumber">92</context> <context context-type="linenumber">92</context>
@ -7365,7 +7365,7 @@
</trans-unit> </trans-unit>
<trans-unit id="f977904fb6da18ed1fcc2b56caa2315e991fd2ac" datatype="html"> <trans-unit id="f977904fb6da18ed1fcc2b56caa2315e991fd2ac" datatype="html">
<source> Skip </source> <source> Skip </source>
<target state="new"> Skip </target> <target state="translated"> Salta </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html</context> <context context-type="sourcefile">apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html</context>
<context context-type="linenumber">83</context> <context context-type="linenumber">83</context>
@ -7373,7 +7373,7 @@
</trans-unit> </trans-unit>
<trans-unit id="3e0b7db80b1d6c100266b97b9bb3f9ddd7652844" datatype="html"> <trans-unit id="3e0b7db80b1d6c100266b97b9bb3f9ddd7652844" datatype="html">
<source>Join now</source> <source>Join now</source>
<target state="new">Join now</target> <target state="translated">Iscriviti adesso</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html</context> <context context-type="sourcefile">apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html</context>
<context context-type="linenumber">93</context> <context context-type="linenumber">93</context>
@ -7381,7 +7381,7 @@
</trans-unit> </trans-unit>
<trans-unit id="e8a4d8ee23e2c3f89acf7214598bcc3182c79268" datatype="html"> <trans-unit id="e8a4d8ee23e2c3f89acf7214598bcc3182c79268" datatype="html">
<source>Allocation Cluster Risks</source> <source>Allocation Cluster Risks</source>
<target state="new">Allocation Cluster Risks</target> <target state="translated">Rischi di allocazione dei Conti</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/fire/fire-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/portfolio/fire/fire-page.html</context>
<context context-type="linenumber">179</context> <context context-type="linenumber">179</context>
@ -7389,7 +7389,7 @@
</trans-unit> </trans-unit>
<trans-unit id="5020357869062357338" datatype="html"> <trans-unit id="5020357869062357338" datatype="html">
<source>Glossary</source> <source>Glossary</source>
<target state="new">Glossary</target> <target state="translated">Glossario</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/glossary/resources-glossary-routing.module.ts</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/glossary/resources-glossary-routing.module.ts</context>
<context context-type="linenumber">10</context> <context context-type="linenumber">10</context>
@ -7401,7 +7401,7 @@
</trans-unit> </trans-unit>
<trans-unit id="7423212324650924366" datatype="html"> <trans-unit id="7423212324650924366" datatype="html">
<source>Guides</source> <source>Guides</source>
<target state="new">Guides</target> <target state="translated">Guide</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/guides/resources-guides-routing.module.ts</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/guides/resources-guides-routing.module.ts</context>
<context context-type="linenumber">10</context> <context context-type="linenumber">10</context>
@ -7413,7 +7413,7 @@
</trans-unit> </trans-unit>
<trans-unit id="7491998780064454778" datatype="html"> <trans-unit id="7491998780064454778" datatype="html">
<source>guides</source> <source>guides</source>
<target state="new">guides</target> <target state="translated">guide</target>
<note priority="1" from="description">snake-case</note> <note priority="1" from="description">snake-case</note>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/overview/resources-overview.component.ts</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/overview/resources-overview.component.ts</context>
@ -7426,7 +7426,7 @@
</trans-unit> </trans-unit>
<trans-unit id="6255655462254999912" datatype="html"> <trans-unit id="6255655462254999912" datatype="html">
<source>glossary</source> <source>glossary</source>
<target state="new">glossary</target> <target state="translated">glossario</target>
<note priority="1" from="description">snake-case</note> <note priority="1" from="description">snake-case</note>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/overview/resources-overview.component.ts</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/overview/resources-overview.component.ts</context>

2
libs/common/src/lib/interfaces/user-settings.interface.ts

@ -14,6 +14,8 @@ export interface UserSettings {
dateRange?: DateRange; dateRange?: DateRange;
emergencyFund?: number; emergencyFund?: number;
'filters.accounts'?: string[]; 'filters.accounts'?: string[];
'filters.dataSource'?: string;
'filters.symbol'?: string;
'filters.tags'?: string[]; 'filters.tags'?: string[];
holdingsViewMode?: HoldingsViewMode; holdingsViewMode?: HoldingsViewMode;
isExperimentalFeatures?: boolean; isExperimentalFeatures?: boolean;

94
libs/ui/src/lib/assistant/assistant.component.ts

@ -1,7 +1,9 @@
import { GfAssetProfileIconComponent } from '@ghostfolio/client/components/asset-profile-icon/asset-profile-icon.component'; import { GfAssetProfileIconComponent } from '@ghostfolio/client/components/asset-profile-icon/asset-profile-icon.component';
import { GfSymbolModule } from '@ghostfolio/client/pipes/symbol/symbol.module';
import { AdminService } from '@ghostfolio/client/services/admin.service'; import { AdminService } from '@ghostfolio/client/services/admin.service';
import { DataService } from '@ghostfolio/client/services/data.service'; import { DataService } from '@ghostfolio/client/services/data.service';
import { Filter, User } from '@ghostfolio/common/interfaces'; import { getAssetProfileIdentifier } from '@ghostfolio/common/helper';
import { Filter, PortfolioPosition, User } from '@ghostfolio/common/interfaces';
import { DateRange } from '@ghostfolio/common/types'; import { DateRange } from '@ghostfolio/common/types';
import { translate } from '@ghostfolio/ui/i18n'; import { translate } from '@ghostfolio/ui/i18n';
@ -35,7 +37,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
import { MatMenuTrigger } from '@angular/material/menu'; import { MatMenuTrigger } from '@angular/material/menu';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { Account, AssetClass } from '@prisma/client'; import { Account, AssetClass, DataSource } from '@prisma/client';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { EMPTY, Observable, Subject, lastValueFrom } from 'rxjs'; import { EMPTY, Observable, Subject, lastValueFrom } from 'rxjs';
import { import {
@ -61,6 +63,7 @@ import {
FormsModule, FormsModule,
GfAssetProfileIconComponent, GfAssetProfileIconComponent,
GfAssistantListItemComponent, GfAssistantListItemComponent,
GfSymbolModule,
MatButtonModule, MatButtonModule,
MatFormFieldModule, MatFormFieldModule,
MatSelectModule, MatSelectModule,
@ -132,8 +135,10 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
public filterForm = this.formBuilder.group({ public filterForm = this.formBuilder.group({
account: new FormControl<string>(undefined), account: new FormControl<string>(undefined),
assetClass: new FormControl<string>(undefined), assetClass: new FormControl<string>(undefined),
holding: new FormControl<PortfolioPosition>(undefined),
tag: new FormControl<string>(undefined) tag: new FormControl<string>(undefined)
}); });
public holdings: PortfolioPosition[] = [];
public isLoading = false; public isLoading = false;
public isOpen = false; public isOpen = false;
public placeholder = $localize`Find holding...`; public placeholder = $localize`Find holding...`;
@ -144,7 +149,13 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
}; };
public tags: Filter[] = []; public tags: Filter[] = [];
private filterTypes: Filter['type'][] = ['ACCOUNT', 'ASSET_CLASS', 'TAG']; private filterTypes: Filter['type'][] = [
'ACCOUNT',
'ASSET_CLASS',
'DATA_SOURCE',
'SYMBOL',
'TAG'
];
private keyManager: FocusKeyManager<GfAssistantListItemComponent>; private keyManager: FocusKeyManager<GfAssistantListItemComponent>;
private unsubscribeSubject = new Subject<void>(); private unsubscribeSubject = new Subject<void>();
@ -156,6 +167,8 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
) {} ) {}
public ngOnInit() { public ngOnInit() {
this.initializeFilterForm();
this.assetClasses = Object.keys(AssetClass).map((assetClass) => { this.assetClasses = Object.keys(AssetClass).map((assetClass) => {
return { return {
id: assetClass, id: assetClass,
@ -263,16 +276,7 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
this.filterForm.enable({ emitEvent: false }); this.filterForm.enable({ emitEvent: false });
} }
this.filterForm.setValue( this.initializeFilterForm();
{
account: this.user?.settings?.['filters.accounts']?.[0] ?? null,
assetClass: this.user?.settings?.['filters.assetClasses']?.[0] ?? null,
tag: this.user?.settings?.['filters.tags']?.[0] ?? null
},
{
emitEvent: false
}
);
this.tags = this.tags =
this.user?.tags this.user?.tags
@ -298,6 +302,19 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
}); });
} }
public holdingComparisonFunction(
option: PortfolioPosition,
value: PortfolioPosition
): boolean {
if (value === null) {
return false;
}
return (
getAssetProfileIdentifier(option) === getAssetProfileIdentifier(value)
);
}
public async initialize() { public async initialize() {
this.isLoading = true; this.isLoading = true;
this.keyManager = new FocusKeyManager(this.assistantListItems).withWrap(); this.keyManager = new FocusKeyManager(this.assistantListItems).withWrap();
@ -331,6 +348,14 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
id: this.filterForm.get('assetClass').value, id: this.filterForm.get('assetClass').value,
type: 'ASSET_CLASS' type: 'ASSET_CLASS'
}, },
{
id: this.filterForm.get('holding').value?.dataSource,
type: 'DATA_SOURCE'
},
{
id: this.filterForm.get('holding').value?.symbol,
type: 'SYMBOL'
},
{ {
id: this.filterForm.get('tag').value, id: this.filterForm.get('tag').value,
type: 'TAG' type: 'TAG'
@ -473,4 +498,47 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
takeUntil(this.unsubscribeSubject) takeUntil(this.unsubscribeSubject)
); );
} }
private initializeFilterForm() {
this.dataService
.fetchPortfolioHoldings()
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ holdings }) => {
this.holdings = holdings
.filter(({ assetSubClass }) => {
return !['CASH'].includes(assetSubClass);
})
.sort((a, b) => {
return a.name?.localeCompare(b.name);
});
this.setFilterFormValues();
});
}
private setFilterFormValues() {
const dataSource = this.user?.settings?.[
'filters.dataSource'
] as DataSource;
const symbol = this.user?.settings?.['filters.symbol'];
const selectedHolding = this.holdings.find((holding) => {
return (
getAssetProfileIdentifier({
dataSource: holding.dataSource,
symbol: holding.symbol
}) === getAssetProfileIdentifier({ dataSource, symbol })
);
});
this.filterForm.setValue(
{
account: this.user?.settings?.['filters.accounts']?.[0] ?? null,
assetClass: this.user?.settings?.['filters.assetClasses']?.[0] ?? null,
holding: selectedHolding ?? null,
tag: this.user?.settings?.['filters.tags']?.[0] ?? null
},
{
emitEvent: false
}
);
}
} }

28
libs/ui/src/lib/assistant/assistant.html

@ -122,6 +122,34 @@
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="mb-3">
<mat-form-field appearance="outline" class="w-100 without-hint">
<mat-label i18n>Holding</mat-label>
<mat-select
formControlName="holding"
[compareWith]="holdingComparisonFunction"
>
<mat-select-trigger>{{
filterForm.get('holding')?.value?.name
}}</mat-select-trigger>
<mat-option [value]="null" />
@for (holding of holdings; track holding.name) {
<mat-option [value]="holding">
<div class="line-height-1 text-truncate">
<span
><b>{{ holding.name }}</b></span
>
<br />
<small class="text-muted"
>{{ holding.symbol | gfSymbol }} ·
{{ holding.currency }}</small
>
</div>
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
<div class="mb-3"> <div class="mb-3">
<mat-form-field appearance="outline" class="w-100 without-hint"> <mat-form-field appearance="outline" class="w-100 without-hint">
<mat-label i18n>Tags</mat-label> <mat-label i18n>Tags</mat-label>

Loading…
Cancel
Save