Compare commits

...

18 Commits

Author SHA1 Message Date
69ac3408f1 Release 1.230.0 (#1639) 2023-01-29 10:00:28 +01:00
e1806b4bd8 Feature/add sourceforge logo to landing page (#1638)
* Add SourceForge

* Update changelog
2023-01-29 09:58:53 +01:00
6aae0cc1e4 Bugfix/fix issue with value in value redaction interceptor (#1627)
* Fix issue with value in value redaction interceptor

* Fix format of world map

* Update changelog
2023-01-29 09:58:05 +01:00
5d8a50a80d Feature/add interstitial for subscription (#1637)
* Add interstitial

* Improve pricing page

* Update changelog
2023-01-28 09:42:15 +01:00
662231e830 Feature/upgrade prisma to version 4.9.0 (#1630)
* Upgrade prisma to version 4.9.0

* Update changelog
2023-01-28 09:41:33 +01:00
4d84459b5b Clean up imports (#1632) 2023-01-27 08:49:31 +01:00
efba7429c1 Bugfix/fix click of unknown accounts (#1629)
* Check for unknown key

* Update changelog
2023-01-25 12:00:52 +01:00
9cae5a3e79 Feature/improve sackgeld.com blog post (#1628)
* Improve blog post and add quote

* Update changelog
2023-01-24 08:11:21 +01:00
c2ed0a436f Downgrade to Node.js 16 (for development) (#1633) 2023-01-23 21:52:46 +01:00
8486c02575 Update Node to version 18.x (#1595)
* Update Node to version 18.x

* Add .nvmrc

* Update changelog

Co-authored-by: Thomas <4159106+dtslvr@users.noreply.github.com>
2023-01-23 08:28:19 +01:00
5122ef3456 Release 1.229.0 (#1626) 2023-01-21 16:10:04 +01:00
579b86665e Feature/add sackgeld.com blog post (#1625)
* Add blog post: Ghostfolio auf Sackgeld.com vorgestellt

* Update changelog
2023-01-21 16:07:32 +01:00
52b3ad6dc3 Feature/refactor value redaction interceptor (#1624)
* Reuse redactAttributes()

* Update changelog
2023-01-21 11:46:56 +01:00
bf9b60aa74 Feature/add sackgeld.com to as seen in section (#1622)
* Add Sackgeld.com

* Update changelog
2023-01-21 11:31:52 +01:00
6cd51fb044 Feature/hide irrelevant errors in client (#1623)
* Hide irrelevant errors in client

* Update changelog
2023-01-21 11:30:53 +01:00
271001f523 Feature/remove toggle on allocations page (#1620)
* Rename allocationCurrent, remove allocationInvestment

* Update changelog
2023-01-21 09:52:58 +01:00
a7e513a6d1 Bugfix/fix filtered value for emergency fund (#1619)
* Fix filtered value

* Update changelog
2023-01-20 20:51:08 +01:00
b5f256be95 Remove mail address (#1621) 2023-01-20 20:50:32 +01:00
71 changed files with 1139 additions and 681 deletions

View File

@ -10,7 +10,7 @@ jobs:
strategy:
matrix:
node_version:
- 16
- 18
steps:
- name: Checkout code
uses: actions/checkout@v3

1
.nvmrc Normal file
View File

@ -0,0 +1 @@
v16

View File

@ -5,6 +5,43 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 1.230.0 - 2023-01-29
### Added
- Added an interstitial for the subscription
- Added _SourceForge_ to the _As seen in_ section on the landing page
- Added a quote to the blog post _Ghostfolio auf Sackgeld.com vorgestellt_
### Changed
- Improved the unit format (`%`) in the global heat map component of the public page
- Improved the pricing page
- Upgraded `Node.js` from version `16` to `18` (`Dockerfile`)
- Upgraded `prisma` from version `4.8.0` to `4.9.0`
### Fixed
- Fixed the click of unknown accounts in the portfolio proportion chart component
- Fixed an issue with `value` in the value redaction interceptor for the impersonation mode
## 1.229.0 - 2023-01-21
### Added
- Added a blog post: _Ghostfolio auf Sackgeld.com vorgestellt_
- Added _Sackgeld.com_ to the _As seen in_ section on the landing page
### Changed
- Removed the toggle _Original Shares_ vs. _Current Shares_ on the allocations page
- Hid error messages related to no current investment in the client
- Refactored the value redaction interceptor for the impersonation mode
### Fixed
- Fixed the value of the active (emergency fund) filter in percentage on the allocations page
## 1.228.1 - 2023-01-18
### Added

View File

@ -1,4 +1,4 @@
FROM --platform=$BUILDPLATFORM node:16-slim as builder
FROM --platform=$BUILDPLATFORM node:18-slim as builder
# Build application and add additional files
WORKDIR /ghostfolio
@ -50,7 +50,7 @@ COPY package.json /ghostfolio/dist/apps/api
RUN yarn database:generate-typings
# Image to run, copy everything needed from builder
FROM node:16-slim
FROM node:18-slim
RUN apt update && apt install -y \
openssl \
&& rm -rf /var/lib/apt/lists/*

View File

@ -148,7 +148,7 @@ Please follow the instructions of the Ghostfolio [Unraid Community App](https://
### Prerequisites
- [Docker](https://www.docker.com/products/docker-desktop)
- [Node.js](https://nodejs.org/en/download) (version 16+)
- [Node.js](https://nodejs.org/en/download) (version 16)
- [Yarn](https://yarnpkg.com/en/docs/install)
- A local copy of this Git repository (clone)
@ -269,7 +269,7 @@ You can get the _Bearer Token_ via `GET http://localhost:3333/api/v1/auth/anonym
Ghostfolio is **100% free** and **open source**. We encourage and support an active and healthy community that accepts contributions from the public - including you.
Not sure what to work on? We have got some ideas. Please join the Ghostfolio [Slack channel](https://join.slack.com/t/ghostfolio/shared_invite/zt-vsaan64h-F_I0fEo5M0P88lP9ibCxFg), tweet to [@ghostfolio\_](https://twitter.com/ghostfolio_) or send an e-mail to hi@ghostfol.io. We would love to hear from you.
Not sure what to work on? We have got some ideas. Please join the Ghostfolio [Slack channel](https://join.slack.com/t/ghostfolio/shared_invite/zt-vsaan64h-F_I0fEo5M0P88lP9ibCxFg) or tweet to [@ghostfolio\_](https://twitter.com/ghostfolio_). We would love to hear from you.
If you like to support this project, get [**Ghostfolio Premium**](https://ghostfol.io/en/pricing) or [**Buy me a coffee**](https://www.buymeacoffee.com/ghostfolio).

View File

@ -1,9 +1,6 @@
import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service';
import { UserService } from '@ghostfolio/api/app/user/user.service';
import {
nullifyValuesInObject,
nullifyValuesInObjects
} from '@ghostfolio/api/helper/object.helper';
import { RedactValuesInResponseInterceptor } from '@ghostfolio/api/interceptors/redact-values-in-response.interceptor';
import { ImpersonationService } from '@ghostfolio/api/services/impersonation.service';
import { Accounts } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
@ -22,7 +19,8 @@ import {
Param,
Post,
Put,
UseGuards
UseGuards,
UseInterceptors
} from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
@ -85,6 +83,7 @@ export class AccountController {
@Get()
@UseGuards(AuthGuard('jwt'))
@UseInterceptors(RedactValuesInResponseInterceptor)
public async getAllAccounts(
@Headers('impersonation-id') impersonationId
): Promise<Accounts> {
@ -94,39 +93,15 @@ export class AccountController {
this.request.user.id
);
let accountsWithAggregations =
await this.portfolioService.getAccountsWithAggregations({
userId: impersonationUserId || this.request.user.id,
withExcludedAccounts: true
});
if (
impersonationUserId ||
this.userService.isRestrictedView(this.request.user)
) {
accountsWithAggregations = {
...nullifyValuesInObject(accountsWithAggregations, [
'totalBalanceInBaseCurrency',
'totalValueInBaseCurrency'
]),
accounts: nullifyValuesInObjects(accountsWithAggregations.accounts, [
'balance',
'balanceInBaseCurrency',
'convertedBalance',
'fee',
'quantity',
'unitPrice',
'value',
'valueInBaseCurrency'
])
};
}
return accountsWithAggregations;
return this.portfolioService.getAccountsWithAggregations({
userId: impersonationUserId || this.request.user.id,
withExcludedAccounts: true
});
}
@Get(':id')
@UseGuards(AuthGuard('jwt'))
@UseInterceptors(RedactValuesInResponseInterceptor)
public async getAccountById(
@Headers('impersonation-id') impersonationId,
@Param('id') id: string
@ -137,35 +112,13 @@ export class AccountController {
this.request.user.id
);
let accountsWithAggregations =
const accountsWithAggregations =
await this.portfolioService.getAccountsWithAggregations({
filters: [{ id, type: 'ACCOUNT' }],
userId: impersonationUserId || this.request.user.id,
withExcludedAccounts: true
});
if (
impersonationUserId ||
this.userService.isRestrictedView(this.request.user)
) {
accountsWithAggregations = {
...nullifyValuesInObject(accountsWithAggregations, [
'totalBalanceInBaseCurrency',
'totalValueInBaseCurrency'
]),
accounts: nullifyValuesInObjects(accountsWithAggregations.accounts, [
'balance',
'balanceInBaseCurrency',
'convertedBalance',
'fee',
'quantity',
'unitPrice',
'value',
'valueInBaseCurrency'
])
};
}
return accountsWithAggregations.accounts[0];
}

View File

@ -83,6 +83,13 @@ export class FrontendMiddleware implements NestMiddleware {
) {
featureGraphicPath = 'assets/images/blog/20221226.jpg';
title = `The importance of tracking your personal finances - ${title}`;
} else if (
request.path.startsWith(
'/de/blog/2023/01/ghostfolio-auf-sackgeld-vorgestellt'
)
) {
featureGraphicPath = 'assets/images/blog/ghostfolio-x-sackgeld.png';
title = `Ghostfolio auf Sackgeld.com vorgestellt - ${title}`;
}
if (

View File

@ -20,7 +20,6 @@ import { REQUEST } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
import { DataSource } from '@prisma/client';
import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { isEmpty } from 'lodash';
import { ImportDataDto } from './import-data.dto';
import { ImportService } from './import.service';

View File

@ -447,7 +447,7 @@ export class PortfolioCalculator {
transactionCount: item.transactionCount
});
if (hasErrors) {
if (hasErrors && item.investment.gt(0)) {
errors.push({ dataSource: item.dataSource, symbol: item.symbol });
}
}

View File

@ -131,7 +131,8 @@ export class PortfolioController {
portfolioPosition.investment / totalInvestment;
portfolioPosition.netPerformance = null;
portfolioPosition.quantity = null;
portfolioPosition.value = portfolioPosition.value / totalValue;
portfolioPosition.valueInPercentage =
portfolioPosition.value / totalValue;
}
for (const [name, { current, original }] of Object.entries(accounts)) {
@ -322,7 +323,7 @@ export class PortfolioController {
totalInvestment: new Big(totalInvestment)
.div(performanceInformation.performance.totalInvestment)
.toNumber(),
value: new Big(value)
valueInPercentage: new Big(value)
.div(performanceInformation.performance.currentValue)
.toNumber()
};
@ -356,6 +357,7 @@ export class PortfolioController {
@Get('positions')
@UseGuards(AuthGuard('jwt'))
@UseInterceptors(RedactValuesInResponseInterceptor)
@UseInterceptors(TransformDataSourceInResponseInterceptor)
public async getPositions(
@Headers('impersonation-id') impersonationId: string,
@ -370,27 +372,11 @@ export class PortfolioController {
filterByTags
});
const result = await this.portfolioService.getPositions({
return this.portfolioService.getPositions({
dateRange,
filters,
impersonationId
});
if (
impersonationId ||
this.userService.isRestrictedView(this.request.user)
) {
result.positions = result.positions.map((position) => {
return nullifyValuesInObject(position, [
'grossPerformance',
'investment',
'netPerformance',
'quantity'
]);
});
}
return result;
}
@Get('public/:accessId')
@ -441,7 +427,7 @@ export class PortfolioController {
for (const [symbol, portfolioPosition] of Object.entries(holdings)) {
portfolioPublicDetails.holdings[symbol] = {
allocationCurrent: portfolioPosition.value / totalValue,
allocationInPercentage: portfolioPosition.value / totalValue,
countries: hasDetails ? portfolioPosition.countries : [],
currency: hasDetails ? portfolioPosition.currency : undefined,
dataSource: portfolioPosition.dataSource,
@ -452,7 +438,7 @@ export class PortfolioController {
sectors: hasDetails ? portfolioPosition.sectors : [],
symbol: portfolioPosition.symbol,
url: portfolioPosition.url,
value: portfolioPosition.value / totalValue
valueInPercentage: portfolioPosition.value / totalValue
};
}
@ -460,6 +446,7 @@ export class PortfolioController {
}
@Get('position/:dataSource/:symbol')
@UseInterceptors(RedactValuesInResponseInterceptor)
@UseInterceptors(TransformDataSourceInRequestInterceptor)
@UseInterceptors(TransformDataSourceInResponseInterceptor)
@UseGuards(AuthGuard('jwt'))
@ -468,27 +455,13 @@ export class PortfolioController {
@Param('dataSource') dataSource,
@Param('symbol') symbol
): Promise<PortfolioPositionDetail> {
let position = await this.portfolioService.getPosition(
const position = await this.portfolioService.getPosition(
dataSource,
impersonationId,
symbol
);
if (position) {
if (
impersonationId ||
this.userService.isRestrictedView(this.request.user)
) {
position = nullifyValuesInObject(position, [
'grossPerformance',
'investment',
'netPerformance',
'orders',
'quantity',
'value'
]);
}
return position;
}

View File

@ -537,12 +537,9 @@ export class PortfolioService {
holdings[item.symbol] = {
markets,
allocationCurrent: filteredValueInBaseCurrency.eq(0)
allocationInPercentage: filteredValueInBaseCurrency.eq(0)
? 0
: value.div(filteredValueInBaseCurrency).toNumber(),
allocationInvestment: item.investment
.div(totalInvestmentInBaseCurrency)
.toNumber(),
assetClass: symbolProfile.assetClass,
assetSubClass: symbolProfile.assetSubClass,
countries: symbolProfile.countries,
@ -614,6 +611,8 @@ export class PortfolioService {
)
.toNumber();
filteredValueInBaseCurrency = emergencyFund;
accounts[UNKNOWN_KEY] = {
balance: 0,
currency: userCurrency,
@ -786,8 +785,8 @@ export class PortfolioService {
historicalDataArray.push({
averagePrice: orders[0].unitPrice,
date: firstBuyDate,
quantity: orders[0].quantity,
value: orders[0].unitPrice
marketPrice: orders[0].unitPrice,
quantity: orders[0].quantity
});
}
@ -816,9 +815,9 @@ export class PortfolioService {
historicalDataArray.push({
date,
marketPrice,
averagePrice: currentAveragePrice,
quantity: currentQuantity,
value: marketPrice
quantity: currentQuantity
});
maxPrice = Math.max(marketPrice ?? 0, maxPrice);
@ -1040,29 +1039,21 @@ export class PortfolioService {
const portfolioStart = parseDate(transactionPoints[0].date);
const startDate = this.getStartDate(dateRange, portfolioStart);
const currentPositions = await portfolioCalculator.getCurrentPositions(
startDate
);
const {
currentValue,
errors,
grossPerformance,
grossPerformancePercentage,
hasErrors,
netPerformance,
netPerformancePercentage,
totalInvestment
} = await portfolioCalculator.getCurrentPositions(startDate);
const hasErrors = currentPositions.hasErrors;
const currentValue = currentPositions.currentValue.toNumber();
const currentGrossPerformance = currentPositions.grossPerformance;
const currentGrossPerformancePercent =
currentPositions.grossPerformancePercentage;
let currentNetPerformance = currentPositions.netPerformance;
let currentNetPerformancePercent =
currentPositions.netPerformancePercentage;
const totalInvestment = currentPositions.totalInvestment;
// if (currentGrossPerformance.mul(currentGrossPerformancePercent).lt(0)) {
// // If algebraic sign is different, harmonize it
// currentGrossPerformancePercent = currentGrossPerformancePercent.mul(-1);
// }
// if (currentNetPerformance.mul(currentNetPerformancePercent).lt(0)) {
// // If algebraic sign is different, harmonize it
// currentNetPerformancePercent = currentNetPerformancePercent.mul(-1);
// }
const currentGrossPerformance = grossPerformance;
const currentGrossPerformancePercent = grossPerformancePercentage;
let currentNetPerformance = netPerformance;
let currentNetPerformancePercent = netPerformancePercentage;
const historicalDataContainer = await this.getChart({
dateRange,
@ -1084,28 +1075,28 @@ export class PortfolioService {
}
return {
errors,
hasErrors,
chart: historicalDataContainer.items.map(
({
date,
netPerformance,
netPerformance: netPerformanceOfItem,
netPerformanceInPercentage,
totalInvestment,
totalInvestment: totalInvestmentOfItem,
value
}) => {
return {
date,
netPerformance,
netPerformanceInPercentage,
totalInvestment,
value
value,
netPerformance: netPerformanceOfItem,
totalInvestment: totalInvestmentOfItem
};
}
),
errors: currentPositions.errors,
firstOrderDate: parseDate(historicalDataContainer.items[0]?.date),
hasErrors: currentPositions.hasErrors || hasErrors,
performance: {
currentValue,
currentValue: currentValue.toNumber(),
currentGrossPerformance: currentGrossPerformance.toNumber(),
currentGrossPerformancePercent:
currentGrossPerformancePercent.toNumber(),
@ -1258,12 +1249,9 @@ export class PortfolioService {
for (const symbol of Object.keys(cashPositions)) {
// Calculate allocations for each currency
cashPositions[symbol].allocationCurrent = value.gt(0)
cashPositions[symbol].allocationInPercentage = value.gt(0)
? new Big(cashPositions[symbol].value).div(value).toNumber()
: 0;
cashPositions[symbol].allocationInvestment = investment.gt(0)
? new Big(cashPositions[symbol].investment).div(investment).toNumber()
: 0;
}
return cashPositions;
@ -1430,8 +1418,7 @@ export class PortfolioService {
}): PortfolioPosition {
return {
currency,
allocationCurrent: 0,
allocationInvestment: 0,
allocationInPercentage: 0,
assetClass: AssetClass.CASH,
assetSubClass: AssetClass.CASH,
countries: [],

View File

@ -1,6 +1,4 @@
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
import { PROPERTY_IS_USER_SIGNUP_ENABLED } from '@ghostfolio/common/config';
import { User, UserSettings } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import type { RequestWithUser } from '@ghostfolio/common/types';
@ -31,7 +29,6 @@ import { UserService } from './user.service';
@Controller('user')
export class UserController {
public constructor(
private readonly configurationService: ConfigurationService,
private readonly jwtService: JwtService,
private readonly propertyService: PropertyService,
@Inject(REQUEST) private readonly request: RequestWithUser,

View File

@ -97,6 +97,7 @@ export class UserService {
const {
accessToken,
Account,
Analytics,
authChallenge,
createdAt,
id,
@ -107,7 +108,12 @@ export class UserService {
thirdPartyId,
updatedAt
} = await this.prismaService.user.findUnique({
include: { Account: true, Settings: true, Subscription: true },
include: {
Account: true,
Analytics: true,
Settings: true,
Subscription: true
},
where: userWhereUniqueInput
});
@ -121,7 +127,8 @@ export class UserService {
role,
Settings,
thirdPartyId,
updatedAt
updatedAt,
activityCount: Analytics?.activityCount
};
if (user?.Settings) {
@ -154,15 +161,22 @@ export class UserService {
(user.Settings.settings as UserSettings).viewMode = 'DEFAULT';
}
let currentPermissions = getPermissions(user.role);
if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) {
user.subscription =
this.subscriptionService.getSubscription(Subscription);
}
let currentPermissions = getPermissions(user.role);
if (
Analytics?.activityCount % 25 === 0 &&
user.subscription?.type === 'Basic'
) {
currentPermissions.push(permissions.enableSubscriptionInterstitial);
}
if (user.subscription?.type === 'Premium') {
currentPermissions.push(permissions.reportDataGlitch);
if (user.subscription?.type === 'Premium') {
currentPermissions.push(permissions.reportDataGlitch);
}
}
if (this.configurationService.get('ENABLE_FEATURE_READ_ONLY_MODE')) {

View File

@ -1,4 +1,4 @@
import { cloneDeep, isObject } from 'lodash';
import { cloneDeep, isArray, isObject } from 'lodash';
export function hasNotDefinedValuesInObject(aObject: Object): boolean {
for (const key in aObject) {
@ -43,15 +43,23 @@ export function redactAttributes({
for (const option of options) {
if (redactedObject.hasOwnProperty(option.attribute)) {
redactedObject[option.attribute] =
option.valueMap[redactedObject[option.attribute]] ??
option.valueMap['*'] ??
redactedObject[option.attribute];
if (option.valueMap['*'] || option.valueMap['*'] === null) {
redactedObject[option.attribute] = option.valueMap['*'];
} else if (option.valueMap[redactedObject[option.attribute]]) {
redactedObject[option.attribute] =
option.valueMap[redactedObject[option.attribute]];
}
} else {
// If the attribute is not present on the current object,
// check if it exists on any nested objects
for (const property in redactedObject) {
if (typeof redactedObject[property] === 'object') {
if (isArray(redactedObject[property])) {
redactedObject[property] = redactedObject[property].map(
(currentObject) => {
return redactAttributes({ options, object: currentObject });
}
);
} else if (isObject(redactedObject[property])) {
// Recursively call the function on the nested object
redactedObject[property] = redactAttributes({
options,

View File

@ -1,5 +1,5 @@
import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface';
import { UserService } from '@ghostfolio/api/app/user/user.service';
import { redactAttributes } from '@ghostfolio/api/helper/object.helper';
import {
CallHandler,
ExecutionContext,
@ -28,59 +28,35 @@ export class RedactValuesInResponseInterceptor<T>
hasImpersonationId ||
this.userService.isRestrictedView(request.user)
) {
if (data.accounts) {
for (const accountId of Object.keys(data.accounts)) {
if (data.accounts[accountId]?.balance !== undefined) {
data.accounts[accountId].balance = null;
}
}
}
if (data.activities) {
data.activities = data.activities.map((activity: Activity) => {
if (activity.Account?.balance !== undefined) {
activity.Account.balance = null;
}
if (activity.comment !== undefined) {
activity.comment = null;
}
if (activity.fee !== undefined) {
activity.fee = null;
}
if (activity.feeInBaseCurrency !== undefined) {
activity.feeInBaseCurrency = null;
}
if (activity.quantity !== undefined) {
activity.quantity = null;
}
if (activity.unitPrice !== undefined) {
activity.unitPrice = null;
}
if (activity.value !== undefined) {
activity.value = null;
}
if (activity.valueInBaseCurrency !== undefined) {
activity.valueInBaseCurrency = null;
}
return activity;
});
}
if (data.filteredValueInBaseCurrency) {
data.filteredValueInBaseCurrency = null;
}
if (data.totalValueInBaseCurrency) {
data.totalValueInBaseCurrency = null;
}
data = redactAttributes({
object: data,
options: [
'balance',
'balanceInBaseCurrency',
'comment',
'convertedBalance',
'fee',
'feeInBaseCurrency',
'filteredValueInBaseCurrency',
'grossPerformance',
'investment',
'netPerformance',
'quantity',
'symbolMapping',
'totalBalanceInBaseCurrency',
'totalValueInBaseCurrency',
'unitPrice',
'value',
'valueInBaseCurrency'
].map((attribute) => {
return {
attribute,
valueMap: {
'*': null
}
};
})
});
}
return data;

View File

@ -116,6 +116,13 @@ const routes: Routes = [
'./pages/blog/2022/12/the-importance-of-tracking-your-personal-finances/the-importance-of-tracking-your-personal-finances-page.module'
).then((m) => m.TheImportanceOfTrackingYourPersonalFinancesPageModule)
},
{
path: 'blog/2023/01/ghostfolio-auf-sackgeld-vorgestellt',
loadChildren: () =>
import(
'./pages/blog/2023/01/ghostfolio-auf-sackgeld-vorgestellt/ghostfolio-auf-sackgeld-vorgestellt-page.module'
).then((m) => m.GhostfolioAufSackgeldVorgestelltPageModule)
},
{
path: 'demo',
loadChildren: () =>

View File

@ -25,6 +25,7 @@ import { DateFormats } from './adapter/date-formats';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { GfHeaderModule } from './components/header/header.module';
import { GfSubscriptionInterstitialDialogModule } from './components/subscription-interstitial-dialog/subscription-interstitial-dialog.module';
import { authInterceptorProviders } from './core/auth.interceptor';
import { httpResponseInterceptorProviders } from './core/http-response.interceptor';
import { LanguageService } from './core/language.service';
@ -40,6 +41,7 @@ export function NgxStripeFactory(): string {
BrowserAnimationsModule,
BrowserModule,
GfHeaderModule,
GfSubscriptionInterstitialDialogModule,
HttpClientModule,
MarkdownModule.forRoot(),
MatAutocompleteModule,

View File

@ -36,7 +36,7 @@ export class MarketDataDetailDialog implements OnDestroy {
this.dateAdapter.setLocale(this.locale);
}
public onCancel(): void {
public onCancel() {
this.dialogRef.close({ withRefresh: false });
}

View File

@ -110,13 +110,12 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
range: this.user?.settings?.dateRange
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((response) => {
this.errors = response.errors;
this.hasError = response.hasErrors;
this.performance = response.performance;
.subscribe(({ chart, errors, performance }) => {
this.errors = errors;
this.performance = performance;
this.isLoadingPerformance = false;
this.historicalDataItems = response.chart.map(
this.historicalDataItems = chart.map(
({ date, netPerformanceInPercentage }) => {
return {
date,

View File

@ -37,7 +37,6 @@
[baseCurrency]="user?.settings?.baseCurrency"
[deviceType]="deviceType"
[errors]="errors"
[hasError]="hasError"
[isAllTimeHigh]="isAllTimeHigh"
[isAllTimeLow]="isAllTimeLow"
[isLoading]="isLoadingPerformance"

View File

@ -3,14 +3,14 @@
<div
class="flex-grow-1 status text-muted text-right"
[title]="
hasError && !isLoading
errors?.length > 0 && !isLoading
? 'Sorry! Our data provider partner is experiencing the hiccups.'
: ''
"
(click)="errors?.length > 0 && onShowErrors()"
>
<ion-icon
*ngIf="hasError && !isLoading"
*ngIf="errors?.length > 0 && !isLoading"
name="alert-circle-outline"
></ion-icon>
</div>

View File

@ -28,7 +28,6 @@ export class PortfolioPerformanceComponent implements OnChanges, OnInit {
@Input() baseCurrency: string;
@Input() deviceType: string;
@Input() errors: ResponseError['errors'];
@Input() hasError: boolean;
@Input() isAllTimeHigh: boolean;
@Input() isAllTimeLow: boolean;
@Input() isLoading: boolean;

View File

@ -111,7 +111,7 @@ export class PositionDetailDialog implements OnDestroy, OnInit {
return {
date: historicalDataItem.date,
value: historicalDataItem.value
value: historicalDataItem.marketPrice
};
}
);

View File

@ -0,0 +1 @@
export interface SubscriptionInterstitialDialogParams {}

View File

@ -0,0 +1,22 @@
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { SubscriptionInterstitialDialogParams } from './interfaces/interfaces';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'd-flex flex-column flex-grow-1 h-100' },
selector: 'gf-subscription-interstitial-dialog',
styleUrls: ['./subscription-interstitial-dialog.scss'],
templateUrl: 'subscription-interstitial-dialog.html'
})
export class SubscriptionInterstitialDialog {
public constructor(
@Inject(MAT_DIALOG_DATA) public data: SubscriptionInterstitialDialogParams,
public dialogRef: MatDialogRef<SubscriptionInterstitialDialog>
) {}
public onCancel() {
this.dialogRef.close({});
}
}

View File

@ -0,0 +1,42 @@
<h1 class="align-items-center d-flex" mat-dialog-title>
<span>Ghostfolio Premium</span>
<gf-premium-indicator class="ml-1"></gf-premium-indicator>
</h1>
<div class="flex-grow-1" mat-dialog-content>
<p class="h5" i18n>
Are you an ambitious investor who needs the full picture?
</p>
<p i18n>
By upgrading to Ghostfolio Premium, you will get these additional features:
</p>
<ul class="list-unstyled mb-3">
<li class="align-items-center d-flex mb-1">
<ion-icon class="mr-1" name="checkmark-circle-outline"></ion-icon>
<span i18n>Portfolio Summary</span>
</li>
<li class="align-items-center d-flex mb-1">
<ion-icon class="mr-1" name="checkmark-circle-outline"></ion-icon>
<span i18n>Performance Benchmarks</span>
</li>
<li class="align-items-center d-flex mb-1">
<ion-icon class="mr-1" name="checkmark-circle-outline"></ion-icon>
<span i18n>Allocations</span>
</li>
<li class="align-items-center d-flex mb-1">
<ion-icon class="mr-1" name="checkmark-circle-outline"></ion-icon>
<span i18n>FIRE Calculator</span>
</li>
<li class="align-items-center d-flex mb-1">
<ion-icon class="mr-1" name="checkmark-circle-outline"></ion-icon>
<a i18n [routerLink]="['/features']">and more Features...</a>
</li>
</ul>
<p>Refine your personal investment strategy now.</p>
</div>
<div class="justify-content-end" mat-dialog-actions>
<button i18n mat-button (click)="onCancel()">Skip</button>
<a color="primary" mat-flat-button [routerLink]="['/pricing']">
<span i18n>Upgrade Plan</span>
<ion-icon class="ml-1" name="arrow-forward-outline"></ion-icon>
</a>
</div>

View File

@ -0,0 +1,21 @@
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatDialogModule } from '@angular/material/dialog';
import { RouterModule } from '@angular/router';
import { GfPremiumIndicatorModule } from '@ghostfolio/ui/premium-indicator';
import { SubscriptionInterstitialDialog } from './subscription-interstitial-dialog.component';
@NgModule({
declarations: [SubscriptionInterstitialDialog],
imports: [
CommonModule,
GfPremiumIndicatorModule,
MatButtonModule,
MatDialogModule,
RouterModule
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class GfSubscriptionInterstitialDialogModule {}

View File

@ -0,0 +1,11 @@
:host {
display: block;
.mat-dialog-content {
max-height: unset;
ion-icon[name='checkmark-circle-outline'] {
color: rgba(var(--palette-accent-500), 1);
}
}
}

View File

@ -42,9 +42,11 @@
href="https://twitter.com/ghostfolio_"
title="Tweet to Ghostfolio on Twitter"
>@ghostfolio_</a
>, send an e-mail to
<a href="mailto:hi@ghostfol.io" title="Send an e-mail"
>hi@ghostfol.io</a
><ng-container *ngIf="hasPermissionForSubscription"
>, send an e-mail to
<a href="mailto:hi@ghostfol.io" title="Send an e-mail"
>hi@ghostfol.io</a
></ng-container
>
or open an issue at
<a

View File

@ -26,7 +26,7 @@ export class CreateOrUpdateAccessDialog implements OnDestroy {
ngOnInit() {}
public onCancel(): void {
public onCancel() {
this.dialogRef.close();
}

View File

@ -36,7 +36,7 @@ export class CreateOrUpdateAccountDialog implements OnDestroy {
this.platforms = platforms;
}
public onCancel(): void {
public onCancel() {
this.dialogRef.close();
}

View File

@ -7,7 +7,7 @@
<div class="mb-3 text-muted"><small>2022-07-23</small></div>
<img
alt="Ghostfolio meets Internet Identity Teaser"
class="rounded w-100"
class="border rounded w-100"
src="../assets/images/blog/ghostfolio-meets-internet-identity.png"
title="Ghostfolio meets Internet Identity"
/>

View File

@ -0,0 +1,20 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuard } from '@ghostfolio/client/core/auth.guard';
import { GhostfolioAufSackgeldVorgestelltPageComponent } from './ghostfolio-auf-sackgeld-vorgestellt-page.component';
const routes: Routes = [
{
canActivate: [AuthGuard],
component: GhostfolioAufSackgeldVorgestelltPageComponent,
path: '',
title: 'Ghostfolio auf Sackgeld.com vorgestellt'
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class GhostfolioAufSackgeldVorgestelltPageRoutingModule {}

View File

@ -0,0 +1,9 @@
import { Component } from '@angular/core';
@Component({
host: { class: 'page' },
selector: 'gf-ghostfolio-auf-sackgeld-vorgestellt-page',
styleUrls: ['./ghostfolio-auf-sackgeld-vorgestellt-page.scss'],
templateUrl: './ghostfolio-auf-sackgeld-vorgestellt-page.html'
})
export class GhostfolioAufSackgeldVorgestelltPageComponent {}

View File

@ -0,0 +1,178 @@
<div class="blog container">
<div class="row">
<div class="col-md-8 offset-md-2">
<article>
<div class="mb-4 text-center">
<h1 class="mb-1">Ghostfolio auf Sackgeld.com vorgestellt</h1>
<div class="mb-3 text-muted"><small>2023-01-21</small></div>
<img
alt="Ghostfolio auf Sackgeld.com vorgestellt Teaser"
class="border rounded w-100"
src="../assets/images/blog/ghostfolio-x-sackgeld.png"
title="Ghostfolio auf Sackgeld.com vorgestellt"
/>
</div>
<section class="mb-4">
<p>
Wir freuen uns darüber, dass unsere Open Source Portfolio Tracking
Software <a href="https://ghostfol.io">Ghostfolio</a> auf dem
FinTech Newsportal <i>Sackgeld.com</i> vorgestellt wurde.
</p>
<div class="container my-4">
<div class="row">
<div class="col-md-10 offset-md-1">
<blockquote class="blockquote m-0">
<p class="mb-0">
«Ghostfolio ist ein umfassender Portfolio Performance
Tracker der einfach zu bedienen ist, mit einigen sehr
innovativen Features aufwartet und echten Mehrwert für den
Investor bringt.»
</p>
</blockquote>
</div>
</div>
</div>
<p>
Im ausführlichen Bericht wird die Funktionsweise von Ghostfolio
erläutert, die unterstützten Assets aufgeführt sowie die
Preisstruktur im Vergleich zu anderen Anbietern dargelegt.
</p>
</section>
<section class="mb-4">
<h2 class="h4">
Ghostfolio Open Source Wealth Management Software
</h2>
<p>
Ghostfolio ermöglicht es dir, dein Portfolio einfach zu verfolgen
und zu analysieren. Es bietet dir detaillierte Informationen über
deine Positionen, historische Entwicklung, Performance und die
Zusammenstellung deines Portfolios. Durch die Open Source-Lizenz (<a
href="https://github.com/ghostfolio/ghostfolio/blob/main/LICENSE"
target="_blank"
>GNU Affero General Public License v3.0</a
>) wird die Software ständig weiterentwickelt, verbessert und du
hast sogar selbst die Möglichkeit, dich daran zu beteiligen. Wir
sind davon überzeugt, mit diesem Open-Source-Ansatz von Ghostfolio
das Finanzwissen und Investieren für alle zugänglicher zu machen.
</p>
</section>
<section class="mb-4">
<h2 class="h4">Sackgeld.com App für ein höheres Sackgeld</h2>
<p>
Das Schweizer FinTech Nachrichtenportal
<a href="https://www.sackgeld.com" target="_blank">Sackgeld.com</a>
informiert über die neuesten Entwicklungen und Innovationen im
Bereich FinTech. Dazu gehören News, Artikel und persönliche
Erfahrungen aus der Welt der digitalen Finanz Apps, Säule 3a, P2P
und Immobilien.
</p>
</section>
<section class="mb-4">
<p>
Wenn du mehr über Ghostfolio erfahren möchtest, kannst du hier den
ganzen Artikel nachlesen:
<a
href="https://www.sackgeld.com/was-taugt-ghostfolio-als-portfolio-performance-tracking-tool"
target="_blank"
>Was taugt Ghostfolio als Portfolio Performance Tracking-Tool?</a
>
</p>
</section>
<section class="mb-4">
<ul class="list-inline">
<li class="list-inline-item">
<span class="badge badge-light">AGPL-3.0</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Aktie</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Altersvorsorge</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Anlage</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">App</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Asset</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Feedback</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Finanzwissen</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Fintech</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Ghostfolio</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Immobilien</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Innovation</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Investieren</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Lizenz</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Media</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Open Source</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">OSS</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">P2P</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Performance</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Portfolio</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Presse</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Sackgeld</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Säule 3a</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Schweiz</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Software</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Taschengeld</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Tool</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Vermögen</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Vorsorge</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Wealth Management</span>
</li>
</ul>
</section>
</article>
</div>
</div>
</div>

View File

@ -0,0 +1,17 @@
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { GhostfolioAufSackgeldVorgestelltPageRoutingModule } from './ghostfolio-auf-sackgeld-vorgestellt-page-routing.module';
import { GhostfolioAufSackgeldVorgestelltPageComponent } from './ghostfolio-auf-sackgeld-vorgestellt-page.component';
@NgModule({
declarations: [GhostfolioAufSackgeldVorgestelltPageComponent],
imports: [
CommonModule,
GhostfolioAufSackgeldVorgestelltPageRoutingModule,
RouterModule
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class GhostfolioAufSackgeldVorgestelltPageModule {}

View File

@ -2,6 +2,32 @@
<div class="mb-5 row">
<div class="col">
<h3 class="d-none d-sm-block mb-3 text-center" i18n>Blog</h3>
<mat-card class="mb-3">
<mat-card-content>
<div class="container p-0">
<div class="flex-nowrap no-gutters row">
<a
class="d-flex overflow-hidden w-100"
href="../de/blog/2023/01/ghostfolio-auf-sackgeld-vorgestellt"
>
<div class="flex-grow-1 overflow-hidden">
<div class="h6 m-0 text-truncate">
Ghostfolio auf Sackgeld.com vorgestellt
</div>
<div class="d-flex text-muted">2023-01-21</div>
</div>
<div class="align-items-center d-flex">
<ion-icon
class="chevron text-muted"
name="chevron-forward-outline"
size="small"
></ion-icon>
</div>
</a>
</div>
</div>
</mat-card-content>
</mat-card>
<mat-card class="mb-3">
<mat-card-content>
<div class="container p-0">

View File

@ -106,7 +106,7 @@
<div class="row mb-5">
<div class="col-12 text-center text-muted"><small>As seen in</small></div>
<div class="col-md-2 d-flex justify-content-center my-1">
<div class="col-md-3 d-flex justify-content-center my-1">
<a
class="d-block logo logo-alternative-to mask"
href="https://alternativeto.net"
@ -114,7 +114,7 @@
title="AlternativeTo - Crowdsourced software recommendations"
></a>
</div>
<div class="col-md-2 d-flex justify-content-center my-1">
<div class="col-md-3 d-flex justify-content-center my-1">
<a
class="d-block logo logo-awesome"
href="https://github.com/awesome-selfhosted/awesome-selfhosted"
@ -122,7 +122,7 @@
title="Awesome-Selfhosted: A list of Free Software network services and web applications which can be hosted on your own servers"
></a>
</div>
<div class="col-md-2 d-flex justify-content-center my-1">
<div class="col-md-3 d-flex justify-content-center my-1">
<a
class="d-block logo logo-openstartup"
href="https://openstartup.tm"
@ -130,7 +130,7 @@
title="Open Startup: The most complete list of open startups"
></a>
</div>
<div class="col-md-2 d-flex justify-content-center my-1">
<div class="col-md-3 d-flex justify-content-center my-1">
<a
class="d-block logo logo-privacy-tools mask"
href="https://www.privacytools.io"
@ -138,7 +138,7 @@
title="Privacy Tools: Software Alternatives and Encryption"
></a>
</div>
<div class="col-md-2 d-flex justify-content-center my-1">
<div class="col-md-3 d-flex justify-content-center my-1">
<a
class="d-block logo logo-product-hunt"
href="https://www.producthunt.com"
@ -146,7 +146,23 @@
title="Product Hunt The best new products in tech."
></a>
</div>
<div class="col-md-2 d-flex justify-content-center my-1">
<div class="col-md-3 d-flex justify-content-center my-1">
<a
class="d-block logo logo-sackgeld mask"
href="https://www.sackgeld.com"
target="_blank"
title="Sackgeld.com Apps für ein höheres Sackgeld"
></a>
</div>
<div class="col-md-3 d-flex justify-content-center my-1">
<a
class="d-block logo logo-sourceforge mask"
href="https://sourceforge.net"
target="_blank"
title="SourceForge: The Complete Open-Source and Business Software Platform"
></a>
</div>
<div class="col-md-3 d-flex justify-content-center my-1">
<a
class="d-block logo logo-unraid mask"
href="https://unraid.net"

View File

@ -75,6 +75,14 @@
filter: grayscale(1);
}
&.logo-sackgeld {
mask-image: url('/assets/images/logo-sackgeld.png');
}
&.logo-sourceforge {
mask-image: url('/assets/images/logo-sourceforge.svg');
}
&.logo-unraid {
mask-image: url('/assets/images/logo-unraid.svg');
}
@ -112,6 +120,8 @@
&.logo-agplv3,
&.logo-alternative-to,
&.logo-privacy-tools,
&.logo-sackgeld,
&.logo-sourceforge,
&.logo-unraid {
background-color: rgba(var(--light-primary-text));
}

View File

@ -80,7 +80,7 @@ export class ImportActivitiesDialog implements OnDestroy {
}
}
public onCancel(): void {
public onCancel() {
this.dialogRef.close();
}

View File

@ -18,9 +18,10 @@ import {
User
} from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { Market, ToggleOption } from '@ghostfolio/common/types';
import { Market } from '@ghostfolio/common/types';
import { translate } from '@ghostfolio/ui/i18n';
import { Account, AssetClass, DataSource } from '@prisma/client';
import { isNumber } from 'lodash';
import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject } from 'rxjs';
import { distinctUntilChanged, switchMap, takeUntil } from 'rxjs/operators';
@ -53,11 +54,6 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
public markets: {
[key in Market]: { name: string; value: number };
};
public period = 'current';
public periodOptions: ToggleOption[] = [
{ label: $localize`Initial`, value: 'original' },
{ label: $localize`Current`, value: 'current' }
];
public placeholder = '';
public portfolioDetails: PortfolioDetails;
public positions: {
@ -146,7 +142,7 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
.subscribe((portfolioDetails) => {
this.portfolioDetails = portfolioDetails;
this.initializeAnalysisData(this.period);
this.initializeAnalysisData();
this.isLoading = false;
@ -248,7 +244,7 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
};
}
public initializeAnalysisData(aPeriod: string) {
public initializeAnalysisData() {
this.initialize();
for (const [id, { current, name, original }] of Object.entries(
@ -257,7 +253,7 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
this.accounts[id] = {
id,
name,
value: aPeriod === 'original' ? original : current
value: current
};
}
@ -266,18 +262,10 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
)) {
let value = 0;
if (aPeriod === 'original') {
if (this.hasImpersonationId) {
value = position.allocationInvestment;
} else {
value = position.investment;
}
if (this.hasImpersonationId) {
value = position.allocationInPercentage;
} else {
if (this.hasImpersonationId) {
value = position.allocationCurrent;
} else {
value = position.value;
}
value = position.value;
}
this.positions[symbol] = {
@ -294,14 +282,11 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
if (position.countries.length > 0) {
this.markets.developedMarkets.value +=
position.markets.developedMarkets *
(aPeriod === 'original' ? position.investment : position.value);
position.markets.developedMarkets * position.value;
this.markets.emergingMarkets.value +=
position.markets.emergingMarkets *
(aPeriod === 'original' ? position.investment : position.value);
position.markets.emergingMarkets * position.value;
this.markets.otherMarkets.value +=
position.markets.otherMarkets *
(aPeriod === 'original' ? position.investment : position.value);
position.markets.otherMarkets * position.value;
for (const country of position.countries) {
const { code, continent, name, weight } = country;
@ -311,11 +296,7 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
} else {
this.continents[continent] = {
name: continent,
value:
weight *
(aPeriod === 'original'
? this.portfolioDetails.holdings[symbol].investment
: this.portfolioDetails.holdings[symbol].value)
value: weight * this.portfolioDetails.holdings[symbol].value
};
}
@ -324,24 +305,16 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
} else {
this.countries[code] = {
name,
value:
weight *
(aPeriod === 'original'
? this.portfolioDetails.holdings[symbol].investment
: this.portfolioDetails.holdings[symbol].value)
value: weight * this.portfolioDetails.holdings[symbol].value
};
}
}
} else {
this.continents[UNKNOWN_KEY].value +=
aPeriod === 'original'
? this.portfolioDetails.holdings[symbol].investment
: this.portfolioDetails.holdings[symbol].value;
this.portfolioDetails.holdings[symbol].value;
this.countries[UNKNOWN_KEY].value +=
aPeriod === 'original'
? this.portfolioDetails.holdings[symbol].investment
: this.portfolioDetails.holdings[symbol].value;
this.portfolioDetails.holdings[symbol].value;
}
if (position.sectors.length > 0) {
@ -353,19 +326,13 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
} else {
this.sectors[name] = {
name,
value:
weight *
(aPeriod === 'original'
? this.portfolioDetails.holdings[symbol].investment
: this.portfolioDetails.holdings[symbol].value)
value: weight * this.portfolioDetails.holdings[symbol].value
};
}
}
} else {
this.sectors[UNKNOWN_KEY].value +=
aPeriod === 'original'
? this.portfolioDetails.holdings[symbol].investment
: this.portfolioDetails.holdings[symbol].value;
this.portfolioDetails.holdings[symbol].value;
}
}
@ -373,7 +340,9 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
dataSource: position.dataSource,
name: position.name,
symbol: prettifySymbol(symbol),
value: aPeriod === 'original' ? position.investment : position.value
value: isNumber(position.value)
? position.value
: position.valueInPercentage
};
}
@ -391,19 +360,13 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
}
public onAccountChartClicked({ symbol }: UniqueAsset) {
if (symbol) {
if (symbol && symbol !== UNKNOWN_KEY) {
this.router.navigate([], {
queryParams: { accountId: symbol, accountDetailDialog: true }
});
}
}
public onChangePeriod(aValue: string) {
this.period = aValue;
this.initializeAnalysisData(this.period);
}
public onSymbolChartClicked({ dataSource, symbol }: UniqueAsset) {
if (dataSource && symbol) {
this.router.navigate([], {

View File

@ -39,12 +39,6 @@
<mat-card class="mb-3">
<mat-card-header class="overflow-hidden w-100">
<mat-card-title class="text-truncate" i18n>By Account</mat-card-title>
<gf-toggle
[defaultValue]="period"
[isLoading]="false"
[options]="periodOptions"
(change)="onChangePeriod($event.value)"
></gf-toggle>
</mat-card-header>
<mat-card-content>
<gf-portfolio-proportion-chart
@ -70,12 +64,6 @@
class="ml-1"
></gf-premium-indicator
></mat-card-title>
<gf-toggle
[defaultValue]="period"
[isLoading]="false"
[options]="periodOptions"
(change)="onChangePeriod($event.value)"
></gf-toggle>
</mat-card-header>
<mat-card-content>
<gf-portfolio-proportion-chart
@ -99,12 +87,6 @@
class="ml-1"
></gf-premium-indicator
></mat-card-title>
<gf-toggle
[defaultValue]="period"
[isLoading]="false"
[options]="periodOptions"
(change)="onChangePeriod($event.value)"
></gf-toggle>
</mat-card-header>
<mat-card-content>
<gf-portfolio-proportion-chart
@ -124,12 +106,6 @@
<mat-card-title class="align-items-center d-flex text-truncate">
<ng-container i18n>By Holding</ng-container></mat-card-title
>
<gf-toggle
[defaultValue]="period"
[isLoading]="false"
[options]="periodOptions"
(change)="onChangePeriod($event.value)"
></gf-toggle>
</mat-card-header>
<mat-card-content>
<gf-portfolio-proportion-chart
@ -157,12 +133,6 @@
class="ml-1"
></gf-premium-indicator
></mat-card-title>
<gf-toggle
[defaultValue]="period"
[isLoading]="false"
[options]="periodOptions"
(change)="onChangePeriod($event.value)"
></gf-toggle>
</mat-card-header>
<mat-card-content>
<gf-portfolio-proportion-chart
@ -187,12 +157,6 @@
class="ml-1"
></gf-premium-indicator
></mat-card-title>
<gf-toggle
[defaultValue]="period"
[isLoading]="false"
[options]="periodOptions"
(change)="onChangePeriod($event.value)"
></gf-toggle>
</mat-card-header>
<mat-card-content>
<gf-portfolio-proportion-chart
@ -216,12 +180,6 @@
class="ml-1"
></gf-premium-indicator
></mat-card-title>
<gf-toggle
[defaultValue]="period"
[isLoading]="false"
[options]="periodOptions"
(change)="onChangePeriod($event.value)"
></gf-toggle>
</mat-card-header>
<mat-card-content>
<gf-portfolio-proportion-chart
@ -248,12 +206,6 @@
class="ml-1"
></gf-premium-indicator
></mat-card-title>
<gf-toggle
[defaultValue]="period"
[isLoading]="false"
[options]="periodOptions"
(change)="onChangePeriod($event.value)"
></gf-toggle>
</mat-card-header>
<mat-card-content>
<gf-world-map-chart

View File

@ -3,7 +3,6 @@ import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { MatCardModule } from '@angular/material/card';
import { MatDialogModule } from '@angular/material/dialog';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { GfToggleModule } from '@ghostfolio/client/components/toggle/toggle.module';
import { GfWorldMapChartModule } from '@ghostfolio/client/components/world-map-chart/world-map-chart.module';
import { GfActivitiesFilterModule } from '@ghostfolio/ui/activities-filter/activities-filter.module';
import { GfPortfolioProportionChartModule } from '@ghostfolio/ui/portfolio-proportion-chart/portfolio-proportion-chart.module';
@ -21,7 +20,6 @@ import { AllocationsPageComponent } from './allocations-page.component';
GfActivitiesFilterModule,
GfPortfolioProportionChartModule,
GfPremiumIndicatorModule,
GfToggleModule,
GfWorldMapChartModule,
GfValueModule,
MatCardModule,

View File

@ -19,7 +19,7 @@ import { DateRange, GroupBy, ToggleOption } from '@ghostfolio/common/types';
import { translate } from '@ghostfolio/ui/i18n';
import { AssetClass, DataSource, SymbolProfile } from '@prisma/client';
import { differenceInDays } from 'date-fns';
import { sortBy } from 'lodash';
import { isNumber, sortBy } from 'lodash';
import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject } from 'rxjs';
import { distinctUntilChanged, map, takeUntil } from 'rxjs/operators';
@ -312,12 +312,13 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
date,
netPerformanceInPercentage,
totalInvestment,
value
value,
valueInPercentage
} of chart) {
this.investments.push({ date, investment: totalInvestment });
this.performanceDataItems.push({
date,
value
value: isNumber(value) ? value : valueInPercentage
});
this.performanceDataItemsInPercentage.push({
date,

View File

@ -31,50 +31,71 @@
<mat-card class="d-flex flex-column h-100">
<div class="flex-grow-1">
<h4>Open Source</h4>
<p>
For tech-savvy investors who prefer to run
<strong>Ghostfolio</strong> on their own infrastructure.
<p i18n>
For tech-savvy investors who prefer to run Ghostfolio on their
own infrastructure.
</p>
<ul class="list-unstyled mb-3">
<li class="align-items-center d-flex mb-1">
<ion-icon
class="mr-1 text-muted"
class="mr-1"
name="checkmark-circle-outline"
></ion-icon>
<span>Unlimited Transactions</span>
<span i18n>Unlimited Transactions</span>
</li>
<li class="align-items-center d-flex mb-1">
<ion-icon
class="mr-1 text-muted"
class="mr-1"
name="checkmark-circle-outline"
></ion-icon>
<span>Portfolio Performance</span>
<span i18n>Unlimited Accounts</span>
</li>
<li class="align-items-center d-flex mb-1">
<ion-icon
class="mr-1 text-muted"
class="mr-1"
name="checkmark-circle-outline"
></ion-icon>
<span>Zen Mode</span>
<span i18n>Portfolio Performance</span>
</li>
<li class="align-items-center d-flex mb-1">
<ion-icon
class="mr-1 text-muted"
class="mr-1"
name="checkmark-circle-outline"
></ion-icon>
<span>Portfolio Summary</span>
<span i18n>Portfolio Summary</span>
</li>
<li class="align-items-center d-flex mb-1">
<ion-icon
class="mr-1 text-muted"
class="mr-1"
name="checkmark-circle-outline"
></ion-icon>
<span>Advanced Insights</span>
<span i18n>Performance Benchmarks</span>
</li>
<li class="align-items-center d-flex mb-1">
<ion-icon
class="mr-1"
name="checkmark-circle-outline"
></ion-icon>
<span i18n>Allocations</span>
</li>
<li class="align-items-center d-flex mb-1">
<ion-icon
class="mr-1"
name="checkmark-circle-outline"
></ion-icon>
<span i18n>FIRE Calculator</span>
</li>
<li class="align-items-center d-flex mb-1">
<ion-icon
class="mr-1"
name="checkmark-circle-outline"
></ion-icon>
<a i18n [routerLink]="['/features']">and more Features...</a>
</li>
</ul>
</div>
<p>Self-hosted, update manually.</p>
<p class="h5 text-right">Free</p>
<p i18n>Self-hosted, update manually.</p>
<p class="h5 text-right" i18n>Free</p>
<div
*ngIf="user?.subscription?.type === 'Basic'"
class="d-none d-lg-block hidden mt-3 text-center"
@ -92,31 +113,54 @@
[ngClass]="{ 'active': user?.subscription?.type === 'Basic' }"
>
<div class="flex-grow-1">
<h4 class="align-items-center d-flex">Basic</h4>
<p>
<div class="align-items-center d-flex mb-2">
<h4 class="flex-grow-1 m-0">Basic</h4>
<div *ngIf="user?.subscription?.type === 'Basic'">
<ion-icon class="mr-1" name="checkmark-outline"></ion-icon>
</div>
</div>
<p i18n>
For new investors who are just getting started with trading.
</p>
<ul class="list-unstyled mb-3">
<li class="align-items-center d-flex mb-1">
<ion-icon
class="mr-1 text-muted"
class="mr-1"
name="checkmark-circle-outline"
></ion-icon>
<span>Unlimited Transactions</span>
<span i18n>Unlimited Transactions</span>
</li>
<li class="align-items-center d-flex mb-1">
<ion-icon
class="mr-1 text-muted"
class="mr-1"
name="checkmark-circle-outline"
></ion-icon>
<span>Portfolio Performance</span>
<span i18n>Unlimited Accounts</span>
</li>
<li class="align-items-center d-flex mb-1">
<ion-icon
class="mr-1 text-muted"
class="mr-1"
name="checkmark-circle-outline"
></ion-icon>
<span i18n>Portfolio Performance</span>
</li>
<li>
<ion-icon
class="invisible"
name="checkmark-circle-outline"
></ion-icon>
</li>
<li>
<ion-icon
class="invisible"
name="checkmark-circle-outline"
></ion-icon>
</li>
<li>
<ion-icon
class="invisible"
name="checkmark-circle-outline"
></ion-icon>
<span>Zen Mode</span>
</li>
<li>
<ion-icon
@ -132,8 +176,8 @@
</li>
</ul>
</div>
<p>Fully managed <strong>Ghostfolio</strong> cloud offering.</p>
<p class="h5 text-right">Free</p>
<p i18n>Fully managed Ghostfolio cloud offering.</p>
<p class="h5 text-right" i18n>Free</p>
<div
*ngIf="user?.subscription?.type === 'Basic'"
class="d-none d-lg-block hidden mt-3 text-center"
@ -151,56 +195,82 @@
[ngClass]="{ 'active': user?.subscription?.type === 'Premium' }"
>
<div class="flex-grow-1">
<h4 class="align-items-center d-flex">
<span>Premium</span>
<gf-premium-indicator
class="ml-1"
[enableLink]="false"
></gf-premium-indicator>
</h4>
<p>
<div class="align-items-center d-flex mb-2">
<h4 class="align-items-center d-flex flex-grow-1 m-0">
<span>Premium</span>
<gf-premium-indicator
class="ml-1"
[enableLink]="false"
></gf-premium-indicator>
</h4>
<div *ngIf="user?.subscription?.type === 'Premium'">
<ion-icon class="mr-1" name="checkmark-outline"></ion-icon>
</div>
</div>
<p i18n>
For ambitious investors who need the full picture of their
financial assets.
</p>
<ul class="list-unstyled mb-3">
<li class="align-items-center d-flex mb-1">
<ion-icon
class="mr-1 text-muted"
class="mr-1"
name="checkmark-circle-outline"
></ion-icon>
<span>Unlimited Transactions</span>
<span i18n>Unlimited Transactions</span>
</li>
<li class="align-items-center d-flex mb-1">
<ion-icon
class="mr-1 text-muted"
class="mr-1"
name="checkmark-circle-outline"
></ion-icon>
<span>Portfolio Performance</span>
<span i18n>Unlimited Accounts</span>
</li>
<li class="align-items-center d-flex mb-1">
<ion-icon
class="mr-1 text-muted"
class="mr-1"
name="checkmark-circle-outline"
></ion-icon>
<span>Zen Mode</span>
<span i18n>Portfolio Performance</span>
</li>
<li class="align-items-center d-flex mb-1">
<ion-icon
class="mr-1 text-muted"
class="mr-1"
name="checkmark-circle-outline"
></ion-icon>
<span>Portfolio Summary</span>
<span i18n>Portfolio Summary</span>
</li>
<li class="align-items-center d-flex mb-1">
<ion-icon
class="mr-1 text-muted"
class="mr-1"
name="checkmark-circle-outline"
></ion-icon>
<span>Advanced Insights</span>
<span i18n>Performance Benchmarks</span>
</li>
<li class="align-items-center d-flex mb-1">
<ion-icon
class="mr-1"
name="checkmark-circle-outline"
></ion-icon>
<span i18n>Allocations</span>
</li>
<li class="align-items-center d-flex mb-1">
<ion-icon
class="mr-1"
name="checkmark-circle-outline"
></ion-icon>
<span i18n>FIRE Calculator</span>
</li>
<li class="align-items-center d-flex mb-1">
<ion-icon
class="mr-1"
name="checkmark-circle-outline"
></ion-icon>
<a i18n [routerLink]="['/features']">and more Features...</a>
</li>
</ul>
</div>
<p>Fully managed <strong>Ghostfolio</strong> cloud offering.</p>
<p i18n>Fully managed Ghostfolio cloud offering.</p>
<p class="h5 text-right" [hidden]="!price">
<span class="font-weight-normal">
<ng-container *ngIf="coupon"
@ -221,11 +291,16 @@
*ngIf="user?.subscription?.type === 'Basic'"
class="mt-3 text-center"
>
<a color="primary" mat-flat-button [routerLink]="['/account']">
<a
color="primary"
i18n
mat-flat-button
[routerLink]="['/account']"
>
Upgrade Plan
</a>
<p class="m-0 text-muted">
<small>One-time payment, no auto-renewal.</small>
<small i18n>One-time payment, no auto-renewal.</small>
</p>
</div>
</mat-card>
@ -235,10 +310,10 @@
</div>
<div *ngIf="!user" class="row">
<div class="col mt-3 text-center">
<a color="primary" mat-flat-button [routerLink]="['/register']">
<a color="primary" i18n mat-flat-button [routerLink]="['/register']">
Get Started
</a>
<p class="m-0 text-muted"><small>Its free.</small></p>
<p class="m-0 text-muted"><small i18n>Its free.</small></p>
</div>
</div>
</div>

View File

@ -2,12 +2,14 @@
color: rgb(var(--dark-primary-text));
display: block;
a {
color: rgba(var(--palette-primary-500), 1);
font-weight: 500;
p {
a {
color: rgba(var(--palette-primary-500), 1);
font-weight: 500;
&:hover {
color: rgba(var(--palette-primary-300), 1);
&:hover {
color: rgba(var(--palette-primary-300), 1);
}
}
}
@ -17,6 +19,10 @@
border-color: rgba(var(--palette-primary-500), 1);
box-shadow: 0 0 0 1px rgba(var(--palette-primary-500), 1);
}
ion-icon[name='checkmark-circle-outline'] {
color: rgba(var(--palette-accent-500), 1);
}
}
}

View File

@ -9,6 +9,7 @@ import {
} from '@ghostfolio/common/interfaces';
import { Market } from '@ghostfolio/common/types';
import { StatusCodes } from 'http-status-codes';
import { isNumber } from 'lodash';
import { DeviceDetectorService } from 'ngx-device-detector';
import { EMPTY, Subject } from 'rxjs';
import { catchError, takeUntil } from 'rxjs/operators';
@ -131,7 +132,7 @@ export class PublicPageComponent implements OnInit {
for (const [symbol, position] of Object.entries(
this.portfolioPublicDetails.holdings
)) {
const value = position.allocationCurrent;
const value = position.allocationInPercentage;
this.positions[symbol] = {
value,
@ -198,7 +199,9 @@ export class PublicPageComponent implements OnInit {
this.symbols[prettifySymbol(symbol)] = {
name: position.name,
symbol: prettifySymbol(symbol),
value: position.value
value: isNumber(position.value)
? position.value
: position.valueInPercentage
};
}

View File

@ -77,6 +77,7 @@
</mat-card-header>
<mat-card-content>
<gf-world-map-chart
format="{0}%"
[countries]="countries"
[isInPercent]="true"
></gf-world-map-chart>

View File

@ -41,7 +41,7 @@ import { AccountWithValue, DateRange, GroupBy } from '@ghostfolio/common/types';
import { translate } from '@ghostfolio/ui/i18n';
import { DataSource, Order as OrderModel } from '@prisma/client';
import { format, parseISO } from 'date-fns';
import { cloneDeep, groupBy } from 'lodash';
import { cloneDeep, groupBy, isNumber } from 'lodash';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@ -299,6 +299,12 @@ export class DataService {
].dateOfFirstActivity
? parseISO(response.holdings[symbol].dateOfFirstActivity)
: undefined;
response.holdings[symbol].value = isNumber(
response.holdings[symbol].value
)
? response.holdings[symbol].value
: response.holdings[symbol].valueInPercentage;
}
}
@ -333,9 +339,23 @@ export class DataService {
}
public fetchPortfolioPublic(aId: string) {
return this.http.get<PortfolioPublicDetails>(
`/api/v1/portfolio/public/${aId}`
);
return this.http
.get<PortfolioPublicDetails>(`/api/v1/portfolio/public/${aId}`)
.pipe(
map((response) => {
if (response.holdings) {
for (const symbol of Object.keys(response.holdings)) {
response.holdings[symbol].value = isNumber(
response.holdings[symbol].value
)
? response.holdings[symbol].value
: response.holdings[symbol].valueInPercentage;
}
}
return response;
})
);
}
public fetchPortfolioReport() {

View File

@ -1,10 +1,15 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { ObservableStore } from '@codewithdan/observable-store';
import { SubscriptionInterstitialDialogParams } from '@ghostfolio/client/components/subscription-interstitial-dialog/interfaces/interfaces';
import { SubscriptionInterstitialDialog } from '@ghostfolio/client/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component';
import { User } from '@ghostfolio/common/interfaces';
import { of } from 'rxjs';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { DeviceDetectorService } from 'ngx-device-detector';
import { of, Subject } from 'rxjs';
import { throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { catchError, map, takeUntil } from 'rxjs/operators';
import { UserStoreActions } from './user-store.actions';
import { UserStoreState } from './user-store.state';
@ -13,10 +18,19 @@ import { UserStoreState } from './user-store.state';
providedIn: 'root'
})
export class UserService extends ObservableStore<UserStoreState> {
public constructor(private http: HttpClient) {
private deviceType: string;
private unsubscribeSubject = new Subject<void>();
public constructor(
private deviceService: DeviceDetectorService,
private dialog: MatDialog,
private http: HttpClient
) {
super({ trackStateHistory: true });
this.setState({ user: undefined }, UserStoreActions.Initialize);
this.deviceType = this.deviceService.getDeviceInfo().deviceType;
}
public get(force = false) {
@ -39,6 +53,26 @@ export class UserService extends ObservableStore<UserStoreState> {
return this.http.get<User>('/api/v1/user').pipe(
map((user) => {
this.setState({ user }, UserStoreActions.GetUser);
if (
hasPermission(
user.permissions,
permissions.enableSubscriptionInterstitial
)
) {
const dialogRef = this.dialog.open(SubscriptionInterstitialDialog, {
autoFocus: false,
data: <SubscriptionInterstitialDialogParams>{},
height: this.deviceType === 'mobile' ? '97.5vh' : '80vh',
width: this.deviceType === 'mobile' ? '100vw' : '50rem'
});
dialogRef
.afterClosed()
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {});
}
return user;
}),
catchError(this.handleError)

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 653 102.6" style="enable-background:new 0 0 653 102.6;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FF6600;}
.st1{fill:#FFFFFF;}
.st2{fill:#FFFFFF;}
</style>
<path class="st0" d="M66.9,54.5c0-19.1-6.8-27.8-10.4-31.1c-0.7-0.6-1.8-0.1-1.7,0.9c0.7,10.8-12.9,13.5-12.9,30.4h0
c0,0,0,0.1,0,0.1c0,10.3,7.8,18.7,17.4,18.7c9.6,0,17.4-8.4,17.4-18.7c0,0,0-0.1,0-0.1h0c0-4.8-1.8-9.4-3.6-12.8
c-0.4-0.7-1.4-0.4-1.3,0.2C75.1,56.7,66.9,65.7,66.9,54.5z"/>
<g>
<path class="st0" d="M46.2,94.8c-0.4,0-0.9-0.2-1.2-0.5L0.5,49.8c-0.6-0.6-0.6-1.7,0-2.4l47-47C47.8,0.2,48.2,0,48.6,0h13.5
c0.8,0,1.3,0.5,1.5,1c0.2,0.5,0.2,1.2-0.4,1.8L19.1,47c-0.9,0.9-0.9,2.3,0,3.2L54,85.2c0.6,0.6,0.6,1.7,0,2.4l-6.7,6.8
C47,94.6,46.6,94.8,46.2,94.8z"/>
</g>
<g>
<path class="st0" d="M55.1,102.6c-0.8,0-1.3-0.5-1.5-1c-0.2-0.5-0.2-1.2,0.4-1.8l44.2-44.2c0.4-0.4,0.7-1,0.7-1.6
c0-0.6-0.2-1.2-0.7-1.6L63.2,17.4c-0.6-0.6-0.6-1.7,0-2.4l6.8-6.8c0.3-0.3,0.7-0.5,1.2-0.5S72,8,72.3,8.3l44.4,44.5
c0.3,0.3,0.5,0.7,0.5,1.2s-0.2,0.9-0.5,1.2l-47,47c-0.3,0.3-0.7,0.5-1.2,0.5H55.1z"/>
</g>
<g>
<g>
<path class="st1" d="M167.2,32c-0.2,0.4-0.5,0.6-1,0.6c-0.3,0-0.7-0.2-1.2-0.7c-0.5-0.5-1.2-1-2-1.5c-0.9-0.6-1.9-1.1-3.2-1.5
c-1.3-0.5-2.9-0.7-4.8-0.7c-1.9,0-3.5,0.3-5,0.8c-1.4,0.5-2.6,1.3-3.6,2.2s-1.7,2-2.2,3.2c-0.5,1.2-0.8,2.5-0.8,3.8
c0,1.8,0.4,3.2,1.1,4.4c0.7,1.1,1.7,2.1,3,2.9c1.2,0.8,2.6,1.5,4.2,2c1.6,0.6,3.2,1.1,4.8,1.6c1.6,0.5,3.2,1.1,4.8,1.8
c1.6,0.6,2.9,1.5,4.2,2.4s2.2,2.2,3,3.6c0.7,1.4,1.1,3.2,1.1,5.3c0,2.2-0.4,4.2-1.1,6.1c-0.7,1.9-1.8,3.6-3.2,5
c-1.4,1.4-3.2,2.5-5.2,3.4c-2.1,0.8-4.4,1.2-7,1.2c-3.4,0-6.4-0.6-8.8-1.8c-2.5-1.2-4.6-2.9-6.5-5l1-1.6c0.3-0.4,0.6-0.5,1-0.5
c0.2,0,0.5,0.1,0.8,0.4c0.3,0.3,0.8,0.7,1.2,1.1c0.5,0.4,1.1,0.9,1.8,1.4c0.7,0.5,1.5,1,2.4,1.4c0.9,0.4,1.9,0.8,3.1,1.1
c1.2,0.3,2.5,0.4,4,0.4c2.1,0,3.9-0.3,5.5-0.9c1.6-0.6,3-1.5,4.1-2.5s2-2.4,2.6-3.8c0.6-1.5,0.9-3.1,0.9-4.7
c0-1.8-0.4-3.3-1.1-4.5c-0.7-1.2-1.7-2.2-3-3c-1.2-0.8-2.6-1.5-4.2-2c-1.6-0.5-3.2-1.1-4.8-1.6c-1.6-0.5-3.2-1.1-4.8-1.7
c-1.6-0.6-2.9-1.4-4.2-2.4c-1.2-1-2.2-2.2-3-3.7c-0.7-1.5-1.1-3.3-1.1-5.6c0-1.7,0.3-3.4,1-5c0.7-1.6,1.6-3,2.9-4.3
c1.3-1.2,2.8-2.2,4.7-3c1.9-0.7,4-1.1,6.4-1.1c2.7,0,5.1,0.4,7.3,1.3c2.1,0.9,4.1,2.2,5.9,3.9L167.2,32z"/>
<path class="st2" d="M152.9,78.8c-3.5,0-6.6-0.6-9.1-1.9c-2.5-1.2-4.8-3-6.7-5.1l-0.3-0.3l1.3-2c0.6-0.7,1.1-0.8,1.5-0.8
c0.4,0,0.8,0.2,1.2,0.6c0.3,0.3,0.8,0.7,1.3,1.1c0.5,0.4,1.1,0.9,1.7,1.4c0.7,0.5,1.4,0.9,2.3,1.3c0.9,0.4,1.9,0.8,3,1
c1.1,0.3,2.4,0.4,3.9,0.4c2,0,3.8-0.3,5.3-0.9c1.5-0.6,2.8-1.4,3.9-2.4c1-1,1.9-2.2,2.4-3.6c0.6-1.4,0.8-2.9,0.8-4.5
c0-1.7-0.3-3.1-1-4.2c-0.7-1.1-1.6-2-2.8-2.8c-1.2-0.8-2.5-1.4-4-1.9c-1.5-0.5-3.1-1.1-4.8-1.6c-1.7-0.5-3.3-1.1-4.8-1.7
c-1.6-0.7-3.1-1.5-4.3-2.5c-1.3-1-2.3-2.4-3.1-3.9c-0.8-1.6-1.2-3.5-1.2-5.8c0-1.8,0.3-3.6,1-5.3c0.7-1.7,1.7-3.2,3-4.5
c1.3-1.3,3-2.3,4.9-3.1c1.9-0.8,4.2-1.2,6.6-1.2c2.8,0,5.3,0.4,7.5,1.3c2.2,0.9,4.2,2.3,6.1,4.1l0.3,0.3l-1.1,2.1
c-0.6,1.1-1.7,1.4-3.1,0.1c-0.5-0.4-1.1-0.9-2-1.4c-0.8-0.5-1.9-1-3.1-1.5c-1.2-0.4-2.7-0.7-4.6-0.7c-1.8,0-3.4,0.3-4.8,0.8
c-1.3,0.5-2.5,1.2-3.4,2.1c-0.9,0.9-1.6,1.9-2.1,3c-0.5,1.1-0.7,2.4-0.7,3.6c0,1.6,0.3,3,1,4c0.7,1.1,1.6,2,2.8,2.8
c1.2,0.8,2.5,1.4,4,2c1.5,0.5,3.1,1.1,4.8,1.6c1.6,0.5,3.3,1.1,4.8,1.8c1.6,0.7,3.1,1.5,4.3,2.5c1.3,1,2.3,2.3,3.1,3.8
c0.8,1.5,1.2,3.4,1.2,5.6c0,2.2-0.4,4.4-1.2,6.4c-0.8,2-1.9,3.7-3.4,5.2c-1.5,1.5-3.3,2.6-5.4,3.5
C158.1,78.3,155.6,78.8,152.9,78.8z M138.4,71.3c1.7,1.9,3.7,3.4,6,4.5c2.4,1.2,5.3,1.8,8.6,1.8c2.5,0,4.8-0.4,6.8-1.2
c2-0.8,3.6-1.9,5-3.2c1.3-1.3,2.4-3,3.1-4.8c0.7-1.8,1.1-3.8,1.1-5.9c0-2-0.4-3.7-1-5.1c-0.7-1.3-1.6-2.5-2.8-3.4
c-1.2-0.9-2.5-1.7-4-2.4c-1.5-0.6-3.1-1.2-4.7-1.8c-1.6-0.5-3.2-1.1-4.8-1.6c-1.6-0.6-3-1.3-4.3-2.1c-1.3-0.8-2.3-1.9-3.1-3.1
c-0.8-1.2-1.2-2.8-1.2-4.7c0-1.4,0.3-2.8,0.8-4.1c0.5-1.3,1.3-2.5,2.3-3.4c1-1,2.3-1.8,3.8-2.3c1.5-0.6,3.3-0.8,5.2-0.8
c1.9,0,3.6,0.2,5,0.7c1.3,0.5,2.5,1,3.3,1.6c0.9,0.6,1.6,1.1,2.1,1.6c0.6,0.5,0.8,0.5,0.8,0.5c0.1,0,0.3,0,0.4-0.3l0.7-1.3
c-1.6-1.5-3.4-2.7-5.3-3.5c-2.1-0.8-4.4-1.2-7-1.2c-2.3,0-4.4,0.4-6.2,1.1c-1.8,0.7-3.3,1.7-4.5,2.8c-1.2,1.2-2.1,2.5-2.8,4.1
c-0.6,1.5-0.9,3.1-0.9,4.8c0,2.1,0.4,3.9,1.1,5.3c0.7,1.4,1.6,2.6,2.8,3.5c1.2,0.9,2.5,1.7,4,2.3c1.5,0.6,3.1,1.2,4.7,1.7
c1.6,0.5,3.2,1,4.8,1.6c1.6,0.6,3,1.2,4.3,2.1c1.3,0.8,2.4,1.9,3.1,3.2c0.8,1.3,1.2,2.9,1.2,4.9c0,1.8-0.3,3.4-0.9,5
c-0.6,1.6-1.5,2.9-2.7,4c-1.2,1.1-2.6,2-4.3,2.7c-1.7,0.6-3.6,1-5.7,1c-1.5,0-2.9-0.2-4.2-0.5c-1.2-0.3-2.3-0.7-3.2-1.1
c-0.9-0.4-1.8-0.9-2.5-1.5c-0.7-0.5-1.3-1-1.8-1.4c-0.5-0.4-0.9-0.8-1.2-1.1c-0.3-0.3-0.5-0.3-0.5-0.3c-0.1,0-0.3,0-0.5,0.3
L138.4,71.3z"/>
</g>
<g>
<path class="st1" d="M226.7,51.6c0,4-0.6,7.6-1.8,10.9c-1.2,3.3-2.9,6.1-5.1,8.4c-2.2,2.3-4.8,4.1-7.8,5.4
c-3,1.3-6.4,1.9-10.1,1.9c-3.6,0-7-0.6-10-1.9c-3-1.3-5.6-3-7.8-5.4c-2.2-2.3-3.9-5.1-5.1-8.4c-1.2-3.3-1.8-6.9-1.8-10.9
c0-4,0.6-7.6,1.8-10.9c1.2-3.3,2.9-6.1,5.1-8.4c2.2-2.3,4.8-4.1,7.8-5.4c3-1.3,6.4-1.9,10-1.9c3.7,0,7.1,0.6,10.1,1.9
c3,1.3,5.6,3,7.8,5.4c2.2,2.3,3.9,5.1,5.1,8.4C226.1,44,226.7,47.6,226.7,51.6z M222.8,51.6c0-3.6-0.5-6.9-1.5-9.8
c-1-2.9-2.4-5.3-4.2-7.3c-1.8-2-4-3.5-6.6-4.6c-2.6-1.1-5.4-1.6-8.5-1.6c-3.1,0-5.9,0.5-8.5,1.6c-2.6,1.1-4.8,2.6-6.6,4.6
c-1.8,2-3.3,4.4-4.3,7.3c-1,2.9-1.5,6.1-1.5,9.8c0,3.6,0.5,6.9,1.5,9.8c1,2.9,2.4,5.3,4.3,7.3c1.8,2,4,3.5,6.6,4.6
c2.6,1.1,5.4,1.6,8.5,1.6c3.1,0,6-0.5,8.5-1.6c2.6-1,4.8-2.6,6.6-4.6c1.8-2,3.2-4.4,4.2-7.3C222.3,58.5,222.8,55.3,222.8,51.6z"/>
<path class="st2" d="M202,78.7c-3.7,0-7.2-0.7-10.2-1.9c-3.1-1.3-5.8-3.1-8-5.5c-2.2-2.4-4-5.2-5.2-8.6c-1.2-3.3-1.9-7.1-1.9-11.1
c0-4,0.6-7.8,1.9-11.1c1.2-3.3,3-6.2,5.2-8.6c2.2-2.4,4.9-4.2,8-5.5c3.1-1.3,6.5-2,10.2-2c3.8,0,7.2,0.7,10.3,1.9
c3.1,1.3,5.8,3.1,8,5.5c2.2,2.4,4,5.3,5.2,8.6c1.2,3.3,1.8,7,1.8,11.1c0,4.1-0.6,7.8-1.8,11.1c-1.2,3.3-3,6.2-5.2,8.6
c-2.2,2.4-4.9,4.2-8,5.5C209.2,78.1,205.7,78.7,202,78.7z M202,25.7c-3.5,0-6.8,0.6-9.8,1.9c-2.9,1.2-5.5,3-7.6,5.2
c-2.1,2.2-3.8,5-4.9,8.2c-1.2,3.2-1.8,6.8-1.8,10.7c0,3.9,0.6,7.5,1.8,10.7c1.2,3.2,2.8,5.9,4.9,8.2c2.1,2.2,4.7,4,7.6,5.2
c2.9,1.2,6.2,1.8,9.8,1.8c3.6,0,6.9-0.6,9.8-1.8c2.9-1.2,5.5-3,7.6-5.2c2.1-2.2,3.8-5,4.9-8.1c1.2-3.2,1.8-6.8,1.8-10.7
c0-3.9-0.6-7.5-1.8-10.7c-1.2-3.2-2.8-5.9-4.9-8.2c-2.1-2.2-4.7-4-7.6-5.2C208.9,26.3,205.6,25.7,202,25.7z"/>
</g>
<g>
<path class="st1" d="M256.4,74.9c2.5,0,4.7-0.4,6.7-1.3c2-0.9,3.6-2.1,5-3.6c1.4-1.5,2.4-3.4,3.1-5.4c0.7-2.1,1.1-4.3,1.1-6.8
V25.7h3.7v32.1c0,2.9-0.5,5.5-1.4,8c-0.9,2.5-2.2,4.6-3.9,6.5c-1.7,1.8-3.8,3.3-6.2,4.3c-2.4,1-5.2,1.6-8.2,1.6
c-3,0-5.8-0.5-8.2-1.6c-2.4-1.1-4.5-2.5-6.2-4.3c-1.7-1.8-3-4-3.9-6.5c-0.9-2.5-1.4-5.2-1.4-8V25.7h3.8v32c0,2.4,0.4,4.7,1.1,6.8
c0.7,2.1,1.8,3.9,3.1,5.4c1.4,1.5,3,2.7,5,3.6C251.6,74.5,253.9,74.9,256.4,74.9z"/>
<path class="st2" d="M256.4,78.8c-3.1,0-5.9-0.5-8.4-1.6c-2.5-1.1-4.7-2.6-6.4-4.5c-1.7-1.9-3.1-4.2-4-6.7
c-0.9-2.5-1.4-5.3-1.4-8.2V25.1h5v32.7c0,2.3,0.4,4.5,1,6.6c0.7,2,1.7,3.8,3,5.2c1.3,1.5,2.9,2.6,4.8,3.5c1.9,0.8,4,1.3,6.4,1.3
c2.4,0,4.6-0.4,6.4-1.2c1.9-0.8,3.5-2,4.8-3.5c1.3-1.5,2.3-3.2,3-5.2c0.7-2,1-4.2,1-6.6V25.1h5v32.7c0,2.9-0.5,5.7-1.4,8.2
c-0.9,2.5-2.3,4.8-4,6.7c-1.7,1.9-3.9,3.4-6.4,4.5C262.3,78.3,259.5,78.8,256.4,78.8z M237.3,26.3v31.5c0,2.8,0.4,5.4,1.3,7.8
c0.9,2.4,2.1,4.5,3.8,6.3c1.6,1.8,3.6,3.2,6,4.2c2.3,1,5,1.5,8,1.5c2.9,0,5.6-0.5,8-1.5c2.3-1,4.4-2.4,6-4.2
c1.6-1.8,2.9-3.9,3.8-6.3c0.9-2.4,1.3-5,1.3-7.8V26.3h-2.5v31.5c0,2.5-0.4,4.8-1.1,7c-0.7,2.2-1.8,4.1-3.3,5.7
c-1.4,1.6-3.2,2.9-5.2,3.8c-2,0.9-4.4,1.4-6.9,1.4c-2.6,0-4.9-0.5-6.9-1.4c-2-0.9-3.8-2.2-5.2-3.8c-1.4-1.6-2.5-3.5-3.2-5.7
c-0.7-2.1-1.1-4.5-1.1-7V26.3H237.3z"/>
</g>
<g>
<path class="st1" d="M297.5,51.3c1,0,0.9,0,0.9,0l2.2,0c2.3,0,4.4-0.3,6.2-0.8c1.8-0.6,3.4-1.3,4.6-2.4c1.3-1,2.2-2.3,2.9-3.7
c0.7-1.4,1-3.1,1-4.9c0-3.7-1.2-6.4-3.6-8.2c-2.4-1.8-5.9-2.7-10.6-2.7h-9.5v22.7v2.8v23.5h-3.7V25.7h13.2c6,0,10.5,1.2,13.4,3.5
c3,2.3,4.4,5.7,4.4,10.2c0,2-0.3,3.8-1,5.4c-0.7,1.6-1.7,3.1-3,4.3c-1.3,1.2-2.8,2.3-4.6,3c-1.8,0.8-3.9,1.3-6.1,1.6
c0.6,0.4,1.1,0.9,1.6,1.5l17.9,22.4h-3.3c-0.4,0-0.7-0.1-1-0.2c-0.3-0.1-0.6-0.4-0.8-0.7l-16.6-21c-0.4-0.5-0.9-0.9-1.3-1.1
c-0.5-0.2-3.4-0.3-4.4-0.3C296.3,51.6,296.7,51.3,297.5,51.3z"/>
<path class="st2" d="M325,78.2h-4.5c-0.5,0-0.9-0.1-1.3-0.3c-0.4-0.2-0.7-0.5-1-0.9l-16.6-21c-0.4-0.5-0.7-0.8-1.1-1
c-0.4-0.1-2.8-0.3-4.1-0.3h-0.6v-2.6c0-0.9,0.2-1.4,1.8-1.4c0.9,0,1,0,1,0l2.2,0c2.2,0,4.2-0.3,6-0.8c1.7-0.5,3.2-1.3,4.4-2.3
c1.2-1,2.1-2.1,2.7-3.5c0.6-1.4,0.9-2.9,0.9-4.6c0-3.5-1.1-6-3.4-7.7c-2.3-1.7-5.7-2.6-10.2-2.6h-8.9v48.9h-5V25.1h13.9
c6.1,0,10.7,1.2,13.8,3.6c3.1,2.4,4.7,6,4.7,10.7c0,2.1-0.4,4-1.1,5.7c-0.7,1.7-1.8,3.2-3.1,4.5c-1.3,1.3-3,2.3-4.8,3.2
c-1.5,0.6-3.1,1.1-4.9,1.4c0.2,0.2,0.4,0.4,0.6,0.7L325,78.2z M296.9,53.5c1.1,0,3.4,0.1,4,0.4c0.6,0.3,1.1,0.7,1.6,1.3l16.6,21
c0.2,0.3,0.4,0.5,0.6,0.6c0.2,0.1,0.4,0.2,0.7,0.2h2l-17.1-21.4c-0.4-0.6-0.9-1-1.4-1.3l-1.5-0.9l1.8-0.2c2.2-0.2,4.2-0.7,5.9-1.5
c1.7-0.8,3.2-1.7,4.5-2.9c1.2-1.2,2.2-2.5,2.8-4.1c0.6-1.6,1-3.3,1-5.2c0-4.3-1.4-7.5-4.2-9.7c-2.8-2.2-7.2-3.3-13-3.3h-12.6V77
h2.5V28h10.1c4.7,0,8.4,0.9,10.9,2.8c2.6,1.9,3.9,4.8,3.9,8.7c0,1.9-0.4,3.6-1,5.1c-0.7,1.5-1.7,2.8-3.1,3.9
c-1.3,1.1-2.9,1.9-4.8,2.5c-1.9,0.6-4,0.9-6.4,0.9l-2.2,0c-0.1,0-0.2,0-0.9,0C297.3,51.9,297,51.9,296.9,53.5z"/>
</g>
<g>
<path class="st1" d="M367.6,68.8c0.2,0,0.5,0.1,0.6,0.3l1.5,1.6c-1.1,1.1-2.2,2.2-3.5,3.1c-1.3,0.9-2.7,1.7-4.2,2.3
c-1.5,0.6-3.2,1.1-4.9,1.5c-1.8,0.4-3.8,0.5-5.9,0.5c-3.6,0-6.9-0.6-9.9-1.9c-3-1.3-5.6-3-7.7-5.4c-2.1-2.3-3.8-5.1-5-8.4
c-1.2-3.3-1.8-6.9-1.8-10.9c0-3.9,0.6-7.5,1.9-10.8c1.2-3.3,3-6,5.2-8.4c2.2-2.3,4.9-4.1,8-5.4c3.1-1.3,6.6-1.9,10.3-1.9
c1.9,0,3.6,0.1,5.2,0.4c1.6,0.3,3,0.7,4.4,1.2c1.4,0.5,2.6,1.2,3.8,2c1.2,0.8,2.4,1.7,3.5,2.7l-1.1,1.6c-0.2,0.3-0.5,0.4-0.9,0.4
c-0.2,0-0.5-0.1-0.8-0.4c-0.3-0.3-0.8-0.6-1.3-1c-0.5-0.4-1.2-0.8-1.9-1.2c-0.7-0.5-1.6-0.9-2.7-1.2c-1-0.4-2.2-0.7-3.6-1
c-1.3-0.3-2.9-0.4-4.6-0.4c-3.2,0-6.1,0.5-8.7,1.6c-2.6,1.1-4.9,2.6-6.8,4.7c-1.9,2-3.4,4.5-4.5,7.3s-1.6,6.1-1.6,9.7
c0,3.7,0.5,6.9,1.6,9.8c1.1,2.9,2.5,5.3,4.4,7.3c1.9,2,4.1,3.5,6.6,4.6c2.5,1.1,5.3,1.6,8.2,1.6c1.9,0,3.5-0.1,5-0.4
c1.5-0.2,2.8-0.6,4-1.1c1.2-0.5,2.4-1.1,3.4-1.8c1.1-0.7,2.1-1.5,3.1-2.5c0.1-0.1,0.2-0.2,0.3-0.2
C367.3,68.9,367.5,68.8,367.6,68.8z"/>
<path class="st2" d="M351.1,78.8c-3.7,0-7.1-0.7-10.1-1.9c-3.1-1.3-5.7-3.1-7.9-5.5c-2.2-2.4-3.9-5.2-5.1-8.6
c-1.2-3.3-1.8-7.1-1.8-11.1c0-4,0.6-7.7,1.9-11c1.3-3.3,3.1-6.2,5.3-8.6c2.3-2.4,5.1-4.3,8.2-5.6c3.2-1.3,6.7-2,10.6-2
c1.9,0,3.7,0.1,5.3,0.4c1.6,0.3,3.1,0.7,4.5,1.2c1.4,0.5,2.7,1.2,3.9,2c1.2,0.8,2.4,1.7,3.6,2.8l0.4,0.4l-1.4,2.1
c-0.2,0.3-0.6,0.7-1.4,0.7c-0.4,0-0.7-0.2-1.2-0.5c-0.3-0.3-0.8-0.6-1.3-0.9c-0.5-0.4-1.1-0.8-1.9-1.2c-0.7-0.4-1.6-0.8-2.6-1.2
c-1-0.4-2.2-0.7-3.5-0.9c-1.3-0.2-2.8-0.4-4.5-0.4c-3.1,0-5.9,0.5-8.5,1.6c-2.5,1.1-4.8,2.6-6.6,4.5c-1.8,1.9-3.3,4.3-4.3,7.1
c-1,2.8-1.6,6-1.6,9.4c0,3.6,0.5,6.8,1.5,9.6c1,2.8,2.4,5.2,4.2,7.1c1.8,1.9,3.9,3.4,6.4,4.4c2.4,1,5.1,1.5,8,1.5
c1.8,0,3.5-0.1,4.9-0.4c1.4-0.2,2.7-0.6,3.9-1.1c1.2-0.5,2.3-1.1,3.3-1.7c1-0.7,2-1.5,3-2.4c0.2-0.2,0.3-0.2,0.5-0.3
c0.5-0.3,1.3-0.2,1.7,0.3l1.9,2l-0.4,0.4c-1.1,1.2-2.3,2.2-3.6,3.2c-1.3,0.9-2.7,1.8-4.3,2.4c-1.5,0.7-3.2,1.2-5.1,1.5
C355.3,78.6,353.3,78.8,351.1,78.8z M352.2,25.7c-3.7,0-7.1,0.6-10.1,1.9c-3,1.2-5.7,3-7.8,5.3c-2.2,2.3-3.9,5-5.1,8.2
c-1.2,3.2-1.8,6.7-1.8,10.6c0,3.9,0.6,7.5,1.8,10.7c1.2,3.2,2.8,5.9,4.9,8.2c2.1,2.2,4.6,4,7.5,5.2c2.9,1.2,6.1,1.8,9.6,1.8
c2.1,0,4-0.2,5.8-0.5c1.7-0.3,3.4-0.8,4.8-1.5c1.5-0.6,2.8-1.4,4-2.3c1.1-0.8,2.1-1.7,3-2.6l-1.1-1.2c-0.1-0.1-0.2-0.1-0.3,0
c-0.1,0-0.2,0.1-0.3,0.2c-1,0.9-2.1,1.8-3.2,2.5c-1.1,0.7-2.3,1.4-3.5,1.9c-1.3,0.5-2.7,0.9-4.1,1.1c-1.5,0.2-3.2,0.4-5.1,0.4
c-3,0-5.9-0.6-8.5-1.6c-2.6-1.1-4.9-2.7-6.8-4.7c-1.9-2-3.4-4.6-4.5-7.5c-1.1-2.9-1.6-6.3-1.6-10c0-3.6,0.5-6.9,1.6-9.9
c1.1-2.9,2.6-5.5,4.6-7.5c2-2.1,4.3-3.7,7-4.8c2.7-1.1,5.7-1.7,8.9-1.7c1.7,0,3.3,0.1,4.7,0.4c1.4,0.3,2.6,0.6,3.7,1
c1.1,0.4,2,0.8,2.8,1.3c0.8,0.5,1.4,0.9,1.9,1.3c0.5,0.4,1,0.7,1.3,1c0.3,0.3,0.5,0.3,0.5,0.3c0.3,0,0.4-0.1,0.4-0.2l0.8-1.2
c-1-0.9-2-1.6-3-2.3c-1.2-0.8-2.4-1.4-3.7-1.9c-1.3-0.5-2.8-0.9-4.3-1.2C355.7,25.9,354,25.7,352.2,25.7z"/>
</g>
<g>
<path class="st1" d="M410.3,25.7v3.1H383v21h22.7v3H383v21.6h27.3v3.1h-31.1V25.7H410.3z"/>
<path class="st2" d="M410.9,78.2h-32.3V25.1h32.3v4.3h-27.3v19.7h22.7v4.3h-22.7v20.4h27.3V78.2z M379.8,77h29.9v-1.9h-27.3V52.2
h22.7v-1.8h-22.7V28.2h27.3v-1.9h-29.9V77z"/>
</g>
<g>
<path class="st1" d="M456.8,25.1V33h-23.5v15.7h19.8v7.9h-19.8v21.6h-9.9v-53H456.8z"/>
</g>
<g>
<path class="st1" d="M514.3,51.6c0,3.9-0.6,7.5-1.9,10.8c-1.3,3.3-3.1,6.2-5.5,8.6c-2.3,2.4-5.2,4.3-8.5,5.7c-3.3,1.4-7,2-11,2
c-4,0-7.7-0.7-11-2c-3.3-1.4-6.1-3.2-8.5-5.7c-2.4-2.4-4.2-5.3-5.5-8.6s-1.9-6.9-1.9-10.8s0.6-7.5,1.9-10.8
c1.3-3.3,3.1-6.2,5.5-8.6c2.4-2.4,5.2-4.3,8.5-5.7c3.3-1.4,7-2,11-2c4,0,7.7,0.7,11,2.1c3.3,1.4,6.1,3.3,8.5,5.7
c2.3,2.4,4.2,5.3,5.5,8.6C513.6,44.1,514.3,47.7,514.3,51.6z M504.2,51.6c0-2.9-0.4-5.5-1.2-7.8c-0.8-2.3-1.9-4.3-3.3-5.9
c-1.4-1.6-3.2-2.8-5.3-3.7c-2.1-0.9-4.4-1.3-7-1.3c-2.6,0-4.9,0.4-7,1.3c-2.1,0.9-3.8,2.1-5.3,3.7c-1.5,1.6-2.6,3.6-3.4,5.9
c-0.8,2.3-1.2,4.9-1.2,7.8s0.4,5.5,1.2,7.8c0.8,2.3,1.9,4.3,3.4,5.9c1.5,1.6,3.2,2.8,5.3,3.7c2.1,0.9,4.4,1.3,7,1.3
c2.6,0,4.9-0.4,7-1.3c2.1-0.9,3.8-2.1,5.3-3.7c1.4-1.6,2.5-3.6,3.3-5.9C503.8,57.1,504.2,54.5,504.2,51.6z"/>
</g>
<g>
<path class="st1" d="M534.9,50.4l2.3,0c1.9,0,3.5-0.2,4.9-0.7c1.4-0.5,2.5-1.1,3.4-1.9c0.9-0.8,1.6-1.8,2-2.9
c0.4-1.1,0.7-2.4,0.7-3.7c0-2.7-0.9-4.8-2.7-6.2c-1.8-1.4-4.5-2.2-8.1-2.2H531v17.6v7.1v20.7h-9.9v-53h16.2c3.6,0,6.7,0.4,9.3,1.1
c2.6,0.7,4.7,1.8,6.3,3.1c1.6,1.3,2.9,3,3.6,4.8c0.8,1.9,1.2,3.9,1.2,6.2c0,1.8-0.3,3.5-0.8,5.1c-0.5,1.6-1.3,3-2.3,4.3
c-1,1.3-2.2,2.4-3.7,3.4c-1.5,1-3.1,1.8-5,2.3c1.2,0.7,2.3,1.7,3.2,3l13.3,19.6h-8.9c-0.9,0-1.6-0.2-2.2-0.5
c-0.6-0.3-1.1-0.8-1.5-1.5c0,0-11.1-17-11.1-17c-0.3-0.4-0.9-1.3-1.5-1.4c-1.2,0-2.4,0-3.5,0c0,0,0-6,0-6.4
C533.8,50.4,534.9,50.4,534.9,50.4z"/>
</g>
<g>
<path class="st1" d="M591.4,70.9c2.2,0,4.2-0.2,5.8-0.6c1.6-0.4,3.2-1,4.7-1.7v-12h-6.6c-0.6,0-1.1-0.2-1.5-0.5
c-0.4-0.4-0.6-0.8-0.6-1.3v-5.6h17.6V73c-1.3,1-2.7,1.8-4.2,2.5c-1.5,0.7-3,1.3-4.7,1.8c-1.7,0.5-3.4,0.8-5.3,1
c-1.9,0.2-3.9,0.3-6.1,0.3c-3.9,0-7.4-0.7-10.7-2c-3.3-1.3-6.1-3.2-8.4-5.6c-2.4-2.4-4.2-5.3-5.6-8.6c-1.3-3.3-2-7-2-10.9
c0-4,0.6-7.6,1.9-11c1.3-3.3,3.1-6.2,5.5-8.6c2.4-2.4,5.3-4.3,8.7-5.6c3.4-1.3,7.2-2,11.4-2c4.3,0,8.1,0.6,11.2,1.9
c3.2,1.3,5.8,3,8,5l-2.9,4.5c-0.6,0.9-1.3,1.4-2.2,1.4c-0.6,0-1.2-0.2-1.8-0.6c-0.8-0.5-1.6-0.9-2.4-1.4c-0.8-0.5-1.7-0.9-2.7-1.2
c-1-0.3-2.1-0.6-3.3-0.8c-1.2-0.2-2.7-0.3-4.3-0.3c-2.6,0-5,0.4-7.1,1.3c-2.1,0.9-3.9,2.1-5.4,3.8c-1.5,1.6-2.6,3.6-3.4,5.9
c-0.8,2.3-1.2,4.9-1.2,7.7c0,3.1,0.4,5.8,1.3,8.2c0.9,2.4,2.1,4.4,3.6,6s3.4,2.9,5.5,3.8S588.9,70.9,591.4,70.9z"/>
</g>
<g>
<path class="st1" d="M645.7,56.8h-16.1v13.4H653v7.9h-33.4v-53H653V33h-23.5v16.3H648v5.8C648,55.1,647.9,56.8,645.7,56.8z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -6,82 +6,86 @@
http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
<url>
<loc>https://ghostfol.io</loc>
<lastmod>2023-01-05T00:00:00+00:00</lastmod>
<lastmod>2023-01-23T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/de/blog/2021/07/hallo-ghostfolio</loc>
<lastmod>2023-01-05T00:00:00+00:00</lastmod>
<lastmod>2023-01-23T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/de/blog/2023/01/ghostfolio-auf-sackgeld-vorgestellt</loc>
<lastmod>2023-01-23T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/about</loc>
<lastmod>2023-01-05T00:00:00+00:00</lastmod>
<lastmod>2023-01-23T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/about/changelog</loc>
<lastmod>2023-01-05T00:00:00+00:00</lastmod>
<lastmod>2023-01-23T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog</loc>
<lastmod>2023-01-05T00:00:00+00:00</lastmod>
<lastmod>2023-01-23T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2021/07/hello-ghostfolio</loc>
<lastmod>2023-01-05T00:00:00+00:00</lastmod>
<lastmod>2023-01-23T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/01/ghostfolio-first-months-in-open-source</loc>
<lastmod>2023-01-05T00:00:00+00:00</lastmod>
<lastmod>2023-01-23T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/07/ghostfolio-meets-internet-identity</loc>
<lastmod>2023-01-05T00:00:00+00:00</lastmod>
<lastmod>2023-01-23T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/07/how-do-i-get-my-finances-in-order</loc>
<lastmod>2023-01-05T00:00:00+00:00</lastmod>
<lastmod>2023-01-23T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/08/500-stars-on-github</loc>
<lastmod>2023-01-05T00:00:00+00:00</lastmod>
<lastmod>2023-01-23T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/10/hacktoberfest-2022</loc>
<lastmod>2023-01-05T00:00:00+00:00</lastmod>
<lastmod>2023-01-23T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/11/black-friday-2022</loc>
<lastmod>2023-01-05T00:00:00+00:00</lastmod>
<lastmod>2023-01-23T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/12/the-importance-of-tracking-your-personal-finances</loc>
<lastmod>2023-01-05T00:00:00+00:00</lastmod>
<lastmod>2023-01-23T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/demo</loc>
<lastmod>2023-01-05T00:00:00+00:00</lastmod>
<lastmod>2023-01-23T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/faq</loc>
<lastmod>2023-01-05T00:00:00+00:00</lastmod>
<lastmod>2023-01-23T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/features</loc>
<lastmod>2023-01-05T00:00:00+00:00</lastmod>
<lastmod>2023-01-23T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/markets</loc>
<lastmod>2023-01-05T00:00:00+00:00</lastmod>
<lastmod>2023-01-23T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/pricing</loc>
<lastmod>2023-01-05T00:00:00+00:00</lastmod>
<lastmod>2023-01-23T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/register</loc>
<lastmod>2023-01-05T00:00:00+00:00</lastmod>
<lastmod>2023-01-23T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources</loc>
<lastmod>2023-01-05T00:00:00+00:00</lastmod>
<lastmod>2023-01-23T00:00:00+00:00</lastmod>
</url>
</urlset>

View File

@ -1694,7 +1694,7 @@
<target state="translated">Nach Währung</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">67</context>
<context context-type="linenumber">61</context>
</context-group>
</trans-unit>
<trans-unit id="8288ff761f2d259625d2e5a3d96db727926d9cd4" datatype="html">
@ -1702,7 +1702,7 @@
<target state="translated">Nach Anlageklasse</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">84</context>
</context-group>
</trans-unit>
<trans-unit id="b64539bb7815eb3275b55ad723d3897fc6ba8d23" datatype="html">
@ -1710,7 +1710,7 @@
<target state="translated">Nach Position</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">125</context>
<context context-type="linenumber">107</context>
</context-group>
</trans-unit>
<trans-unit id="9f86714c9a6b74e13c96ab02102ce40c34fe13b9" datatype="html">
@ -1718,7 +1718,7 @@
<target state="translated">Nach Sektor</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">130</context>
</context-group>
</trans-unit>
<trans-unit id="7017e0e26b53ef322c3e3bbf95f06a85487a12b2" datatype="html">
@ -1726,7 +1726,7 @@
<target state="translated">Nach Kontinent</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">184</context>
<context context-type="linenumber">154</context>
</context-group>
</trans-unit>
<trans-unit id="f27e9dd8de80176286e02312e694cb8d1e485a5d" datatype="html">
@ -1734,7 +1734,7 @@
<target state="translated">Nach Land</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">213</context>
<context context-type="linenumber">177</context>
</context-group>
</trans-unit>
<trans-unit id="85780db87ac6c9f202615ac63754551c061e7236" datatype="html">
@ -1742,7 +1742,7 @@
<target state="translated">Regionen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">245</context>
<context context-type="linenumber">203</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2370,7 +2370,7 @@
<target state="translated">Entwickelte Länder</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">272</context>
<context context-type="linenumber">224</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2382,7 +2382,7 @@
<target state="translated">Schwellenländer</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">281</context>
<context context-type="linenumber">233</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2394,7 +2394,7 @@
<target state="translated">Andere Länder</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">290</context>
<context context-type="linenumber">242</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2417,22 +2417,6 @@
<context context-type="linenumber">44</context>
</context-group>
</trans-unit>
<trans-unit id="2937311350146031865" datatype="html">
<source>Initial</source>
<target state="translated">Beginn</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
<context context-type="linenumber">58</context>
</context-group>
</trans-unit>
<trans-unit id="6603000223840533819" datatype="html">
<source>Current</source>
<target state="translated">Aktuell</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
<context context-type="linenumber">59</context>
</context-group>
</trans-unit>
<trans-unit id="6762743264882388498" datatype="html">
<source>Monthly</source>
<target state="translated">Monatlich</target>
@ -2454,7 +2438,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">281</context>
<context context-type="linenumber">283</context>
</context-group>
</trans-unit>
<trans-unit id="3441715041566940420" datatype="html">
@ -2462,7 +2446,7 @@
<target state="translated">Verzinsung</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">291</context>
<context context-type="linenumber">293</context>
</context-group>
</trans-unit>
<trans-unit id="1054498214311181686" datatype="html">
@ -2470,7 +2454,7 @@
<target state="translated">Ersparnisse</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">301</context>
<context context-type="linenumber">303</context>
</context-group>
</trans-unit>
<trans-unit id="aad5320acd7453f912bc8714e72c2fa71e8ab18e" datatype="html">
@ -2518,7 +2502,7 @@
<target state="translated">Filtern nach Konto oder Tag...</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
<context context-type="linenumber">137</context>
<context context-type="linenumber">132</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
@ -2666,7 +2650,7 @@
<target state="translated">Gesamtbetrag</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">178</context>
<context context-type="linenumber">181</context>
</context-group>
</trans-unit>
<trans-unit id="f1a355a1af2e818050a3af693ac8b521fa7edc5f" datatype="html">
@ -2682,7 +2666,7 @@
<target state="translated">Sparrate</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">242</context>
<context context-type="linenumber">245</context>
</context-group>
</trans-unit>
<trans-unit id="4086606389696938932" datatype="html">

View File

@ -1695,7 +1695,7 @@
<target state="translated">Por divisa</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">67</context>
<context context-type="linenumber">61</context>
</context-group>
</trans-unit>
<trans-unit id="8288ff761f2d259625d2e5a3d96db727926d9cd4" datatype="html">
@ -1703,7 +1703,7 @@
<target state="translated">Por tipo de activo</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">84</context>
</context-group>
</trans-unit>
<trans-unit id="b64539bb7815eb3275b55ad723d3897fc6ba8d23" datatype="html">
@ -1711,7 +1711,7 @@
<target state="translated">Por participación</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">125</context>
<context context-type="linenumber">107</context>
</context-group>
</trans-unit>
<trans-unit id="9f86714c9a6b74e13c96ab02102ce40c34fe13b9" datatype="html">
@ -1719,7 +1719,7 @@
<target state="translated">Por sector</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">130</context>
</context-group>
</trans-unit>
<trans-unit id="7017e0e26b53ef322c3e3bbf95f06a85487a12b2" datatype="html">
@ -1727,7 +1727,7 @@
<target state="translated">Por continente</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">184</context>
<context context-type="linenumber">154</context>
</context-group>
</trans-unit>
<trans-unit id="f27e9dd8de80176286e02312e694cb8d1e485a5d" datatype="html">
@ -1735,7 +1735,7 @@
<target state="translated">Por país</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">213</context>
<context context-type="linenumber">177</context>
</context-group>
</trans-unit>
<trans-unit id="85780db87ac6c9f202615ac63754551c061e7236" datatype="html">
@ -1743,7 +1743,7 @@
<target state="translated">Regiones</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">245</context>
<context context-type="linenumber">203</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2295,7 +2295,7 @@
<target state="translated">Mercados desarrollados</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">272</context>
<context context-type="linenumber">224</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2343,7 +2343,7 @@
<target state="translated">Otros mercados</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">290</context>
<context context-type="linenumber">242</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2355,7 +2355,7 @@
<target state="translated">Mercados emergentes</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">281</context>
<context context-type="linenumber">233</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2423,15 +2423,7 @@
<target state="translated">Ahorros</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">301</context>
</context-group>
</trans-unit>
<trans-unit id="2937311350146031865" datatype="html">
<source>Initial</source>
<target state="translated">Inicial</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
<context context-type="linenumber">58</context>
<context context-type="linenumber">303</context>
</context-group>
</trans-unit>
<trans-unit id="3441715041566940420" datatype="html">
@ -2439,7 +2431,7 @@
<target state="translated">Interés</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">291</context>
<context context-type="linenumber">293</context>
</context-group>
</trans-unit>
<trans-unit id="5213771062241898526" datatype="html">
@ -2455,15 +2447,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">281</context>
</context-group>
</trans-unit>
<trans-unit id="6603000223840533819" datatype="html">
<source>Current</source>
<target state="translated">Actual</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
<context context-type="linenumber">59</context>
<context context-type="linenumber">283</context>
</context-group>
</trans-unit>
<trans-unit id="6762743264882388498" datatype="html">
@ -2511,7 +2495,7 @@
<target state="translated">Filtrar por cuenta o etiqueta...</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
<context context-type="linenumber">137</context>
<context context-type="linenumber">132</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
@ -2667,7 +2651,7 @@
<target state="translated">Importe total</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">178</context>
<context context-type="linenumber">181</context>
</context-group>
</trans-unit>
<trans-unit id="f1a355a1af2e818050a3af693ac8b521fa7edc5f" datatype="html">
@ -2683,7 +2667,7 @@
<target state="translated">Tasa de ahorro</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">242</context>
<context context-type="linenumber">245</context>
</context-group>
</trans-unit>
<trans-unit id="4086606389696938932" datatype="html">

View File

@ -1218,7 +1218,7 @@
<target state="translated">Montant Total</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">178</context>
<context context-type="linenumber">181</context>
</context-group>
</trans-unit>
<trans-unit id="8192718423057883427" datatype="html">
@ -1226,7 +1226,7 @@
<target state="translated">Taux d&apos;Épargne</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">242</context>
<context context-type="linenumber">245</context>
</context-group>
</trans-unit>
<trans-unit id="6a95e051c4fd80012488effb15d2842b2155ae5e" datatype="html">
@ -2209,28 +2209,12 @@
<context context-type="linenumber">12</context>
</context-group>
</trans-unit>
<trans-unit id="2937311350146031865" datatype="html">
<source>Initial</source>
<target state="translated">Initial</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
<context context-type="linenumber">58</context>
</context-group>
</trans-unit>
<trans-unit id="6603000223840533819" datatype="html">
<source>Current</source>
<target state="translated">Actuel</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
<context context-type="linenumber">59</context>
</context-group>
</trans-unit>
<trans-unit id="2078421919111943467" datatype="html">
<source>Filter by account or tag...</source>
<target state="translated">Filtrer par compte ou étiquette...</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
<context context-type="linenumber">137</context>
<context context-type="linenumber">132</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
@ -2270,7 +2254,7 @@
<target state="translated">Par Devise</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">67</context>
<context context-type="linenumber">61</context>
</context-group>
</trans-unit>
<trans-unit id="8288ff761f2d259625d2e5a3d96db727926d9cd4" datatype="html">
@ -2278,7 +2262,7 @@
<target state="translated">Par Classe d&apos;Actifs</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">84</context>
</context-group>
</trans-unit>
<trans-unit id="b64539bb7815eb3275b55ad723d3897fc6ba8d23" datatype="html">
@ -2286,7 +2270,7 @@
<target state="translated">Par Position</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">125</context>
<context context-type="linenumber">107</context>
</context-group>
</trans-unit>
<trans-unit id="9f86714c9a6b74e13c96ab02102ce40c34fe13b9" datatype="html">
@ -2294,7 +2278,7 @@
<target state="translated">Par Secteur</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">130</context>
</context-group>
</trans-unit>
<trans-unit id="7017e0e26b53ef322c3e3bbf95f06a85487a12b2" datatype="html">
@ -2302,7 +2286,7 @@
<target state="translated">Par Continent</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">184</context>
<context context-type="linenumber">154</context>
</context-group>
</trans-unit>
<trans-unit id="f27e9dd8de80176286e02312e694cb8d1e485a5d" datatype="html">
@ -2310,7 +2294,7 @@
<target state="translated">Par Pays</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">213</context>
<context context-type="linenumber">177</context>
</context-group>
</trans-unit>
<trans-unit id="85780db87ac6c9f202615ac63754551c061e7236" datatype="html">
@ -2318,7 +2302,7 @@
<target state="translated">Régions</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">245</context>
<context context-type="linenumber">203</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2330,7 +2314,7 @@
<target state="translated">Marchés Développés</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">272</context>
<context context-type="linenumber">224</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2342,7 +2326,7 @@
<target state="translated">Marchés Émergents</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">281</context>
<context context-type="linenumber">233</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2354,7 +2338,7 @@
<target state="translated">Autres marchés</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">290</context>
<context context-type="linenumber">242</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2390,7 +2374,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">281</context>
<context context-type="linenumber">283</context>
</context-group>
</trans-unit>
<trans-unit id="6762743264882388498" datatype="html">
@ -2790,7 +2774,7 @@
<target state="translated">Intérêt</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">291</context>
<context context-type="linenumber">293</context>
</context-group>
</trans-unit>
<trans-unit id="1054498214311181686" datatype="html">
@ -2798,7 +2782,7 @@
<target state="translated">Épargne</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">301</context>
<context context-type="linenumber">303</context>
</context-group>
</trans-unit>
<trans-unit id="2ee26d58f2707416e636887111d5603b35346c4a" datatype="html">

View File

@ -1695,7 +1695,7 @@
<target state="translated">Per valuta</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">67</context>
<context context-type="linenumber">61</context>
</context-group>
</trans-unit>
<trans-unit id="8288ff761f2d259625d2e5a3d96db727926d9cd4" datatype="html">
@ -1703,7 +1703,7 @@
<target state="translated">Per asset class</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">84</context>
</context-group>
</trans-unit>
<trans-unit id="b64539bb7815eb3275b55ad723d3897fc6ba8d23" datatype="html">
@ -1711,7 +1711,7 @@
<target state="translated">Per partecipazione</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">125</context>
<context context-type="linenumber">107</context>
</context-group>
</trans-unit>
<trans-unit id="9f86714c9a6b74e13c96ab02102ce40c34fe13b9" datatype="html">
@ -1719,7 +1719,7 @@
<target state="translated">Per settore</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">130</context>
</context-group>
</trans-unit>
<trans-unit id="7017e0e26b53ef322c3e3bbf95f06a85487a12b2" datatype="html">
@ -1727,7 +1727,7 @@
<target state="translated">Per continente</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">184</context>
<context context-type="linenumber">154</context>
</context-group>
</trans-unit>
<trans-unit id="f27e9dd8de80176286e02312e694cb8d1e485a5d" datatype="html">
@ -1735,7 +1735,7 @@
<target state="translated">Per paese</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">213</context>
<context context-type="linenumber">177</context>
</context-group>
</trans-unit>
<trans-unit id="85780db87ac6c9f202615ac63754551c061e7236" datatype="html">
@ -1743,7 +1743,7 @@
<target state="translated">Regioni</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">245</context>
<context context-type="linenumber">203</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2295,7 +2295,7 @@
<target state="translated">Mercati sviluppati</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">272</context>
<context context-type="linenumber">224</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2343,7 +2343,7 @@
<target state="translated">Altri mercati</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">290</context>
<context context-type="linenumber">242</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2355,7 +2355,7 @@
<target state="translated">Mercati emergenti</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">281</context>
<context context-type="linenumber">233</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2423,15 +2423,7 @@
<target state="translated">Risparmio</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">301</context>
</context-group>
</trans-unit>
<trans-unit id="2937311350146031865" datatype="html">
<source>Initial</source>
<target state="translated">Iniziale</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
<context context-type="linenumber">58</context>
<context context-type="linenumber">303</context>
</context-group>
</trans-unit>
<trans-unit id="3441715041566940420" datatype="html">
@ -2439,7 +2431,7 @@
<target state="translated">Interesse</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">291</context>
<context context-type="linenumber">293</context>
</context-group>
</trans-unit>
<trans-unit id="5213771062241898526" datatype="html">
@ -2455,15 +2447,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">281</context>
</context-group>
</trans-unit>
<trans-unit id="6603000223840533819" datatype="html">
<source>Current</source>
<target state="translated">Attuale</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
<context context-type="linenumber">59</context>
<context context-type="linenumber">283</context>
</context-group>
</trans-unit>
<trans-unit id="6762743264882388498" datatype="html">
@ -2511,7 +2495,7 @@
<target state="translated">Filtra per account o tag...</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
<context context-type="linenumber">137</context>
<context context-type="linenumber">132</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
@ -2667,7 +2651,7 @@
<target state="new">Total Amount</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">178</context>
<context context-type="linenumber">181</context>
</context-group>
</trans-unit>
<trans-unit id="f1a355a1af2e818050a3af693ac8b521fa7edc5f" datatype="html">
@ -2683,7 +2667,7 @@
<target state="translated">Tasso di risparmio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">242</context>
<context context-type="linenumber">245</context>
</context-group>
</trans-unit>
<trans-unit id="4086606389696938932" datatype="html">

View File

@ -1694,7 +1694,7 @@
<target state="translated">Per valuta</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">67</context>
<context context-type="linenumber">61</context>
</context-group>
</trans-unit>
<trans-unit id="8288ff761f2d259625d2e5a3d96db727926d9cd4" datatype="html">
@ -1702,7 +1702,7 @@
<target state="translated">Per activaklasse</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">84</context>
</context-group>
</trans-unit>
<trans-unit id="b64539bb7815eb3275b55ad723d3897fc6ba8d23" datatype="html">
@ -1710,7 +1710,7 @@
<target state="translated">Per participatie</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">125</context>
<context context-type="linenumber">107</context>
</context-group>
</trans-unit>
<trans-unit id="9f86714c9a6b74e13c96ab02102ce40c34fe13b9" datatype="html">
@ -1718,7 +1718,7 @@
<target state="translated">Per Sector</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">130</context>
</context-group>
</trans-unit>
<trans-unit id="7017e0e26b53ef322c3e3bbf95f06a85487a12b2" datatype="html">
@ -1726,7 +1726,7 @@
<target state="translated">Per continent</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">184</context>
<context context-type="linenumber">154</context>
</context-group>
</trans-unit>
<trans-unit id="f27e9dd8de80176286e02312e694cb8d1e485a5d" datatype="html">
@ -1734,7 +1734,7 @@
<target state="translated">Per land</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">213</context>
<context context-type="linenumber">177</context>
</context-group>
</trans-unit>
<trans-unit id="85780db87ac6c9f202615ac63754551c061e7236" datatype="html">
@ -1742,7 +1742,7 @@
<target state="translated">Regio&apos;s</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">245</context>
<context context-type="linenumber">203</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2294,7 +2294,7 @@
<target state="translated">Ontwikkelde markten</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">272</context>
<context context-type="linenumber">224</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2342,7 +2342,7 @@
<target state="translated">Andere markten</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">290</context>
<context context-type="linenumber">242</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2354,7 +2354,7 @@
<target state="translated">Opkomende markten</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">281</context>
<context context-type="linenumber">233</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2422,15 +2422,7 @@
<target state="translated">Besparingen</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">301</context>
</context-group>
</trans-unit>
<trans-unit id="2937311350146031865" datatype="html">
<source>Initial</source>
<target state="translated">Aanvankelijk</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
<context context-type="linenumber">58</context>
<context context-type="linenumber">303</context>
</context-group>
</trans-unit>
<trans-unit id="3441715041566940420" datatype="html">
@ -2438,7 +2430,7 @@
<target state="translated">Rente</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">291</context>
<context context-type="linenumber">293</context>
</context-group>
</trans-unit>
<trans-unit id="5213771062241898526" datatype="html">
@ -2454,15 +2446,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">281</context>
</context-group>
</trans-unit>
<trans-unit id="6603000223840533819" datatype="html">
<source>Current</source>
<target state="translated">Huidige</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
<context context-type="linenumber">59</context>
<context context-type="linenumber">283</context>
</context-group>
</trans-unit>
<trans-unit id="6762743264882388498" datatype="html">
@ -2510,7 +2494,7 @@
<target state="translated">Filter op account of tag...</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
<context context-type="linenumber">137</context>
<context context-type="linenumber">132</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
@ -2666,7 +2650,7 @@
<target state="translated">Totaalbedrag</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">178</context>
<context context-type="linenumber">181</context>
</context-group>
</trans-unit>
<trans-unit id="f1a355a1af2e818050a3af693ac8b521fa7edc5f" datatype="html">
@ -2682,7 +2666,7 @@
<target state="translated">Spaarquote</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">242</context>
<context context-type="linenumber">245</context>
</context-group>
</trans-unit>
<trans-unit id="4086606389696938932" datatype="html">

View File

@ -1114,7 +1114,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">281</context>
<context context-type="linenumber">283</context>
</context-group>
</trans-unit>
<trans-unit id="112783260724635106" datatype="html">
@ -1122,7 +1122,7 @@
<target state="new">Total Amount</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">178</context>
<context context-type="linenumber">181</context>
</context-group>
</trans-unit>
<trans-unit id="8192718423057883427" datatype="html">
@ -1130,7 +1130,7 @@
<target state="new">Savings Rate</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">242</context>
<context context-type="linenumber">245</context>
</context-group>
</trans-unit>
<trans-unit id="6a95e051c4fd80012488effb15d2842b2155ae5e" datatype="html">
@ -2153,28 +2153,12 @@
<context context-type="linenumber">12</context>
</context-group>
</trans-unit>
<trans-unit id="2937311350146031865" datatype="html">
<source>Initial</source>
<target state="new">Initial</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
<context context-type="linenumber">58</context>
</context-group>
</trans-unit>
<trans-unit id="6603000223840533819" datatype="html">
<source>Current</source>
<target state="new">Current</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
<context context-type="linenumber">59</context>
</context-group>
</trans-unit>
<trans-unit id="2078421919111943467" datatype="html">
<source>Filter by account or tag...</source>
<target state="new">Filter by account or tag...</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
<context context-type="linenumber">137</context>
<context context-type="linenumber">132</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
@ -2214,7 +2198,7 @@
<target state="new">By Currency</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">67</context>
<context context-type="linenumber">61</context>
</context-group>
</trans-unit>
<trans-unit id="8288ff761f2d259625d2e5a3d96db727926d9cd4" datatype="html">
@ -2222,7 +2206,7 @@
<target state="new">By Asset Class</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">84</context>
</context-group>
</trans-unit>
<trans-unit id="b64539bb7815eb3275b55ad723d3897fc6ba8d23" datatype="html">
@ -2230,7 +2214,7 @@
<target state="new">By Holding</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">125</context>
<context context-type="linenumber">107</context>
</context-group>
</trans-unit>
<trans-unit id="9f86714c9a6b74e13c96ab02102ce40c34fe13b9" datatype="html">
@ -2238,7 +2222,7 @@
<target state="new">By Sector</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">130</context>
</context-group>
</trans-unit>
<trans-unit id="7017e0e26b53ef322c3e3bbf95f06a85487a12b2" datatype="html">
@ -2246,7 +2230,7 @@
<target state="new">By Continent</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">184</context>
<context context-type="linenumber">154</context>
</context-group>
</trans-unit>
<trans-unit id="f27e9dd8de80176286e02312e694cb8d1e485a5d" datatype="html">
@ -2254,7 +2238,7 @@
<target state="new">By Country</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">213</context>
<context context-type="linenumber">177</context>
</context-group>
</trans-unit>
<trans-unit id="85780db87ac6c9f202615ac63754551c061e7236" datatype="html">
@ -2262,7 +2246,7 @@
<target state="new">Regions</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">245</context>
<context context-type="linenumber">203</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2274,7 +2258,7 @@
<target state="new">Developed Markets</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">272</context>
<context context-type="linenumber">224</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2286,7 +2270,7 @@
<target state="new">Emerging Markets</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">281</context>
<context context-type="linenumber">233</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2298,7 +2282,7 @@
<target state="new">Other Markets</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">290</context>
<context context-type="linenumber">242</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2706,7 +2690,7 @@
<target state="new">Interest</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">291</context>
<context context-type="linenumber">293</context>
</context-group>
</trans-unit>
<trans-unit id="1054498214311181686" datatype="html">
@ -2714,7 +2698,7 @@
<target state="new">Savings</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">301</context>
<context context-type="linenumber">303</context>
</context-group>
</trans-unit>
<trans-unit id="4086606389696938932" datatype="html">

View File

@ -1529,49 +1529,49 @@
<source>By Currency</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">67</context>
<context context-type="linenumber">61</context>
</context-group>
</trans-unit>
<trans-unit id="8288ff761f2d259625d2e5a3d96db727926d9cd4" datatype="html">
<source>By Asset Class</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">96</context>
<context context-type="linenumber">84</context>
</context-group>
</trans-unit>
<trans-unit id="b64539bb7815eb3275b55ad723d3897fc6ba8d23" datatype="html">
<source>By Holding</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">125</context>
<context context-type="linenumber">107</context>
</context-group>
</trans-unit>
<trans-unit id="9f86714c9a6b74e13c96ab02102ce40c34fe13b9" datatype="html">
<source>By Sector</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">130</context>
</context-group>
</trans-unit>
<trans-unit id="7017e0e26b53ef322c3e3bbf95f06a85487a12b2" datatype="html">
<source>By Continent</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">184</context>
<context context-type="linenumber">154</context>
</context-group>
</trans-unit>
<trans-unit id="f27e9dd8de80176286e02312e694cb8d1e485a5d" datatype="html">
<source>By Country</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">213</context>
<context context-type="linenumber">177</context>
</context-group>
</trans-unit>
<trans-unit id="85780db87ac6c9f202615ac63754551c061e7236" datatype="html">
<source>Regions</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">245</context>
<context context-type="linenumber">203</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2062,7 +2062,7 @@
<source>Developed Markets</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">272</context>
<context context-type="linenumber">224</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2106,7 +2106,7 @@
<source>Other Markets</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">290</context>
<context context-type="linenumber">242</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2117,7 +2117,7 @@
<source>Emerging Markets</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
<context context-type="linenumber">281</context>
<context context-type="linenumber">233</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -2178,21 +2178,14 @@
<source>Savings</source>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">301</context>
</context-group>
</trans-unit>
<trans-unit id="2937311350146031865" datatype="html">
<source>Initial</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
<context context-type="linenumber">58</context>
<context context-type="linenumber">303</context>
</context-group>
</trans-unit>
<trans-unit id="3441715041566940420" datatype="html">
<source>Interest</source>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">291</context>
<context context-type="linenumber">293</context>
</context-group>
</trans-unit>
<trans-unit id="5213771062241898526" datatype="html">
@ -2207,14 +2200,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">281</context>
</context-group>
</trans-unit>
<trans-unit id="6603000223840533819" datatype="html">
<source>Current</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
<context context-type="linenumber">59</context>
<context context-type="linenumber">283</context>
</context-group>
</trans-unit>
<trans-unit id="6762743264882388498" datatype="html">
@ -2256,7 +2242,7 @@
<source>Filter by account or tag...</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
<context context-type="linenumber">137</context>
<context context-type="linenumber">132</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
@ -2394,7 +2380,7 @@
<source>Total Amount</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">178</context>
<context context-type="linenumber">181</context>
</context-group>
</trans-unit>
<trans-unit id="f1a355a1af2e818050a3af693ac8b521fa7edc5f" datatype="html">
@ -2408,7 +2394,7 @@
<source>Savings Rate</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">242</context>
<context context-type="linenumber">245</context>
</context-group>
</trans-unit>
<trans-unit id="1270654249046226808" datatype="html">

View File

@ -2,9 +2,11 @@ export interface HistoricalDataItem {
averagePrice?: number;
date: string;
grossPerformancePercent?: number;
marketPrice?: number;
netPerformance?: number;
netPerformanceInPercentage?: number;
quantity?: number;
totalInvestment?: number;
value?: number;
valueInPercentage?: number;
}

View File

@ -5,8 +5,7 @@ import { Country } from './country.interface';
import { Sector } from './sector.interface';
export interface PortfolioPosition {
allocationCurrent: number;
allocationInvestment: number;
allocationInPercentage: number;
assetClass?: AssetClass;
assetSubClass?: AssetSubClass | 'CASH';
countries: Country[];
@ -31,5 +30,6 @@ export interface PortfolioPosition {
symbol: string;
type?: string;
url?: string;
value: number;
value?: number;
valueInPercentage?: number;
}

View File

@ -6,7 +6,7 @@ export interface PortfolioPublicDetails {
holdings: {
[symbol: string]: Pick<
PortfolioPosition,
| 'allocationCurrent'
| 'allocationInPercentage'
| 'countries'
| 'currency'
| 'dataSource'
@ -18,6 +18,7 @@ export interface PortfolioPublicDetails {
| 'symbol'
| 'url'
| 'value'
| 'valueInPercentage'
>;
};
}

View File

@ -5,6 +5,7 @@ import { UserSettings } from './user-settings.interface';
export type UserWithSettings = User & {
Account: Account[];
activityCount: number;
permissions?: string[];
Settings: Settings & { settings: UserSettings };
subscription?: {

View File

@ -19,6 +19,7 @@ export const permissions = {
enableSocialLogin: 'enableSocialLogin',
enableStatistics: 'enableStatistics',
enableSubscription: 'enableSubscription',
enableSubscriptionInterstitial: 'enableSubscriptionInterstitial',
enableSystemMessage: 'enableSystemMessage',
reportDataGlitch: 'reportDataGlitch',
toggleReadOnlyMode: 'toggleReadOnlyMode',

View File

@ -3,7 +3,7 @@
class="gf-table w-100"
mat-table
matSort
matSortActive="allocationCurrent"
matSortActive="allocationInPercentage"
matSortDirection="desc"
[dataSource]="dataSource"
>
@ -85,7 +85,7 @@
</td>
</ng-container>
<ng-container matColumnDef="allocationCurrent">
<ng-container matColumnDef="allocationInPercentage">
<th
*matHeaderCellDef
class="justify-content-end px-1"
@ -99,7 +99,7 @@
<gf-value
[isPercent]="true"
[locale]="locale"
[value]="isLoading ? undefined : element.allocationCurrent"
[value]="isLoading ? undefined : element.allocationInPercentage"
></gf-value>
</div>
</td>

View File

@ -58,7 +58,7 @@ export class HoldingsTableComponent implements OnChanges, OnDestroy, OnInit {
this.displayedColumns.push('value');
}
this.displayedColumns.push('allocationCurrent');
this.displayedColumns.push('allocationInPercentage');
this.displayedColumns.push('performance');
this.isLoading = true;

View File

@ -1,6 +1,6 @@
{
"name": "ghostfolio",
"version": "1.228.1",
"version": "1.230.0",
"homepage": "https://ghostfol.io",
"license": "AGPL-3.0",
"scripts": {
@ -81,7 +81,7 @@
"@nestjs/schedule": "2.1.0",
"@nestjs/serve-static": "3.0.0",
"@nrwl/angular": "15.0.13",
"@prisma/client": "4.8.0",
"@prisma/client": "4.9.0",
"@simplewebauthn/browser": "5.2.1",
"@simplewebauthn/server": "5.2.1",
"@stripe/stripe-js": "1.22.0",
@ -119,7 +119,7 @@
"passport": "0.6.0",
"passport-google-oauth20": "2.0.0",
"passport-jwt": "4.0.0",
"prisma": "4.8.0",
"prisma": "4.9.0",
"reflect-metadata": "0.1.13",
"rxjs": "7.5.6",
"stripe": "8.199.0",

View File

@ -3677,22 +3677,22 @@
dependencies:
esquery "^1.0.1"
"@prisma/client@4.8.0":
version "4.8.0"
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-4.8.0.tgz#6ec7adaca6a2e233d7e41dbe7cc6d0fa6143a407"
integrity sha512-Y1riB0p2W52kh3zgssP/YAhln3RjBFcJy3uwEiyjmU+TQYh6QTZDRFBo3JtBWuq2FyMOl1Rye8jxzUP+n0l5Cg==
"@prisma/client@4.9.0":
version "4.9.0"
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-4.9.0.tgz#4a4068f3540732ea5723c008d49ed684d20f9340"
integrity sha512-bz6QARw54sWcbyR1lLnF2QHvRW5R/Jxnbbmwh3u+969vUKXtBkXgSgjDA85nji31ZBlf7+FrHDy5x+5ydGyQDg==
dependencies:
"@prisma/engines-version" "4.8.0-61.d6e67a83f971b175a593ccc12e15c4a757f93ffe"
"@prisma/engines-version" "4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5"
"@prisma/engines-version@4.8.0-61.d6e67a83f971b175a593ccc12e15c4a757f93ffe":
version "4.8.0-61.d6e67a83f971b175a593ccc12e15c4a757f93ffe"
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-4.8.0-61.d6e67a83f971b175a593ccc12e15c4a757f93ffe.tgz#30401aba1029e7d32e3cb717e705a7c92ccc211e"
integrity sha512-MHSOSexomRMom8QN4t7bu87wPPD+pa+hW9+71JnVcF3DqyyO/ycCLhRL1we3EojRpZxKvuyGho2REQsMCvxcJw==
"@prisma/engines-version@4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5":
version "4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5"
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-4.9.0-42.ceb5c99003b99c9ee2c1d2e618e359c14aef2ea5.tgz#9d817a5779fc05b107eb02f63d197ad296d60b3c"
integrity sha512-M16aibbxi/FhW7z1sJCX8u+0DriyQYY5AyeTH7plQm9MLnURoiyn3CZBqAyIoQ+Z1pS77usCIibYJWSgleBMBA==
"@prisma/engines@4.8.0":
version "4.8.0"
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-4.8.0.tgz#5123c67dc0d2caa008268fc63081ca2d68b2ed7e"
integrity sha512-A1Asn2rxZMlLAj1HTyfaCv0VQrLUv034jVay05QlqZg1qiHPeA3/pGTfNMijbsMYCsGVxfWEJuaZZuNxXGMCrA==
"@prisma/engines@4.9.0":
version "4.9.0"
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-4.9.0.tgz#05a1411964e047c1bc43f777c7a1c69f86a2a26c"
integrity sha512-t1pt0Gsp+HcgPJrHFc+d/ZSAaKKWar2G/iakrE07yeKPNavDP3iVKPpfXP22OTCHZUWf7OelwKJxQgKAm5hkgw==
"@samverschueren/stream-to-observable@^0.3.0":
version "0.3.1"
@ -16427,12 +16427,12 @@ pretty-hrtime@^1.0.3:
resolved "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz"
integrity sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==
prisma@4.8.0:
version "4.8.0"
resolved "https://registry.yarnpkg.com/prisma/-/prisma-4.8.0.tgz#634dbbdc9d3f76c61604880251673d08ccb6f02b"
integrity sha512-DWIhxvxt8f4h6MDd35mz7BJff+fu7HItW3WPDIEpCR3RzcOWyiHBbLQW5/DOgmf+pRLTjwXQob7kuTZVYUAw5w==
prisma@4.9.0:
version "4.9.0"
resolved "https://registry.yarnpkg.com/prisma/-/prisma-4.9.0.tgz#295954b2a89cd35a0e6bcf66b2b036dbf80c75ee"
integrity sha512-bS96oZ5oDFXYgoF2l7PJ3Mp1wWWfLOo8B/jAfbA2Pn0Wm5Z/owBHzaMQKS3i1CzVBDWWPVnOohmbJmjvkcHS5w==
dependencies:
"@prisma/engines" "4.8.0"
"@prisma/engines" "4.9.0"
prismjs@^1.27.0, prismjs@^1.28.0:
version "1.28.0"