Browse Source

Merge branch 'main' into spanish

pull/1312/head
casitu 3 years ago
committed by GitHub
parent
commit
dfb21692d1
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      CHANGELOG.md
  2. 24
      apps/api/src/app/info/info.service.ts
  3. 21
      apps/client/src/app/components/admin-overview/admin-overview.html
  4. 16
      apps/client/src/app/pages/landing/landing-page.component.ts
  5. 53
      apps/client/src/app/pages/landing/landing-page.html
  6. 2
      apps/client/src/app/pages/landing/landing-page.module.ts
  7. 6
      apps/client/src/app/pages/portfolio/allocations/allocations-page.html
  8. 8
      apps/client/src/locales/messages.es.xlf
  9. 5
      apps/client/src/styles.scss
  10. 1
      libs/common/src/lib/interfaces/statistics.interface.ts
  11. 8
      libs/ui/src/lib/value/value.component.html
  12. 2
      libs/ui/src/lib/value/value.component.scss
  13. 1
      libs/ui/src/lib/value/value.component.ts
  14. 4
      libs/ui/src/lib/value/value.module.ts
  15. 6
      package.json
  16. 36
      yarn.lock

16
CHANGELOG.md

@ -7,9 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased ## Unreleased
### Changed
- Improved the usage of the value component in the admin control panel
### Fixed
- Fixed the usage of the value component on the allocations page
## 1.200.0 - 01.10.2022
### Added ### Added
- Added a mini statistics section to the landing page including pulls on _Docker Hub_
- Added an _As seen in_ section to the landing page - Added an _As seen in_ section to the landing page
- Added support for an icon in the value component
### Changed
- Upgraded `prisma` from version `4.1.1` to `4.4.0`
## 1.199.1 - 27.09.2022 ## 1.199.1 - 27.09.2022

24
apps/api/src/app/info/info.service.ts

