Feature/improve local number formatting in value component (#1992)
* Improve local number formatting * Update changelog
This commit is contained in:
parent
73c127f10c
commit
86296b3591
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Improved the local number formatting in the value component
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fixed the vertical alignment in the toggle component
|
- Fixed the vertical alignment in the toggle component
|
||||||
|
@ -20,9 +20,11 @@ import {
|
|||||||
encodeDataSource,
|
encodeDataSource,
|
||||||
extractNumberFromString
|
extractNumberFromString
|
||||||
} from '@ghostfolio/common/helper';
|
} from '@ghostfolio/common/helper';
|
||||||
import { InfoItem } from '@ghostfolio/common/interfaces';
|
import {
|
||||||
import { Statistics } from '@ghostfolio/common/interfaces/statistics.interface';
|
InfoItem,
|
||||||
import { Subscription } from '@ghostfolio/common/interfaces/subscription.interface';
|
Statistics,
|
||||||
|
Subscription
|
||||||
|
} from '@ghostfolio/common/interfaces';
|
||||||
import { permissions } from '@ghostfolio/common/permissions';
|
import { permissions } from '@ghostfolio/common/permissions';
|
||||||
import { SubscriptionOffer } from '@ghostfolio/common/types';
|
import { SubscriptionOffer } from '@ghostfolio/common/types';
|
||||||
import { Injectable, Logger } from '@nestjs/common';
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
|
@ -4,7 +4,7 @@ import {
|
|||||||
DEFAULT_LANGUAGE_CODE,
|
DEFAULT_LANGUAGE_CODE,
|
||||||
PROPERTY_STRIPE_CONFIG
|
PROPERTY_STRIPE_CONFIG
|
||||||
} from '@ghostfolio/common/config';
|
} from '@ghostfolio/common/config';
|
||||||
import { Subscription as SubscriptionInterface } from '@ghostfolio/common/interfaces/subscription.interface';
|
import { Subscription as SubscriptionInterface } from '@ghostfolio/common/interfaces';
|
||||||
import { UserWithSettings } from '@ghostfolio/common/types';
|
import { UserWithSettings } from '@ghostfolio/common/types';
|
||||||
import { SubscriptionType } from '@ghostfolio/common/types/subscription-type.type';
|
import { SubscriptionType } from '@ghostfolio/common/types/subscription-type.type';
|
||||||
import { Injectable, Logger } from '@nestjs/common';
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
|
@ -3,8 +3,7 @@ import { environment } from '@ghostfolio/client/../environments/environment';
|
|||||||
import { DataService } from '@ghostfolio/client/services/data.service';
|
import { DataService } from '@ghostfolio/client/services/data.service';
|
||||||
import { UserService } from '@ghostfolio/client/services/user/user.service';
|
import { UserService } from '@ghostfolio/client/services/user/user.service';
|
||||||
import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config';
|
import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config';
|
||||||
import { User } from '@ghostfolio/common/interfaces';
|
import { Statistics, User } from '@ghostfolio/common/interfaces';
|
||||||
import { Statistics } from '@ghostfolio/common/interfaces/statistics.interface';
|
|
||||||
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
import { takeUntil } from 'rxjs/operators';
|
||||||
|
@ -6,12 +6,26 @@
|
|||||||
<p>
|
<p>
|
||||||
Ghostfolio is a lightweight wealth management application for
|
Ghostfolio is a lightweight wealth management application for
|
||||||
individuals to keep track of stocks, ETFs or cryptocurrencies and make
|
individuals to keep track of stocks, ETFs or cryptocurrencies and make
|
||||||
solid, data-driven investment decisions. We share aggregated
|
solid, data-driven investment decisions. The source code is fully
|
||||||
<a href="https://ghostfol.io/{{ defaultLanguageCode }}/open"
|
available as
|
||||||
|
<a
|
||||||
|
href="https://github.com/ghostfolio/ghostfolio"
|
||||||
|
title="Find Ghostfolio on GitHub"
|
||||||
|
>open source software</a
|
||||||
|
>
|
||||||
|
(OSS) under the
|
||||||
|
<a
|
||||||
|
href="https://www.gnu.org/licenses/agpl-3.0.html"
|
||||||
|
title="GNU Affero General Public License"
|
||||||
|
>AGPL-3.0 license</a
|
||||||
|
>
|
||||||
|
and we share aggregated
|
||||||
|
<a
|
||||||
|
href="https://ghostfol.io/{{ defaultLanguageCode }}/open"
|
||||||
|
title="Open Startup"
|
||||||
>key metrics</a
|
>key metrics</a
|
||||||
>
|
>
|
||||||
of our platform’s performance and the source code is fully available
|
of the platform’s performance. The project has been initiated by
|
||||||
as open source software (OSS). The project has been initiated by
|
|
||||||
<a href="https://dotsilver.ch" title="Website of Thomas Kaul"
|
<a href="https://dotsilver.ch" title="Website of Thomas Kaul"
|
||||||
>Thomas Kaul</a
|
>Thomas Kaul</a
|
||||||
>
|
>
|
||||||
@ -130,6 +144,7 @@
|
|||||||
<gf-value
|
<gf-value
|
||||||
size="large"
|
size="large"
|
||||||
subLabel="(Last 24 hours)"
|
subLabel="(Last 24 hours)"
|
||||||
|
[locale]="user?.settings?.locale"
|
||||||
[value]="statistics?.activeUsers1d ?? '-'"
|
[value]="statistics?.activeUsers1d ?? '-'"
|
||||||
>Active Users</gf-value
|
>Active Users</gf-value
|
||||||
>
|
>
|
||||||
@ -138,6 +153,7 @@
|
|||||||
<gf-value
|
<gf-value
|
||||||
size="large"
|
size="large"
|
||||||
subLabel="(Last 30 days)"
|
subLabel="(Last 30 days)"
|
||||||
|
[locale]="user?.settings?.locale"
|
||||||
[value]="statistics?.newUsers30d ?? '-'"
|
[value]="statistics?.newUsers30d ?? '-'"
|
||||||
>New Users</gf-value
|
>New Users</gf-value
|
||||||
>
|
>
|
||||||
@ -146,6 +162,7 @@
|
|||||||
<gf-value
|
<gf-value
|
||||||
size="large"
|
size="large"
|
||||||
subLabel="(Last 30 days)"
|
subLabel="(Last 30 days)"
|
||||||
|
[locale]="user?.settings?.locale"
|
||||||
[value]="statistics?.activeUsers30d ?? '-'"
|
[value]="statistics?.activeUsers30d ?? '-'"
|
||||||
>Active Users</gf-value
|
>Active Users</gf-value
|
||||||
>
|
>
|
||||||
@ -154,6 +171,7 @@
|
|||||||
<a class="d-block" href="https://ghostfolio.slack.com">
|
<a class="d-block" href="https://ghostfolio.slack.com">
|
||||||
<gf-value
|
<gf-value
|
||||||
size="large"
|
size="large"
|
||||||
|
[locale]="user?.settings?.locale"
|
||||||
[value]="statistics?.slackCommunityUsers ?? '-'"
|
[value]="statistics?.slackCommunityUsers ?? '-'"
|
||||||
>Users in Slack community</gf-value
|
>Users in Slack community</gf-value
|
||||||
>
|
>
|
||||||
@ -166,6 +184,7 @@
|
|||||||
>
|
>
|
||||||
<gf-value
|
<gf-value
|
||||||
size="large"
|
size="large"
|
||||||
|
[locale]="user?.settings?.locale"
|
||||||
[value]="statistics?.gitHubContributors ?? '-'"
|
[value]="statistics?.gitHubContributors ?? '-'"
|
||||||
>Contributors on GitHub</gf-value
|
>Contributors on GitHub</gf-value
|
||||||
>
|
>
|
||||||
@ -178,6 +197,7 @@
|
|||||||
>
|
>
|
||||||
<gf-value
|
<gf-value
|
||||||
size="large"
|
size="large"
|
||||||
|
[locale]="user?.settings?.locale"
|
||||||
[value]="statistics?.gitHubStargazers ?? '-'"
|
[value]="statistics?.gitHubStargazers ?? '-'"
|
||||||
>Stars on GitHub</gf-value
|
>Stars on GitHub</gf-value
|
||||||
>
|
>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { DataService } from '@ghostfolio/client/services/data.service';
|
import { DataService } from '@ghostfolio/client/services/data.service';
|
||||||
import { Statistics } from '@ghostfolio/common/interfaces/statistics.interface';
|
import { Statistics } from '@ghostfolio/common/interfaces';
|
||||||
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
import { DeviceDetectorService } from 'ngx-device-detector';
|
import { DeviceDetectorService } from 'ngx-device-detector';
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { DataService } from '@ghostfolio/client/services/data.service';
|
import { DataService } from '@ghostfolio/client/services/data.service';
|
||||||
import { Statistics } from '@ghostfolio/common/interfaces/statistics.interface';
|
import { UserService } from '@ghostfolio/client/services/user/user.service';
|
||||||
import { Subject } from 'rxjs';
|
import { Statistics, User } from '@ghostfolio/common/interfaces';
|
||||||
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
host: { class: 'page' },
|
host: { class: 'page' },
|
||||||
@ -11,16 +12,31 @@ import { Subject } from 'rxjs';
|
|||||||
})
|
})
|
||||||
export class OpenPageComponent implements OnDestroy, OnInit {
|
export class OpenPageComponent implements OnDestroy, OnInit {
|
||||||
public statistics: Statistics;
|
public statistics: Statistics;
|
||||||
|
public user: User;
|
||||||
|
|
||||||
private unsubscribeSubject = new Subject<void>();
|
private unsubscribeSubject = new Subject<void>();
|
||||||
|
|
||||||
public constructor(private dataService: DataService) {
|
public constructor(
|
||||||
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
|
private dataService: DataService,
|
||||||
|
private userService: UserService
|
||||||
|
) {
|
||||||
const { statistics } = this.dataService.fetchInfo();
|
const { statistics } = this.dataService.fetchInfo();
|
||||||
|
|
||||||
this.statistics = statistics;
|
this.statistics = statistics;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ngOnInit() {}
|
public ngOnInit() {
|
||||||
|
this.userService.stateChanged
|
||||||
|
.pipe(takeUntil(this.unsubscribeSubject))
|
||||||
|
.subscribe((state) => {
|
||||||
|
if (state?.user) {
|
||||||
|
this.user = state.user;
|
||||||
|
|
||||||
|
this.changeDetectorRef.markForCheck();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public ngOnDestroy() {
|
public ngOnDestroy() {
|
||||||
this.unsubscribeSubject.next();
|
this.unsubscribeSubject.next();
|
||||||
|
@ -4,15 +4,21 @@
|
|||||||
<h3 class="d-none d-sm-block mb-3 text-center">Open Startup</h3>
|
<h3 class="d-none d-sm-block mb-3 text-center">Open Startup</h3>
|
||||||
<div class="intro-container">
|
<div class="intro-container">
|
||||||
<p>
|
<p>
|
||||||
At Ghostfolio, transparency is at the core of our values. We openly
|
At Ghostfolio, transparency is at the core of our values. We publish
|
||||||
share aggregated key metrics of our platform’s performance and publish
|
|
||||||
the source code as
|
the source code as
|
||||||
<a
|
<a
|
||||||
href="https://github.com/ghostfolio/ghostfolio"
|
href="https://github.com/ghostfolio/ghostfolio"
|
||||||
title="Contributors to Ghostfolio"
|
title="Find Ghostfolio on GitHub"
|
||||||
>open source software</a
|
>open source software</a
|
||||||
>
|
>
|
||||||
(OSS).
|
(OSS) under the
|
||||||
|
<a
|
||||||
|
href="https://www.gnu.org/licenses/agpl-3.0.html"
|
||||||
|
title="GNU Affero General Public License"
|
||||||
|
>AGPL-3.0 license</a
|
||||||
|
>
|
||||||
|
and we openly share aggregated key metrics of the platform’s
|
||||||
|
performance.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -27,6 +33,7 @@
|
|||||||
<gf-value
|
<gf-value
|
||||||
size="large"
|
size="large"
|
||||||
subLabel="(Last 24 hours)"
|
subLabel="(Last 24 hours)"
|
||||||
|
[locale]="user?.settings?.locale"
|
||||||
[value]="statistics?.activeUsers1d ?? '-'"
|
[value]="statistics?.activeUsers1d ?? '-'"
|
||||||
>Active Users</gf-value
|
>Active Users</gf-value
|
||||||
>
|
>
|
||||||
@ -35,6 +42,7 @@
|
|||||||
<gf-value
|
<gf-value
|
||||||
size="large"
|
size="large"
|
||||||
subLabel="(Last 30 days)"
|
subLabel="(Last 30 days)"
|
||||||
|
[locale]="user?.settings?.locale"
|
||||||
[value]="statistics?.newUsers30d ?? '-'"
|
[value]="statistics?.newUsers30d ?? '-'"
|
||||||
>New Users</gf-value
|
>New Users</gf-value
|
||||||
>
|
>
|
||||||
@ -43,6 +51,7 @@
|
|||||||
<gf-value
|
<gf-value
|
||||||
size="large"
|
size="large"
|
||||||
subLabel="(Last 30 days)"
|
subLabel="(Last 30 days)"
|
||||||
|
[locale]="user?.settings?.locale"
|
||||||
[value]="statistics?.activeUsers30d ?? '-'"
|
[value]="statistics?.activeUsers30d ?? '-'"
|
||||||
>Active Users</gf-value
|
>Active Users</gf-value
|
||||||
>
|
>
|
||||||
@ -51,6 +60,7 @@
|
|||||||
<a class="d-block" href="https://ghostfolio.slack.com">
|
<a class="d-block" href="https://ghostfolio.slack.com">
|
||||||
<gf-value
|
<gf-value
|
||||||
size="large"
|
size="large"
|
||||||
|
[locale]="user?.settings?.locale"
|
||||||
[value]="statistics?.slackCommunityUsers ?? '-'"
|
[value]="statistics?.slackCommunityUsers ?? '-'"
|
||||||
>Users in Slack community</gf-value
|
>Users in Slack community</gf-value
|
||||||
>
|
>
|
||||||
@ -63,6 +73,7 @@
|
|||||||
>
|
>
|
||||||
<gf-value
|
<gf-value
|
||||||
size="large"
|
size="large"
|
||||||
|
[locale]="user?.settings?.locale"
|
||||||
[value]="statistics?.gitHubContributors ?? '-'"
|
[value]="statistics?.gitHubContributors ?? '-'"
|
||||||
>Contributors on GitHub</gf-value
|
>Contributors on GitHub</gf-value
|
||||||
>
|
>
|
||||||
@ -75,6 +86,7 @@
|
|||||||
>
|
>
|
||||||
<gf-value
|
<gf-value
|
||||||
size="large"
|
size="large"
|
||||||
|
[locale]="user?.settings?.locale"
|
||||||
[value]="statistics?.gitHubStargazers ?? '-'"
|
[value]="statistics?.gitHubStargazers ?? '-'"
|
||||||
>Stars on GitHub</gf-value
|
>Stars on GitHub</gf-value
|
||||||
>
|
>
|
||||||
@ -87,6 +99,7 @@
|
|||||||
>
|
>
|
||||||
<gf-value
|
<gf-value
|
||||||
size="large"
|
size="large"
|
||||||
|
[locale]="user?.settings?.locale"
|
||||||
[value]="statistics?.dockerHubPulls ?? '-'"
|
[value]="statistics?.dockerHubPulls ?? '-'"
|
||||||
>Pulls on Docker Hub</gf-value
|
>Pulls on Docker Hub</gf-value
|
||||||
>
|
>
|
||||||
@ -97,6 +110,7 @@
|
|||||||
<gf-value
|
<gf-value
|
||||||
size="large"
|
size="large"
|
||||||
[isPercent]="true"
|
[isPercent]="true"
|
||||||
|
[locale]="user?.settings?.locale"
|
||||||
[precision]="2"
|
[precision]="2"
|
||||||
[value]="statistics?.uptime ?? '-'"
|
[value]="statistics?.uptime ?? '-'"
|
||||||
>Uptime</gf-value
|
>Uptime</gf-value
|
||||||
|
@ -37,6 +37,8 @@ import { ImportResponse } from './responses/import-response.interface';
|
|||||||
import { OAuthResponse } from './responses/oauth-response.interface';
|
import { OAuthResponse } from './responses/oauth-response.interface';
|
||||||
import { PortfolioPerformanceResponse } from './responses/portfolio-performance-response.interface';
|
import { PortfolioPerformanceResponse } from './responses/portfolio-performance-response.interface';
|
||||||
import { ScraperConfiguration } from './scraper-configuration.interface';
|
import { ScraperConfiguration } from './scraper-configuration.interface';
|
||||||
|
import { Statistics } from './statistics.interface';
|
||||||
|
import { Subscription } from './subscription.interface';
|
||||||
import { TimelinePosition } from './timeline-position.interface';
|
import { TimelinePosition } from './timeline-position.interface';
|
||||||
import { UniqueAsset } from './unique-asset.interface';
|
import { UniqueAsset } from './unique-asset.interface';
|
||||||
import { UserSettings } from './user-settings.interface';
|
import { UserSettings } from './user-settings.interface';
|
||||||
@ -80,6 +82,8 @@ export {
|
|||||||
Position,
|
Position,
|
||||||
ResponseError,
|
ResponseError,
|
||||||
ScraperConfiguration,
|
ScraperConfiguration,
|
||||||
|
Statistics,
|
||||||
|
Subscription,
|
||||||
TimelinePosition,
|
TimelinePosition,
|
||||||
UniqueAsset,
|
UniqueAsset,
|
||||||
User,
|
User,
|
||||||
|
@ -21,7 +21,7 @@ export class ValueComponent implements OnChanges {
|
|||||||
@Input() isCurrency = false;
|
@Input() isCurrency = false;
|
||||||
@Input() isDate = false;
|
@Input() isDate = false;
|
||||||
@Input() isPercent = false;
|
@Input() isPercent = false;
|
||||||
@Input() locale = getLocale();
|
@Input() locale: string | undefined;
|
||||||
@Input() position = '';
|
@Input() position = '';
|
||||||
@Input() precision: number | undefined;
|
@Input() precision: number | undefined;
|
||||||
@Input() size: 'large' | 'medium' | 'small' = 'small';
|
@Input() size: 'large' | 'medium' | 'small' = 'small';
|
||||||
@ -92,7 +92,7 @@ export class ValueComponent implements OnChanges {
|
|||||||
});
|
});
|
||||||
} catch {}
|
} catch {}
|
||||||
} else {
|
} else {
|
||||||
this.formattedValue = this.value?.toString();
|
this.formattedValue = this.value?.toLocaleString(this.locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isAbsolute) {
|
if (this.isAbsolute) {
|
||||||
@ -128,6 +128,11 @@ export class ValueComponent implements OnChanges {
|
|||||||
this.formattedValue = '';
|
this.formattedValue = '';
|
||||||
this.isNumber = false;
|
this.isNumber = false;
|
||||||
this.isString = false;
|
this.isString = false;
|
||||||
|
|
||||||
|
if (!this.locale) {
|
||||||
|
this.locale = getLocale();
|
||||||
|
}
|
||||||
|
|
||||||
this.useAbsoluteValue = false;
|
this.useAbsoluteValue = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user