Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
f332aea9b4 | |||
7a9fd18407 | |||
ca08d3154a | |||
01d4ae8757 | |||
43ce2786c1 | |||
de2092c4d2 | |||
435a180e54 | |||
0ad30ffabe | |||
0cc5e558f1 | |||
63b183cc6f | |||
10bae24c5c | |||
0e29278e96 | |||
2db46e5bbf | |||
e757e90e5a | |||
184ddc6209 | |||
e3662a143c | |||
25afd7e07b | |||
7fceaa1350 |
36
.github/workflows/build-code.yml
vendored
Normal file
36
.github/workflows/build-code.yml
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
name: Build code
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node_version:
|
||||
- 16
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Use Node.js ${{ matrix.node_version }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node_version }}
|
||||
cache: 'yarn'
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Check formatting
|
||||
run: yarn format:check
|
||||
|
||||
- name: Execute tests
|
||||
run: yarn test
|
||||
|
||||
- name: Build application
|
||||
run: yarn build:all
|
49
.github/workflows/docker-image.yml
vendored
Normal file
49
.github/workflows/docker-image.yml
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
name: Docker image CD
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*.*.*'
|
||||
pull_request:
|
||||
branches:
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
build_and_push:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: ghostfolio/ghostfolio
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Login to DockerHub
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.output.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
30
.travis.yml
30
.travis.yml
@ -1,30 +0,0 @@
|
||||
language: node_js
|
||||
git:
|
||||
depth: false
|
||||
node_js:
|
||||
- 16
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
cache: yarn
|
||||
|
||||
if: (type = pull_request) OR (tag IS present)
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: Install dependencies
|
||||
if: type = pull_request
|
||||
script: yarn --frozen-lockfile
|
||||
- stage: Check formatting
|
||||
if: type = pull_request
|
||||
script: yarn format:check
|
||||
- stage: Execute tests
|
||||
if: type = pull_request
|
||||
script: yarn test
|
||||
- stage: Build application
|
||||
if: type = pull_request
|
||||
script: yarn build:all
|
||||
- stage: Build and publish docker image
|
||||
if: tag IS present
|
||||
script: ./publish-docker-image.sh
|
31
CHANGELOG.md
31
CHANGELOG.md
@ -5,6 +5,37 @@ 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.185.0 - 30.08.2022
|
||||
|
||||
### Added
|
||||
|
||||
- Added a skeleton loader to the market mood component in the markets overview
|
||||
|
||||
### Changed
|
||||
|
||||
- Moved the build pipeline from _Travis_ to _GitHub Actions_
|
||||
- Increased the caching of the benchmarks
|
||||
|
||||
### Fixed
|
||||
|
||||
- Disabled the language selector for the demo user
|
||||
|
||||
## 1.184.2 - 28.08.2022
|
||||
|
||||
### Added
|
||||
|
||||
- Added the alias to the `Access` database schema
|
||||
- Added support for translated time distances
|
||||
- Added a _GitHub Action_ to create an `arm64` docker image
|
||||
|
||||
### Changed
|
||||
|
||||
- Improved the language localization for German (`de`)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed the missing assets during the local development
|
||||
|
||||
## 1.183.0 - 24.08.2022
|
||||
|
||||
### Added
|
||||
|
18
Dockerfile
18
Dockerfile
@ -1,7 +1,6 @@
|
||||
FROM node:16-alpine as builder
|
||||
FROM --platform=$BUILDPLATFORM node:16-slim as builder
|
||||
|
||||
# Build application and add additional files
|
||||
|
||||
WORKDIR /ghostfolio
|
||||
|
||||
# Only add basic files without the application itself to avoid rebuilding
|
||||
@ -10,9 +9,16 @@ COPY ./CHANGELOG.md CHANGELOG.md
|
||||
COPY ./LICENSE LICENSE
|
||||
COPY ./package.json package.json
|
||||
COPY ./yarn.lock yarn.lock
|
||||
COPY ./.yarnrc .yarnrc
|
||||
COPY ./prisma/schema.prisma prisma/schema.prisma
|
||||
|
||||
RUN apk add --no-cache python3 g++ make openssl git
|
||||
RUN apt update && apt install -y \
|
||||
git \
|
||||
g++ \
|
||||
make \
|
||||
openssl \
|
||||
python3 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
RUN yarn install
|
||||
|
||||
# See https://github.com/nrwl/nx/issues/6586 for further details
|
||||
@ -45,7 +51,11 @@ COPY package.json /ghostfolio/dist/apps/api
|
||||
RUN yarn database:generate-typings
|
||||
|
||||
# Image to run, copy everything needed from builder
|
||||
FROM node:16-alpine
|
||||
FROM node:16-slim
|
||||
RUN apt update && apt install -y \
|
||||
openssl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=builder /ghostfolio/dist/apps /ghostfolio/apps
|
||||
WORKDIR /ghostfolio/apps/api
|
||||
EXPOSE 3333
|
||||
|
@ -12,13 +12,11 @@
|
||||
<strong>Open Source Wealth Management Software</strong>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://ghostfol.io"><strong>Ghostfol.io</strong></a> | <a href="https://ghostfol.io/demo"><strong>Live Demo</strong></a> | <a href="https://ghostfol.io/pricing"><strong>Ghostfolio Premium</strong></a> | <a href="https://ghostfol.io/faq"><strong>FAQ</strong></a> | <a href="https://ghostfol.io/blog"><strong>Blog</strong></a> | <a href="https://join.slack.com/t/ghostfolio/shared_invite/zt-vsaan64h-F_I0fEo5M0P88lP9ibCxFg"><strong>Slack</strong></a> | <a href="https://twitter.com/ghostfolio_"><strong>Twitter</strong></a>
|
||||
<a href="https://ghostfol.io"><strong>Ghostfol.io</strong></a> | <a href="https://ghostfol.io/en/demo"><strong>Live Demo</strong></a> | <a href="https://ghostfol.io/en/pricing"><strong>Ghostfolio Premium</strong></a> | <a href="https://ghostfol.io/en/faq"><strong>FAQ</strong></a> | <a href="https://ghostfol.io/en/blog"><strong>Blog</strong></a> | <a href="https://join.slack.com/t/ghostfolio/shared_invite/zt-vsaan64h-F_I0fEo5M0P88lP9ibCxFg"><strong>Slack</strong></a> | <a href="https://twitter.com/ghostfolio_"><strong>Twitter</strong></a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="#contributing">
|
||||
<img src="https://img.shields.io/badge/contributions-welcome-orange.svg"/></a>
|
||||
<a href="https://travis-ci.com/github/ghostfolio/ghostfolio" rel="nofollow">
|
||||
<img src="https://travis-ci.com/ghostfolio/ghostfolio.svg?branch=main" alt="Build Status"/></a>
|
||||
<a href="https://www.gnu.org/licenses/agpl-3.0" rel="nofollow">
|
||||
<img src="https://img.shields.io/badge/License-AGPL%20v3-blue.svg" alt="License: AGPL v3"/></a>
|
||||
</p>
|
||||
@ -33,7 +31,7 @@
|
||||
|
||||
## Ghostfolio Premium
|
||||
|
||||
Our official **[Ghostfolio Premium](https://ghostfol.io/pricing)** cloud offering is the easiest way to get started. Due to the time it saves, this will be the best option for most people. The revenue is used for covering the hosting costs.
|
||||
Our official **[Ghostfolio Premium](https://ghostfol.io/en/pricing)** cloud offering is the easiest way to get started. Due to the time it saves, this will be the best option for most people. The revenue is used for covering the hosting costs.
|
||||
|
||||
If you prefer to run Ghostfolio on your own infrastructure, please find further instructions in the [Self-hosting](#self-hosting) section.
|
||||
|
||||
@ -259,7 +257,7 @@ Ghostfolio is **100% free** and **open source**. We encourage and support an act
|
||||
|
||||
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.
|
||||
|
||||
If you like to support this project, get **[Ghostfolio Premium](https://ghostfol.io/pricing)** or **[Buy me a coffee](https://www.buymeacoffee.com/ghostfolio)**.
|
||||
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)**.
|
||||
|
||||
## License
|
||||
|
||||
|
@ -42,14 +42,16 @@ export class AccessController {
|
||||
return accessesWithGranteeUser.map((access) => {
|
||||
if (access.GranteeUser) {
|
||||
return {
|
||||
granteeAlias: access.GranteeUser?.alias,
|
||||
alias: access.alias,
|
||||
grantee: access.GranteeUser?.id,
|
||||
id: access.id,
|
||||
type: 'RESTRICTED_VIEW'
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
granteeAlias: 'Public',
|
||||
alias: access.alias,
|
||||
grantee: 'Public',
|
||||
id: access.id,
|
||||
type: 'PUBLIC'
|
||||
};
|
||||
@ -71,6 +73,10 @@ export class AccessController {
|
||||
}
|
||||
|
||||
return this.accessService.createAccess({
|
||||
alias: data.alias || undefined,
|
||||
GranteeUser: data.granteeUserId
|
||||
? { connect: { id: data.granteeUserId } }
|
||||
: undefined,
|
||||
User: { connect: { id: this.request.user.id } }
|
||||
});
|
||||
}
|
||||
|
@ -1 +1,11 @@
|
||||
export class CreateAccessDto {}
|
||||
import { IsOptional, IsString } from 'class-validator';
|
||||
|
||||
export class CreateAccessDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
alias?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
granteeUserId?: string;
|
||||
}
|
||||
|
@ -1,30 +1,20 @@
|
||||
import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request.interceptor';
|
||||
import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response.interceptor';
|
||||
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
|
||||
import { PROPERTY_BENCHMARKS } from '@ghostfolio/common/config';
|
||||
import { BenchmarkResponse, UniqueAsset } from '@ghostfolio/common/interfaces';
|
||||
import { BenchmarkResponse } from '@ghostfolio/common/interfaces';
|
||||
import { Controller, Get, UseInterceptors } from '@nestjs/common';
|
||||
|
||||
import { BenchmarkService } from './benchmark.service';
|
||||
|
||||
@Controller('benchmark')
|
||||
export class BenchmarkController {
|
||||
public constructor(
|
||||
private readonly benchmarkService: BenchmarkService,
|
||||
private readonly propertyService: PropertyService
|
||||
) {}
|
||||
public constructor(private readonly benchmarkService: BenchmarkService) {}
|
||||
|
||||
@Get()
|
||||
@UseInterceptors(TransformDataSourceInRequestInterceptor)
|
||||
@UseInterceptors(TransformDataSourceInResponseInterceptor)
|
||||
public async getBenchmark(): Promise<BenchmarkResponse> {
|
||||
const benchmarkAssets: UniqueAsset[] =
|
||||
((await this.propertyService.getByKey(
|
||||
PROPERTY_BENCHMARKS
|
||||
)) as UniqueAsset[]) ?? [];
|
||||
|
||||
return {
|
||||
benchmarks: await this.benchmarkService.getBenchmarks(benchmarkAssets)
|
||||
benchmarks: await this.benchmarkService.getBenchmarks()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
|
||||
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service';
|
||||
import { MarketDataService } from '@ghostfolio/api/services/market-data.service';
|
||||
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
|
||||
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile.service';
|
||||
import { PROPERTY_BENCHMARKS } from '@ghostfolio/common/config';
|
||||
import { BenchmarkResponse, UniqueAsset } from '@ghostfolio/common/interfaces';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import Big from 'big.js';
|
||||
import ms from 'ms';
|
||||
|
||||
@Injectable()
|
||||
export class BenchmarkService {
|
||||
@ -13,15 +16,17 @@ export class BenchmarkService {
|
||||
public constructor(
|
||||
private readonly dataProviderService: DataProviderService,
|
||||
private readonly marketDataService: MarketDataService,
|
||||
private readonly propertyService: PropertyService,
|
||||
private readonly redisCacheService: RedisCacheService,
|
||||
private readonly symbolProfileService: SymbolProfileService
|
||||
) {}
|
||||
|
||||
public async getBenchmarks(
|
||||
benchmarkAssets: UniqueAsset[]
|
||||
): Promise<BenchmarkResponse['benchmarks']> {
|
||||
public async getBenchmarks({ useCache = true } = {}): Promise<
|
||||
BenchmarkResponse['benchmarks']
|
||||
> {
|
||||
let benchmarks: BenchmarkResponse['benchmarks'];
|
||||
|
||||
if (useCache) {
|
||||
try {
|
||||
benchmarks = JSON.parse(
|
||||
await this.redisCacheService.get(this.CACHE_KEY_BENCHMARKS)
|
||||
@ -31,7 +36,12 @@ export class BenchmarkService {
|
||||
return benchmarks;
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
const benchmarkAssets: UniqueAsset[] =
|
||||
((await this.propertyService.getByKey(
|
||||
PROPERTY_BENCHMARKS
|
||||
)) as UniqueAsset[]) ?? [];
|
||||
const promises: Promise<number>[] = [];
|
||||
|
||||
const [quotes, assetProfiles] = await Promise.all([
|
||||
@ -76,7 +86,8 @@ export class BenchmarkService {
|
||||
|
||||
await this.redisCacheService.set(
|
||||
this.CACHE_KEY_BENCHMARKS,
|
||||
JSON.stringify(benchmarks)
|
||||
JSON.stringify(benchmarks),
|
||||
ms('4 hours') / 1000
|
||||
);
|
||||
|
||||
return benchmarks;
|
||||
|
@ -349,6 +349,7 @@ export class PortfolioController {
|
||||
|
||||
const portfolioPublicDetails: PortfolioPublicDetails = {
|
||||
hasDetails,
|
||||
alias: access.alias,
|
||||
holdings: {}
|
||||
};
|
||||
|
||||
|
@ -62,7 +62,7 @@ export class UserService {
|
||||
tags,
|
||||
access: access.map((accessItem) => {
|
||||
return {
|
||||
alias: accessItem.User.alias,
|
||||
alias: accessItem.alias,
|
||||
id: accessItem.id
|
||||
};
|
||||
}),
|
||||
|
@ -7,7 +7,7 @@ import { Module } from '@nestjs/common';
|
||||
|
||||
@Module({
|
||||
exports: [TwitterBotService],
|
||||
imports: [BenchmarkModule, ConfigurationModule, PropertyModule, SymbolModule],
|
||||
imports: [BenchmarkModule, ConfigurationModule, SymbolModule],
|
||||
providers: [TwitterBotService]
|
||||
})
|
||||
export class TwitterBotModule {}
|
||||
|
@ -1,9 +1,7 @@
|
||||
import { BenchmarkService } from '@ghostfolio/api/app/benchmark/benchmark.service';
|
||||
import { SymbolService } from '@ghostfolio/api/app/symbol/symbol.service';
|
||||
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
|
||||
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
|
||||
import {
|
||||
PROPERTY_BENCHMARKS,
|
||||
ghostfolioFearAndGreedIndexDataSource,
|
||||
ghostfolioFearAndGreedIndexSymbol
|
||||
} from '@ghostfolio/common/config';
|
||||
@ -11,7 +9,6 @@ import {
|
||||
resolveFearAndGreedIndex,
|
||||
resolveMarketCondition
|
||||
} from '@ghostfolio/common/helper';
|
||||
import { UniqueAsset } from '@ghostfolio/common/interfaces';
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { isWeekend } from 'date-fns';
|
||||
import { TwitterApi, TwitterApiReadWrite } from 'twitter-api-v2';
|
||||
@ -23,7 +20,6 @@ export class TwitterBotService {
|
||||
public constructor(
|
||||
private readonly benchmarkService: BenchmarkService,
|
||||
private readonly configurationService: ConfigurationService,
|
||||
private readonly propertyService: PropertyService,
|
||||
private readonly symbolService: SymbolService
|
||||
) {
|
||||
this.twitterClient = new TwitterApi({
|
||||
@ -82,14 +78,9 @@ export class TwitterBotService {
|
||||
}
|
||||
|
||||
private async getBenchmarkListing(aMax: number) {
|
||||
const benchmarkAssets: UniqueAsset[] =
|
||||
((await this.propertyService.getByKey(
|
||||
PROPERTY_BENCHMARKS
|
||||
)) as UniqueAsset[]) ?? [];
|
||||
|
||||
const benchmarks = await this.benchmarkService.getBenchmarks(
|
||||
benchmarkAssets
|
||||
);
|
||||
const benchmarks = await this.benchmarkService.getBenchmarks({
|
||||
useCache: false
|
||||
});
|
||||
|
||||
const benchmarkListing: string[] = [];
|
||||
|
||||
|
@ -2,5 +2,13 @@
|
||||
"/api": {
|
||||
"target": "http://localhost:3333",
|
||||
"secure": false
|
||||
},
|
||||
"/assets": {
|
||||
"target": "http://localhost:3333",
|
||||
"secure": false
|
||||
},
|
||||
"/ionicons": {
|
||||
"target": "http://localhost:3333",
|
||||
"secure": false
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,15 @@
|
||||
<table class="gf-table w-100" mat-table [dataSource]="dataSource">
|
||||
<ng-container matColumnDef="granteeAlias">
|
||||
<ng-container matColumnDef="alias">
|
||||
<th *matHeaderCellDef class="px-1" i18n mat-header-cell>Alias</th>
|
||||
<td *matCellDef="let element" class="px-1" mat-cell>
|
||||
{{ element.alias }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="grantee">
|
||||
<th *matHeaderCellDef class="px-1" i18n mat-header-cell>Grantee</th>
|
||||
<td *matCellDef="let element" class="px-1" mat-cell>
|
||||
{{ element.granteeAlias }}
|
||||
{{ element.grantee }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
|
@ -33,7 +33,7 @@ export class AccessTableComponent implements OnChanges, OnInit {
|
||||
public ngOnInit() {}
|
||||
|
||||
public ngOnChanges() {
|
||||
this.displayedColumns = ['granteeAlias', 'type', 'details'];
|
||||
this.displayedColumns = ['alias', 'grantee', 'type', 'details'];
|
||||
|
||||
if (this.showActions) {
|
||||
this.displayedColumns.push('actions');
|
||||
|
@ -1,4 +1,5 @@
|
||||
<div class="align-items-center d-flex flex-row">
|
||||
<div class="position-relative">
|
||||
<div class="align-items-center d-flex flex-row" [hidden]="!fearAndGreedIndex">
|
||||
<div class="h2 mb-0 mr-2">{{ fearAndGreedIndexEmoji }}</div>
|
||||
<div>
|
||||
<div class="h4 mb-0">
|
||||
@ -11,3 +12,12 @@
|
||||
<small class="d-block" i18n>Current Market Mood</small>
|
||||
</div>
|
||||
</div>
|
||||
<ngx-skeleton-loader
|
||||
*ngIf="!fearAndGreedIndex"
|
||||
animation="pulse"
|
||||
class="position-absolute w-100"
|
||||
[theme]="{
|
||||
height: '100%'
|
||||
}"
|
||||
></ngx-skeleton-loader>
|
||||
</div>
|
||||
|
@ -1,3 +1,8 @@
|
||||
:host {
|
||||
display: block;
|
||||
|
||||
ngx-skeleton-loader {
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
|
||||
|
||||
import { FearAndGreedIndexComponent } from './fear-and-greed-index.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [FearAndGreedIndexComponent],
|
||||
exports: [FearAndGreedIndexComponent],
|
||||
imports: [CommonModule]
|
||||
imports: [CommonModule, NgxSkeletonLoaderModule]
|
||||
})
|
||||
export class GfFearAndGreedIndexModule {}
|
||||
|
@ -20,7 +20,6 @@
|
||||
<gf-fear-and-greed-index
|
||||
class="d-flex justify-content-center"
|
||||
[fearAndGreedIndex]="fearAndGreedIndex"
|
||||
[hidden]="isLoading"
|
||||
></gf-fear-and-greed-index>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,6 +10,7 @@
|
||||
[baseCurrency]="user?.settings?.baseCurrency"
|
||||
[hasPermissionToUpdateUserSettings]="!hasImpersonationId && hasPermissionToUpdateUserSettings"
|
||||
[isLoading]="isLoading"
|
||||
[language]="user?.settings?.language"
|
||||
[locale]="user?.settings?.locale"
|
||||
[summary]="summary"
|
||||
(emergencyFundChanged)="onChangeEmergencyFund($event)"
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
OnInit,
|
||||
Output
|
||||
} from '@angular/core';
|
||||
import { getDateFnsLocale } from '@ghostfolio/common/helper';
|
||||
import { PortfolioSummary } from '@ghostfolio/common/interfaces';
|
||||
import { formatDistanceToNow } from 'date-fns';
|
||||
|
||||
@ -20,6 +21,7 @@ export class PortfolioSummaryComponent implements OnChanges, OnInit {
|
||||
@Input() baseCurrency: string;
|
||||
@Input() hasPermissionToUpdateUserSettings: boolean;
|
||||
@Input() isLoading: boolean;
|
||||
@Input() language: string;
|
||||
@Input() locale: string;
|
||||
@Input() summary: PortfolioSummary;
|
||||
|
||||
@ -34,7 +36,9 @@ export class PortfolioSummaryComponent implements OnChanges, OnInit {
|
||||
public ngOnChanges() {
|
||||
if (this.summary) {
|
||||
if (this.summary.firstOrderDate) {
|
||||
this.timeInMarket = formatDistanceToNow(this.summary.firstOrderDate);
|
||||
this.timeInMarket = formatDistanceToNow(this.summary.firstOrderDate, {
|
||||
locale: getDateFnsLocale(this.language)
|
||||
});
|
||||
} else {
|
||||
this.timeInMarket = '-';
|
||||
}
|
||||
|
@ -316,6 +316,7 @@ export class AccountPageComponent implements OnDestroy, OnInit {
|
||||
const dialogRef = this.dialog.open(CreateOrUpdateAccessDialog, {
|
||||
data: {
|
||||
access: {
|
||||
alias: '',
|
||||
type: 'PUBLIC'
|
||||
}
|
||||
},
|
||||
@ -331,7 +332,7 @@ export class AccountPageComponent implements OnDestroy, OnInit {
|
||||
|
||||
if (access) {
|
||||
this.dataService
|
||||
.postAccess({})
|
||||
.postAccess({ alias: access.alias })
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe({
|
||||
next: () => {
|
||||
|
@ -119,6 +119,7 @@
|
||||
<mat-form-field appearance="outline" class="w-100">
|
||||
<mat-select
|
||||
name="language"
|
||||
[disabled]="!hasPermissionToUpdateUserSettings"
|
||||
[value]="language"
|
||||
(selectionChange)="onChangeUserSetting('language', $event.value)"
|
||||
>
|
||||
|
@ -1,6 +1,17 @@
|
||||
<form #addAccessForm="ngForm" class="d-flex flex-column h-100">
|
||||
<h1 i18n mat-dialog-title>Grant access</h1>
|
||||
<div class="flex-grow-1" mat-dialog-content>
|
||||
<div>
|
||||
<mat-form-field appearance="outline" class="w-100">
|
||||
<mat-label i18n>Alias</mat-label>
|
||||
<input
|
||||
matInput
|
||||
name="alias"
|
||||
type="text"
|
||||
[(ngModel)]="data.access.alias"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div>
|
||||
<mat-form-field appearance="outline" class="w-100">
|
||||
<mat-label i18n>Type</mat-label>
|
||||
|
@ -4,6 +4,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
|
||||
import { CreateOrUpdateAccessDialog } from './create-or-update-access-dialog.component';
|
||||
@ -16,6 +17,7 @@ import { CreateOrUpdateAccessDialog } from './create-or-update-access-dialog.com
|
||||
MatButtonModule,
|
||||
MatDialogModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
MatSelectModule,
|
||||
ReactiveFormsModule
|
||||
]
|
||||
|
@ -38,7 +38,6 @@ export class HoldingsPageComponent implements OnDestroy, OnInit {
|
||||
public routeQueryParams: Subscription;
|
||||
public user: User;
|
||||
|
||||
private readonly SEARCH_PLACEHOLDER = 'Filter by account or tag...';
|
||||
private unsubscribeSubject = new Subject<void>();
|
||||
|
||||
public constructor(
|
||||
@ -84,7 +83,9 @@ export class HoldingsPageComponent implements OnDestroy, OnInit {
|
||||
this.isLoading = true;
|
||||
this.activeFilters = filters;
|
||||
this.placeholder =
|
||||
this.activeFilters.length <= 0 ? this.SEARCH_PLACEHOLDER : '';
|
||||
this.activeFilters.length <= 0
|
||||
? $localize`Filter by account or tag...`
|
||||
: '';
|
||||
|
||||
return this.dataService.fetchPortfolioDetails({
|
||||
filters: this.activeFilters
|
||||
|
@ -2,7 +2,8 @@
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h3 class="h4 mb-3 text-center" i18n>
|
||||
Hello, someone has shared a <strong>Portfolio</strong> with you!
|
||||
Hello, {{ portfolioPublicDetails?.alias ?? 'someone' }} has shared a
|
||||
<strong>Portfolio</strong> with you!
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -26,7 +26,7 @@
|
||||
<target state="translated">Empfänger</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/components/access-table/access-table.component.html</context>
|
||||
<context context-type="linenumber">3</context>
|
||||
<context context-type="linenumber">10</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="f61c6867295f3b53d23557021f2f4e0aa1d0b8fc" datatype="html">
|
||||
@ -34,7 +34,7 @@
|
||||
<target state="translated">Typ</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/components/access-table/access-table.component.html</context>
|
||||
<context context-type="linenumber">10</context>
|
||||
<context context-type="linenumber">17</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/components/admin-jobs/admin-jobs.html</context>
|
||||
@ -42,7 +42,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html</context>
|
||||
<context context-type="linenumber">6</context>
|
||||
<context context-type="linenumber">17</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html</context>
|
||||
@ -62,7 +62,7 @@
|
||||
<target state="translated">Details</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/components/access-table/access-table.component.html</context>
|
||||
<context context-type="linenumber">20</context>
|
||||
<context context-type="linenumber">27</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="53ea2772322e7d4d21515bb0c6dead283f8e18a5" datatype="html">
|
||||
@ -70,7 +70,7 @@
|
||||
<target state="translated">Widerrufen</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/components/access-table/access-table.component.html</context>
|
||||
<context context-type="linenumber">47</context>
|
||||
<context context-type="linenumber">54</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="8264698726451826067" datatype="html">
|
||||
@ -131,7 +131,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="d04d5b5d13ac9acf9750f1807f0227eeee98b247" datatype="html">
|
||||
<source>Total</source>
|
||||
<target state="translated">Total</target>
|
||||
<target state="translated">Gesamt</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/components/accounts-table/accounts-table.component.html</context>
|
||||
<context context-type="linenumber">18</context>
|
||||
@ -366,7 +366,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html</context>
|
||||
<context context-type="linenumber">14</context>
|
||||
<context context-type="linenumber">25</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html</context>
|
||||
@ -390,7 +390,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html</context>
|
||||
<context context-type="linenumber">21</context>
|
||||
<context context-type="linenumber">32</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html</context>
|
||||
@ -798,7 +798,7 @@
|
||||
<target state="translated">Registrieren</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">136</context>
|
||||
<context context-type="linenumber">137</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="5207635742003539443" datatype="html">
|
||||
@ -1070,7 +1070,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">44</context>
|
||||
<context context-type="linenumber">45</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="aee7d0de4e30405c1289745e4264e622b613632a" datatype="html">
|
||||
@ -1438,7 +1438,7 @@
|
||||
<target state="translated">Öffentlich</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html</context>
|
||||
<context context-type="linenumber">8</context>
|
||||
<context context-type="linenumber">19</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="5016419499983434110" datatype="html">
|
||||
@ -1678,7 +1678,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">75</context>
|
||||
<context context-type="linenumber">76</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="2948175671993825247" datatype="html">
|
||||
@ -1782,7 +1782,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">13</context>
|
||||
<context context-type="linenumber">14</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="888f6842631dc20550ad7e9a9c45ef55bf45852b" datatype="html">
|
||||
@ -2041,20 +2041,12 @@
|
||||
<context context-type="linenumber">12</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="7081e73933b030c02e11519f76884ef7cb5d99fc" datatype="html">
|
||||
<source> Hello, someone has shared a <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="<strong>"/>Portfolio<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="</strong>"/> with you! </source>
|
||||
<target state="new"/>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">4,6</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="4056a76e7a710ab32285892a58d66f2d1a927796" datatype="html">
|
||||
<source>Currencies</source>
|
||||
<target state="translated">Währungen</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">29</context>
|
||||
<context context-type="linenumber">30</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="3c3163d370916438f3b52ea17720bfb2a68a1709" datatype="html">
|
||||
@ -2062,7 +2054,7 @@
|
||||
<target state="translated">Kontinente</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">59</context>
|
||||
<context context-type="linenumber">60</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="a3d148b40a389fda0665eb583c9e434ec5ee1ced" datatype="html">
|
||||
@ -2070,7 +2062,7 @@
|
||||
<target state="new"/>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">131,133</context>
|
||||
<context context-type="linenumber">132,134</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="8298333184054476827" datatype="html">
|
||||
@ -2206,7 +2198,7 @@
|
||||
<target state="translated">Möchtest du diese Aktivität wirklich löschen?</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.ts</context>
|
||||
<context context-type="linenumber">136</context>
|
||||
<context context-type="linenumber">134</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="170f7de02b14690fb9c1999a16926c0044bfd5c1" datatype="html">
|
||||
@ -2422,7 +2414,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">89</context>
|
||||
<context context-type="linenumber">90</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="81eb53c18dfd116d6e54877444847b3091d92ab0" datatype="html">
|
||||
@ -2434,7 +2426,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">98</context>
|
||||
<context context-type="linenumber">99</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="7233cd3a1ef8913fa5c6db7a29c88044646ceacc" datatype="html">
|
||||
@ -2446,7 +2438,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">107</context>
|
||||
<context context-type="linenumber">108</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="add4cd82e3e38a3110fe67b3c7df56e9602644ee" datatype="html">
|
||||
@ -2503,7 +2495,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="e34e2478d2d30c9d01758d01b7212411171b9bd5" datatype="html">
|
||||
<source>Projected Total Amount</source>
|
||||
<target state="translated">Geschätzter Gesamtbetrag</target>
|
||||
<target state="translated">Projizierter Gesamtbetrag</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.html</context>
|
||||
<context context-type="linenumber">44</context>
|
||||
@ -2616,6 +2608,38 @@
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
|
||||
<context context-type="linenumber">136</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/holdings/holdings-page.component.ts</context>
|
||||
<context context-type="linenumber">87</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="303469635941752458" datatype="html">
|
||||
<source>Filter by account, currency, symbol or type...</source>
|
||||
<target state="translated">Filtern nach Konto, Währung, Symbol oder Typ...</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.ts</context>
|
||||
<context context-type="linenumber">291</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="fbaaeb297e70b9a800acf841b9d26c19d60651ef" datatype="html">
|
||||
<source>Alias</source>
|
||||
<target state="translated">Alias</target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/components/access-table/access-table.component.html</context>
|
||||
<context context-type="linenumber">3</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html</context>
|
||||
<context context-type="linenumber">6</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="3d14940af7de691ac27efb67bef3e974cbe3281c" datatype="html">
|
||||
<source> Hello, <x id="INTERPOLATION" equiv-text="{{ portfolioPublicDetails?.alias ?? 'someone' }}"/> has shared a <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="<strong>"/>Portfolio<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="</strong>"/> with you! </source>
|
||||
<target state="translated"> Hallo, <x id="INTERPOLATION" equiv-text="{{ portfolioPublicDetails?.alias ?? 'jemand' }}"/> hat ein <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="<strong>"/>Portfolio<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="</strong>"/> mit dir geteilt! </target>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">4,7</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
|
@ -24,14 +24,14 @@
|
||||
<source>Grantee</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/components/access-table/access-table.component.html</context>
|
||||
<context context-type="linenumber">3</context>
|
||||
<context context-type="linenumber">10</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="f61c6867295f3b53d23557021f2f4e0aa1d0b8fc" datatype="html">
|
||||
<source>Type</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/components/access-table/access-table.component.html</context>
|
||||
<context context-type="linenumber">10</context>
|
||||
<context context-type="linenumber">17</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/components/admin-jobs/admin-jobs.html</context>
|
||||
@ -39,7 +39,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html</context>
|
||||
<context context-type="linenumber">6</context>
|
||||
<context context-type="linenumber">17</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html</context>
|
||||
@ -58,14 +58,14 @@
|
||||
<source>Details</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/components/access-table/access-table.component.html</context>
|
||||
<context context-type="linenumber">20</context>
|
||||
<context context-type="linenumber">27</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="53ea2772322e7d4d21515bb0c6dead283f8e18a5" datatype="html">
|
||||
<source>Revoke</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/components/access-table/access-table.component.html</context>
|
||||
<context context-type="linenumber">47</context>
|
||||
<context context-type="linenumber">54</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="8264698726451826067" datatype="html">
|
||||
@ -337,7 +337,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html</context>
|
||||
<context context-type="linenumber">14</context>
|
||||
<context context-type="linenumber">25</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html</context>
|
||||
@ -360,7 +360,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html</context>
|
||||
<context context-type="linenumber">21</context>
|
||||
<context context-type="linenumber">32</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html</context>
|
||||
@ -726,7 +726,7 @@
|
||||
<source>Get Started</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">136</context>
|
||||
<context context-type="linenumber">137</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="5207635742003539443" datatype="html">
|
||||
@ -968,7 +968,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">44</context>
|
||||
<context context-type="linenumber">45</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="aee7d0de4e30405c1289745e4264e622b613632a" datatype="html">
|
||||
@ -1292,7 +1292,7 @@
|
||||
<source>Public</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html</context>
|
||||
<context context-type="linenumber">8</context>
|
||||
<context context-type="linenumber">19</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="5016419499983434110" datatype="html">
|
||||
@ -1506,7 +1506,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">75</context>
|
||||
<context context-type="linenumber">76</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="2948175671993825247" datatype="html">
|
||||
@ -1599,7 +1599,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">13</context>
|
||||
<context context-type="linenumber">14</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="888f6842631dc20550ad7e9a9c45ef55bf45852b" datatype="html">
|
||||
@ -1829,32 +1829,25 @@
|
||||
<context context-type="linenumber">12</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="7081e73933b030c02e11519f76884ef7cb5d99fc" datatype="html">
|
||||
<source> Hello, someone has shared a <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="<strong>"/>Portfolio<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="</strong>"/> with you! </source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">4,6</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="4056a76e7a710ab32285892a58d66f2d1a927796" datatype="html">
|
||||
<source>Currencies</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">29</context>
|
||||
<context context-type="linenumber">30</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="3c3163d370916438f3b52ea17720bfb2a68a1709" datatype="html">
|
||||
<source>Continents</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">59</context>
|
||||
<context context-type="linenumber">60</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="a3d148b40a389fda0665eb583c9e434ec5ee1ced" datatype="html">
|
||||
<source> Ghostfolio empowers you to keep track of your wealth. </source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">131,133</context>
|
||||
<context context-type="linenumber">132,134</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="8298333184054476827" datatype="html">
|
||||
@ -1973,7 +1966,7 @@
|
||||
<source>Do you really want to delete this activity?</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.ts</context>
|
||||
<context context-type="linenumber">136</context>
|
||||
<context context-type="linenumber">134</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="170f7de02b14690fb9c1999a16926c0044bfd5c1" datatype="html">
|
||||
@ -2107,7 +2100,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">89</context>
|
||||
<context context-type="linenumber">90</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="27fe3d097c64eaec7ff564358f80fb7ba795f484" datatype="html">
|
||||
@ -2147,7 +2140,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">107</context>
|
||||
<context context-type="linenumber">108</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="81eb53c18dfd116d6e54877444847b3091d92ab0" datatype="html">
|
||||
@ -2158,7 +2151,7 @@
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">98</context>
|
||||
<context context-type="linenumber">99</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="936788a5ab949fe0d70098ba051ac7a44999ff08" datatype="html">
|
||||
@ -2329,6 +2322,10 @@
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
|
||||
<context context-type="linenumber">136</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/holdings/holdings-page.component.ts</context>
|
||||
<context context-type="linenumber">87</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="4550487415324294802" datatype="html">
|
||||
<source>Filter by...</source>
|
||||
@ -2337,6 +2334,31 @@
|
||||
<context context-type="linenumber">129</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="303469635941752458" datatype="html">
|
||||
<source>Filter by account, currency, symbol or type...</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">libs/ui/src/lib/activities-table/activities-table.component.ts</context>
|
||||
<context context-type="linenumber">291</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="3d14940af7de691ac27efb67bef3e974cbe3281c" datatype="html">
|
||||
<source> Hello, <x id="INTERPOLATION" equiv-text="{{ portfolioPublicDetails?.alias ?? 'someone' }}"/> has shared a <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="<strong>"/>Portfolio<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="</strong>"/> with you! </source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||
<context context-type="linenumber">4,7</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
<trans-unit id="fbaaeb297e70b9a800acf841b9d26c19d60651ef" datatype="html">
|
||||
<source>Alias</source>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/components/access-table/access-table.component.html</context>
|
||||
<context context-type="linenumber">3</context>
|
||||
</context-group>
|
||||
<context-group purpose="location">
|
||||
<context context-type="sourcefile">apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html</context>
|
||||
<context context-type="linenumber">6</context>
|
||||
</context-group>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
@ -1,6 +1,7 @@
|
||||
import * as currencies from '@dinero.js/currencies';
|
||||
import { DataSource } from '@prisma/client';
|
||||
import { getDate, getMonth, getYear, parse, subDays } from 'date-fns';
|
||||
import { de } from 'date-fns/locale';
|
||||
|
||||
import { ghostfolioScraperApiSymbolPrefix, locale } from './config';
|
||||
import { Benchmark } from './interfaces';
|
||||
@ -56,6 +57,14 @@ export function getCssVariable(aCssVariable: string) {
|
||||
);
|
||||
}
|
||||
|
||||
export function getDateFnsLocale(aLanguageCode: string) {
|
||||
if (aLanguageCode === 'de') {
|
||||
return de;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function getDateFormatString(aLocale?: string) {
|
||||
const formatObject = new Intl.DateTimeFormat(aLocale).formatToParts(
|
||||
new Date()
|
||||
|
@ -1,5 +1,6 @@
|
||||
export interface Access {
|
||||
granteeAlias: string;
|
||||
alias?: string;
|
||||
grantee: string;
|
||||
id: string;
|
||||
type: 'PUBLIC' | 'RESTRICTED_VIEW';
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { PortfolioPosition } from '@ghostfolio/common/interfaces';
|
||||
|
||||
export interface PortfolioPublicDetails {
|
||||
alias?: string;
|
||||
hasDetails: boolean;
|
||||
holdings: {
|
||||
[symbol: string]: Pick<
|
||||
|
@ -65,8 +65,6 @@ export class ActivitiesTableComponent implements OnChanges, OnDestroy {
|
||||
public totalFees: number;
|
||||
public totalValue: number;
|
||||
|
||||
private readonly SEARCH_PLACEHOLDER =
|
||||
'Filter by account, currency, symbol or type...';
|
||||
private readonly SEARCH_STRING_SEPARATOR = ',';
|
||||
private unsubscribeSubject = new Subject<void>();
|
||||
|
||||
@ -289,7 +287,9 @@ export class ActivitiesTableComponent implements OnChanges, OnDestroy {
|
||||
});
|
||||
|
||||
this.placeholder =
|
||||
lowercaseSearchKeywords.length <= 0 ? this.SEARCH_PLACEHOLDER : '';
|
||||
lowercaseSearchKeywords.length <= 0
|
||||
? $localize`Filter by account, currency, symbol or type...`
|
||||
: '';
|
||||
|
||||
this.searchKeywords = filters.map((filter) => {
|
||||
return filter.label;
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ghostfolio",
|
||||
"version": "1.183.0",
|
||||
"version": "1.185.0",
|
||||
"homepage": "https://ghostfol.io",
|
||||
"license": "AGPL-3.0",
|
||||
"scripts": {
|
||||
@ -24,7 +24,7 @@
|
||||
"database:migrate": "prisma migrate deploy",
|
||||
"database:push": "prisma db push",
|
||||
"database:seed": "prisma db seed",
|
||||
"database:setup": "yarn database:push && yarn database:seed && yarn database:baseline",
|
||||
"database:setup": "yarn database:push && yarn database:seed",
|
||||
"database:validate": "prisma validate",
|
||||
"dep-graph": "nx dep-graph",
|
||||
"e2e": "ng e2e",
|
||||
|
@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Access" ADD COLUMN "alias" TEXT;
|
@ -1,7 +1,7 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
previewFeatures = []
|
||||
binaryTargets = ["debian-openssl-1.1.x", "native"]
|
||||
binaryTargets = ["debian-openssl-1.1.x", "linux-arm64-openssl-1.1.x", "native"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
@ -10,6 +10,7 @@ datasource db {
|
||||
}
|
||||
|
||||
model Access {
|
||||
alias String?
|
||||
createdAt DateTime @default(now())
|
||||
granteeUserId String?
|
||||
id String @id @default(uuid())
|
||||
|
@ -1,5 +0,0 @@
|
||||
set -xe
|
||||
echo "$DOCKER_HUB_ACCESS_TOKEN" | docker login -u "$DOCKER_HUB_USERNAME" --password-stdin
|
||||
|
||||
docker build -t ghostfolio/ghostfolio:$TRAVIS_TAG -t ghostfolio/ghostfolio:latest .
|
||||
docker push ghostfolio/ghostfolio --all-tags
|
Reference in New Issue
Block a user