@ -145,6 +145,27 @@ export class InfoService {
}); });
} }
private async countDockerHubPulls(): Promise<number> {
try {
const get = bent(
`https://hub.docker.com/v2/repositories/ghostfolio/ghostfolio`,
'GET',
'json',
200,
{
'User-Agent': 'request'
}
);
const { pull_count } = await get();
return pull_count;
} catch (error) {
Logger.error(error, 'InfoService');
return undefined;
}
}
private async countGitHubContributors(): Promise<number> { private async countGitHubContributors(): Promise<number> {
try { try {
const get = bent( const get = bent(
@ -245,6 +266,8 @@ export class InfoService {
const activeUsers1d = await this.countActiveUsers(1); const activeUsers1d = await this.countActiveUsers(1);
const activeUsers30d = await this.countActiveUsers(30); const activeUsers30d = await this.countActiveUsers(30);
const newUsers30d = await this.countNewUsers(30); const newUsers30d = await this.countNewUsers(30);
const dockerHubPulls = await this.countDockerHubPulls();
const gitHubContributors = await this.countGitHubContributors(); const gitHubContributors = await this.countGitHubContributors();
const gitHubStargazers = await this.countGitHubStargazers(); const gitHubStargazers = await this.countGitHubStargazers();
const slackCommunityUsers = await this.countSlackCommunityUsers(); const slackCommunityUsers = await this.countSlackCommunityUsers();
@ -252,6 +275,7 @@ export class InfoService {
statistics = { statistics = {
activeUsers1d, activeUsers1d,
activeUsers30d, activeUsers30d,
dockerHubPulls,
gitHubContributors, gitHubContributors,
gitHubStargazers, gitHubStargazers,
newUsers30d, newUsers30d,

21
apps/client/src/app/components/admin-overview/admin-overview.html

@ -5,15 +5,26 @@
<mat-card-content> <mat-card-content>
<div class="d-flex my-3"> <div class="d-flex my-3">
<div class="w-50" i18n>User Count</div> <div class="w-50" i18n>User Count</div>
<div class="w-50">{{ userCount }}</div> <div class="w-50">
<gf-value
precision="0"
[locale]="user?.settings?.locale"
[value]="userCount"
></gf-value>
</div>
</div> </div>
<div class="d-flex my-3"> <div class="d-flex my-3">
<div class="w-50" i18n>Activity Count</div> <div class="w-50" i18n>Activity Count</div>
<div class="w-50"> <div class="w-50">
<ng-container *ngIf="transactionCount"> <gf-value
{{ transactionCount }} ({{ transactionCount / userCount | number precision="0"
: '1.2-2' }} <span i18n>per User</span>) [locale]="user?.settings?.locale"
</ng-container> [value]="transactionCount"
></gf-value>
<div *ngIf="transactionCount && userCount">
{{ transactionCount / userCount | number : '1.2-2' }}
<span i18n>per User</span>
</div>
</div> </div>
</div> </div>
<div class="d-flex my-3"> <div class="d-flex my-3">

16
apps/client/src/app/pages/landing/landing-page.component.ts

@ -1,4 +1,7 @@
import { Component, OnDestroy, OnInit } from '@angular/core'; import { Component, OnDestroy, OnInit } from '@angular/core';
import { DataService } from '@ghostfolio/client/services/data.service';
import { Statistics } from '@ghostfolio/common/interfaces/statistics.interface';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { format } from 'date-fns'; import { format } from 'date-fns';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
@ -11,6 +14,8 @@ import { Subject } from 'rxjs';
export class LandingPageComponent implements OnDestroy, OnInit { export class LandingPageComponent implements OnDestroy, OnInit {
public currentYear = format(new Date(), 'yyyy'); public currentYear = format(new Date(), 'yyyy');
public demoAuthToken: string; public demoAuthToken: string;
public hasPermissionForStatistics: boolean;
public statistics: Statistics;
public testimonials = [ public testimonials = [
{ {
author: 'Philipp', author: 'Philipp',
@ -36,7 +41,16 @@ export class LandingPageComponent implements OnDestroy, OnInit {
private unsubscribeSubject = new Subject<void>(); private unsubscribeSubject = new Subject<void>();
public constructor() {} public constructor(private dataService: DataService) {
const { globalPermissions, statistics } = this.dataService.fetchInfo();
this.hasPermissionForStatistics = hasPermission(
globalPermissions,
permissions.enableStatistics
);
this.statistics = statistics;
}
public ngOnInit() {} public ngOnInit() {}

53
apps/client/src/app/pages/landing/landing-page.html

@ -42,7 +42,52 @@
</div> </div>
</div> </div>
<div class="row my-3"> <div *ngIf="hasPermissionForStatistics" class="row mb-5">
<div class="col-md-4 d-flex my-1">
<a
class="d-block"
title="Ghostfolio in Numbers: Monthly Active Users (MAU)"
[routerLink]="['/about']"
>
<gf-value
icon="people-outline"
size="large"
[value]="statistics?.activeUsers30d ?? '-'"
>Monthly Active Users</gf-value
>
</a>
</div>
<div class="col-md-4 d-flex my-1">
<a
class="d-block"
title="Ghostfolio in Numbers: Stars on GitHub"
[routerLink]="['/about']"
>
<gf-value
icon="star-outline"
size="large"
[value]="statistics?.gitHubStargazers ?? '-'"
>Stars on GitHub</gf-value
>
</a>
</div>
<div class="col-md-4 d-flex my-1">
<a
class="d-block"
title="Ghostfolio in Numbers: Pulls on Docker Hub"
[routerLink]="['/about']"
>
<gf-value
icon="cloud-download-outline"
size="large"
[value]="statistics?.dockerHubPulls ?? '-'"
>Pulls on Docker Hub</gf-value
>
</a>
</div>
</div>
<div class="row mb-5">
<div class="col-12 text-center text-muted"><small>As seen in</small></div> <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-2 d-flex justify-content-center my-1">
<a <a
@ -110,20 +155,20 @@
<div class="row my-3"> <div class="row my-3">
<div class="col-md-4 my-2"> <div class="col-md-4 my-2">
<mat-card> <mat-card>
<mat-card-title class="text-center">360° View</mat-card-title> <mat-card-title>360° View</mat-card-title>
Get the full picture of your personal finances across multiple Get the full picture of your personal finances across multiple
platforms. platforms.
</mat-card> </mat-card>
</div> </div>
<div class="col-md-4 my-2"> <div class="col-md-4 my-2">
<mat-card> <mat-card>
<mat-card-title class="text-center">Web3 Ready</mat-card-title> <mat-card-title>Web3 Ready</mat-card-title>
Use Ghostfolio anonymously and own your financial data. Use Ghostfolio anonymously and own your financial data.
</mat-card> </mat-card>
</div> </div>
<div class="col-md-4 my-2"> <div class="col-md-4 my-2">
<mat-card> <mat-card>
<mat-card-title class="text-center">Open Source</mat-card-title> <mat-card-title>Open Source</mat-card-title>
Benefit from continuous improvements through a strong community. Benefit from continuous improvements through a strong community.
</mat-card> </mat-card>
</div> </div>

2
apps/client/src/app/pages/landing/landing-page.module.ts

@ -4,6 +4,7 @@ import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card'; import { MatCardModule } from '@angular/material/card';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { GfLogoModule } from '@ghostfolio/ui/logo'; import { GfLogoModule } from '@ghostfolio/ui/logo';
import { GfValueModule } from '@ghostfolio/ui/value';
import { LandingPageRoutingModule } from './landing-page-routing.module'; import { LandingPageRoutingModule } from './landing-page-routing.module';
import { LandingPageComponent } from './landing-page.component'; import { LandingPageComponent } from './landing-page.component';
@ -13,6 +14,7 @@ import { LandingPageComponent } from './landing-page.component';
imports: [ imports: [
CommonModule, CommonModule,
GfLogoModule, GfLogoModule,
GfValueModule,
LandingPageRoutingModule, LandingPageRoutingModule,
MatButtonModule, MatButtonModule,
MatCardModule, MatCardModule,

6
apps/client/src/app/pages/portfolio/allocations/allocations-page.html

@ -13,12 +13,12 @@
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<mat-card class="mb-3"> <mat-card class="mb-3">
<mat-card-header class="overflow-hidden w-100"> <mat-card-header class="mb-2 overflow-hidden w-100">
<mat-card-title class="text-truncate" i18n <mat-card-title class="m-0 text-truncate" i18n
>Proportion of Net Worth</mat-card-title >Proportion of Net Worth</mat-card-title
> >
<gf-value <gf-value
class="align-items-end flex-grow-1 ml-2" class="flex-grow-1 justify-content-end l-2"
size="medium" size="medium"
[isPercent]="true" [isPercent]="true"
[value]="isLoading ? undefined : portfolioDetails?.filteredValueInPercentage" [value]="isLoading ? undefined : portfolioDetails?.filteredValueInPercentage"

8
apps/client/src/locales/messages.es.xlf

@ -2660,11 +2660,7 @@
</trans-unit> </trans-unit>
<trans-unit id="ac598d664f86ba5783915d65f2664a7f38a9d23a" datatype="html"> <trans-unit id="ac598d664f86ba5783915d65f2664a7f38a9d23a" datatype="html">
<source>Account Type</source> <source>Account Type</source>
<<<<<<< HEAD
<target state="translated">Tipo de cuenta</target> <target state="translated">Tipo de cuenta</target>
=======
<target state="new">Account Type</target>
>>>>>>> parent of 5e338d43 (Update messages.es.xlf)
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html</context> <context context-type="sourcefile">apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html</context>
<context context-type="linenumber">25</context> <context context-type="linenumber">25</context>
@ -2672,11 +2668,7 @@
</trans-unit> </trans-unit>
<trans-unit id="98fc3013bfcbf452b9f37bbfcdb77b9b882866e3" datatype="html"> <trans-unit id="98fc3013bfcbf452b9f37bbfcdb77b9b882866e3" datatype="html">
<source>Excluded from Analysis</source> <source>Excluded from Analysis</source>
<<<<<<< HEAD
<target state="translated">Excluido del análisis</target> <target state="translated">Excluido del análisis</target>
=======
<target state="new">Excluded from Analysis</target>
>>>>>>> parent of 5e338d43 (Update messages.es.xlf)
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html</context> <context context-type="sourcefile">apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html</context>
<context context-type="linenumber">176</context> <context context-type="linenumber">176</context>

5
apps/client/src/styles.scss

@ -18,6 +18,7 @@ $mat-css-light-theme-selector: '.is-light-theme';
:root { :root {
--dark-background: rgb(39, 39, 39); --dark-background: rgb(39, 39, 39);
--font-family-sans-serif: Roboto, 'Helvetica Neue', sans-serif;
--light-background: rgb(255, 255, 255); --light-background: rgb(255, 255, 255);
} }
@ -146,6 +147,10 @@ ngx-skeleton-loader {
@include gf-table; @include gf-table;
} }
.lead {
font-weight: unset;
}
.mat-card { .mat-card {
&:not([class*='mat-elevation-z']) { &:not([class*='mat-elevation-z']) {
border: 1px solid rgba(var(--dark-dividers)); border: 1px solid rgba(var(--dark-dividers));

1
libs/common/src/lib/interfaces/statistics.interface.ts

@ -1,6 +1,7 @@
export interface Statistics { export interface Statistics {
activeUsers1d: number; activeUsers1d: number;
activeUsers30d: number; activeUsers30d: number;
dockerHubPulls: number;
gitHubContributors: number; gitHubContributors: number;
gitHubStargazers: number; gitHubStargazers: number;
newUsers30d: number; newUsers30d: number;

8
libs/ui/src/lib/value/value.component.html

@ -1,3 +1,7 @@
<div *ngIf="icon" class="align-self-center mr-3">
<ion-icon class="h3 m-0" [name]="icon"></ion-icon>
</div>
<div>
<ng-template #label><ng-content></ng-content></ng-template> <ng-template #label><ng-content></ng-content></ng-template>
<ng-container *ngIf="value || value === 0 || value === null"> <ng-container *ngIf="value || value === 0 || value === null">
<div <div
@ -61,7 +65,9 @@
*ngIf="value === undefined" *ngIf="value === undefined"
animation="pulse" animation="pulse"
[theme]="{ [theme]="{
height: size === 'large' ? '2.5rem' : size === 'medium' ? '2rem' : '1.5rem', height:
size === 'large' ? '2.5rem' : size === 'medium' ? '2rem' : '1.5rem',
width: '5rem' width: '5rem'
}" }"
></ngx-skeleton-loader> ></ngx-skeleton-loader>
</div>

2
libs/ui/src/lib/value/value.component.scss

@ -1,6 +1,6 @@
:host { :host {
display: flex; display: flex;
flex-direction: column; flex-direction: row;
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;
.h2 { .h2 {

1
libs/ui/src/lib/value/value.component.ts

@ -16,6 +16,7 @@ import { isNumber } from 'lodash';
export class ValueComponent implements OnChanges { export class ValueComponent implements OnChanges {
@Input() colorizeSign = false; @Input() colorizeSign = false;
@Input() currency = ''; @Input() currency = '';
@Input() icon = '';
@Input() isAbsolute = false; @Input() isAbsolute = false;
@Input() isCurrency = false; @Input() isCurrency = false;
@Input() isDate = false; @Input() isDate = false;

4
libs/ui/src/lib/value/value.module.ts

@ -1,5 +1,5 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { ValueComponent } from './value.component'; import { ValueComponent } from './value.component';
@ -8,6 +8,6 @@ import { ValueComponent } from './value.component';
declarations: [ValueComponent], declarations: [ValueComponent],
exports: [ValueComponent], exports: [ValueComponent],
imports: [CommonModule, NgxSkeletonLoaderModule], imports: [CommonModule, NgxSkeletonLoaderModule],
providers: [] schemas: [CUSTOM_ELEMENTS_SCHEMA]
}) })
export class GfValueModule {} export class GfValueModule {}

6
package.json

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

36
yarn.lock

@ -3839,22 +3839,22 @@
schema-utils "^3.0.0" schema-utils "^3.0.0"
source-map "^0.7.3" source-map "^0.7.3"
"@prisma/client@4.1.1": "@prisma/client@4.4.0":
version "4.1.1" version "4.4.0"
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-4.1.1.tgz#dcb1118397deb8247fbe39a1f3eee5606648adf8" resolved "https://registry.yarnpkg.com/@prisma/client/-/client-4.4.0.tgz#45f59c172dd3621ecc92d7cf9bc765d85e6c7d56"
integrity sha512-2pXuIUYxHv5H9o6QTa1VIsl4yMgsAjKQOitlo8WVTB+vo73rmMJITBPavdGUZSWUc7adMkFzEV3y5rVTUQr77Q== integrity sha512-ciKOP246x1xwr04G9ajHlJ4pkmtu9Q6esVyqVBO0QJihaKQIUvbPjClp17IsRJyxqNpFm4ScbOc/s9DUzKHINQ==
dependencies: dependencies:
"@prisma/engines-version" "4.1.0-48.8d8414deb360336e4698a65aa45a1fbaf1ce13d8" "@prisma/engines-version" "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6"
"@prisma/engines-version@4.1.0-48.8d8414deb360336e4698a65aa45a1fbaf1ce13d8": "@prisma/engines-version@4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6":
version "4.1.0-48.8d8414deb360336e4698a65aa45a1fbaf1ce13d8" version "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6"
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-4.1.0-48.8d8414deb360336e4698a65aa45a1fbaf1ce13d8.tgz#ce00e6377126e491a8b1e0e2039c97e2924bd6d9" resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6.tgz#00875863bb30b670a586a5b5794a000f7f3ad976"
integrity sha512-cRRJwpHFGFJZvtHbY3GZjMffNBEjjZk68ztn+S2hDgPCGB4H66IK26roK94GJxBodSehwRJ0wGyebC2GoIH1JQ== integrity sha512-P5v/PuEIJLYXZUZBvOLPqoyCW+m6StNqHdiR6te++gYVODpPdLakks5HVx3JaZIY+LwR02juJWFlwpc9Eog/ug==
"@prisma/engines@4.1.1": "@prisma/engines@4.4.0":
version "4.1.1" version "4.4.0"
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-4.1.1.tgz#a6a75870618bbd19ff734c51af7dbe9f362c3265" resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-4.4.0.tgz#6ca7d3ce8eee08dcfa82311b0a02f5ccaac7dc0c"
integrity sha512-DCw8L/SS0IXqmj5IW/fMxOXiifnsfjBzDfRhf0j3NFWqvMCh9OtfjmXQZxVgI2mwvJLc/5jzXhkiWT39qS09dA== integrity sha512-Fpykccxlt9MHrAs/QpPGpI2nOiRxuLA+LiApgA59ibbf24YICZIMWd3SI2YD+q0IAIso0jCGiHhirAIbxK3RyQ==
"@rollup/plugin-babel@^5.3.0": "@rollup/plugin-babel@^5.3.0":
version "5.3.1" version "5.3.1"
@ -16763,12 +16763,12 @@ pretty-hrtime@^1.0.3:
resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
integrity sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A== integrity sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==
prisma@4.1.1: prisma@4.4.0:
version "4.1.1" version "4.4.0"
resolved "https://registry.yarnpkg.com/prisma/-/prisma-4.1.1.tgz#41c2e19896357f484ef21567165d762908376fca" resolved "https://registry.yarnpkg.com/prisma/-/prisma-4.4.0.tgz#0c53324bf6a29474636b3e1964e0d72e0277bf8f"
integrity sha512-yw50J8If2dKP4wYIi695zthsCASQFHiogGvUHHWd3falx/rpsD6Sb1LMLRV9nO3iGG3lozxNJ2PSINxK7xwdpg== integrity sha512-l/QKLmLcKJQFuc+X02LyICo0NWTUVaNNZ00jKJBqwDyhwMAhboD1FWwYV50rkH4Wls0RviAJSFzkC2ZrfawpfA==
dependencies: dependencies:
"@prisma/engines" "4.1.1" "@prisma/engines" "4.4.0"
prismjs@^1.27.0, prismjs@^1.28.0: prismjs@^1.27.0, prismjs@^1.28.0:
version "1.28.0" version "1.28.0"

Loading…
Cancel
Save