Browse Source

Merge branch 'main' into feature/upgrade-prisma-to-version-6.1.0

pull/4135/head
Thomas Kaul 8 months ago
committed by GitHub
parent
commit
4d541cd2b4
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 13
      CHANGELOG.md
  2. 40
      apps/api/src/app/info/info.service.ts
  3. 10
      apps/api/src/app/logo/logo.service.ts
  4. 5
      apps/api/src/app/order/order.service.ts
  5. 3
      apps/api/src/main.ts
  6. 36
      apps/api/src/services/data-provider/coingecko/coingecko.service.ts
  7. 8
      apps/api/src/services/data-provider/data-enhancer/openfigi/openfigi.service.ts
  8. 38
      apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts
  9. 34
      apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts
  10. 26
      apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts
  11. 34
      apps/api/src/services/data-provider/ghostfolio/ghostfolio.service.ts
  12. 10
      apps/api/src/services/data-provider/manual/manual.service.ts
  13. 10
      apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts
  14. 6
      apps/client/.eslintrc.json
  15. 3
      apps/client/src/app/app.component.ts
  16. 3
      apps/client/src/app/components/access-table/access-table.component.ts
  17. 3
      apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts
  18. 3
      apps/client/src/app/components/accounts-table/accounts-table.component.ts
  19. 3
      apps/client/src/app/components/admin-jobs/admin-jobs.component.ts
  20. 3
      apps/client/src/app/components/admin-market-data/admin-market-data.component.ts
  21. 3
      apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts
  22. 3
      apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.component.ts
  23. 3
      apps/client/src/app/components/admin-overview/admin-overview.component.ts
  24. 3
      apps/client/src/app/components/admin-platform/admin-platform.component.ts
  25. 3
      apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.component.ts
  26. 6
      apps/client/src/app/components/admin-settings/admin-settings.component.ts
  27. 15
      apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts
  28. 2
      apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html
  29. 3
      apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/interfaces/interfaces.ts
  30. 3
      apps/client/src/app/components/admin-tag/admin-tag.component.ts
  31. 3
      apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.component.ts
  32. 3
      apps/client/src/app/components/admin-users/admin-users.component.ts
  33. 1
      apps/client/src/app/components/asset-profile-icon/asset-profile-icon.component.ts
  34. 3
      apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
  35. 3
      apps/client/src/app/components/dialog-footer/dialog-footer.component.ts
  36. 3
      apps/client/src/app/components/dialog-header/dialog-header.component.ts
  37. 3
      apps/client/src/app/components/fear-and-greed-index/fear-and-greed-index.component.ts
  38. 3
      apps/client/src/app/components/header/header.component.ts
  39. 1
      apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts
  40. 3
      apps/client/src/app/components/home-holdings/home-holdings.component.ts
  41. 3
      apps/client/src/app/components/home-market/home-market.component.ts
  42. 3
      apps/client/src/app/components/home-overview/home-overview.component.ts
  43. 3
      apps/client/src/app/components/home-summary/home-summary.component.ts
  44. 3
      apps/client/src/app/components/investment-chart/investment-chart.component.ts
  45. 3
      apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.component.ts
  46. 3
      apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts
  47. 3
      apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts
  48. 1
      apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.component.ts
  49. 3
      apps/client/src/app/components/rule/rule.component.ts
  50. 3
      apps/client/src/app/components/rules/rules.component.ts
  51. 3
      apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts
  52. 3
      apps/client/src/app/components/toggle/toggle.component.ts
  53. 3
      apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts
  54. 3
      apps/client/src/app/components/user-account-access/user-account-access.component.ts
  55. 11
      apps/client/src/app/components/user-account-membership/user-account-membership.component.ts
  56. 3
      apps/client/src/app/components/user-account-settings/user-account-settings.component.ts
  57. 3
      apps/client/src/app/components/world-map-chart/world-map-chart.component.ts
  58. 1
      apps/client/src/app/core/notification/alert-dialog/alert-dialog.component.ts
  59. 1
      apps/client/src/app/core/notification/confirmation-dialog/confirmation-dialog.component.ts
  60. 1
      apps/client/src/app/core/notification/prompt-dialog/prompt-dialog.component.ts
  61. 3
      apps/client/src/app/directives/file-drop/file-drop.directive.ts
  62. 3
      apps/client/src/app/pages/about/about-page.component.ts
  63. 3
      apps/client/src/app/pages/about/changelog/changelog-page.component.ts
  64. 3
      apps/client/src/app/pages/about/license/license-page.component.ts
  65. 3
      apps/client/src/app/pages/about/oss-friends/oss-friends-page.component.ts
  66. 3
      apps/client/src/app/pages/about/overview/about-overview-page.component.ts
  67. 3
      apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.component.ts
  68. 3
      apps/client/src/app/pages/accounts/accounts-page.component.ts
  69. 3
      apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts
  70. 3
      apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.component.ts
  71. 3
      apps/client/src/app/pages/admin/admin-page.component.ts
  72. 1
      apps/client/src/app/pages/api/api-page.component.ts
  73. 3
      apps/client/src/app/pages/auth/auth-page.component.ts
  74. 1
      apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.component.ts
  75. 1
      apps/client/src/app/pages/blog/2021/07/hello-ghostfolio/hello-ghostfolio-page.component.ts
  76. 1
      apps/client/src/app/pages/blog/2022/01/first-months-in-open-source/first-months-in-open-source-page.component.ts
  77. 1
      apps/client/src/app/pages/blog/2022/07/ghostfolio-meets-internet-identity/ghostfolio-meets-internet-identity-page.component.ts
  78. 1
      apps/client/src/app/pages/blog/2022/07/how-do-i-get-my-finances-in-order/how-do-i-get-my-finances-in-order-page.component.ts
  79. 1
      apps/client/src/app/pages/blog/2022/08/500-stars-on-github/500-stars-on-github-page.component.ts
  80. 1
      apps/client/src/app/pages/blog/2022/10/hacktoberfest-2022/hacktoberfest-2022-page.component.ts
  81. 1
      apps/client/src/app/pages/blog/2022/11/black-friday-2022/black-friday-2022-page.component.ts
  82. 1
      apps/client/src/app/pages/blog/2022/12/the-importance-of-tracking-your-personal-finances/the-importance-of-tracking-your-personal-finances-page.component.ts
  83. 1
      apps/client/src/app/pages/blog/2023/01/ghostfolio-auf-sackgeld-vorgestellt/ghostfolio-auf-sackgeld-vorgestellt-page.component.ts
  84. 1
      apps/client/src/app/pages/blog/2023/02/ghostfolio-meets-umbrel/ghostfolio-meets-umbrel-page.component.ts
  85. 1
      apps/client/src/app/pages/blog/2023/03/1000-stars-on-github/1000-stars-on-github-page.component.ts
  86. 1
      apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.component.ts
  87. 1
      apps/client/src/app/pages/blog/2023/07/exploring-the-path-to-fire/exploring-the-path-to-fire-page.component.ts
  88. 1
      apps/client/src/app/pages/blog/2023/08/ghostfolio-joins-oss-friends/ghostfolio-joins-oss-friends-page.component.ts
  89. 1
      apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts
  90. 1
      apps/client/src/app/pages/blog/2023/09/hacktoberfest-2023/hacktoberfest-2023-page.component.ts
  91. 1
      apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts
  92. 1
      apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts
  93. 1
      apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component.ts
  94. 1
      apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts
  95. 3
      apps/client/src/app/pages/blog/blog-page.component.ts
  96. 3
      apps/client/src/app/pages/faq/faq-page.component.ts
  97. 3
      apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts
  98. 3
      apps/client/src/app/pages/faq/saas/saas-page.component.ts
  99. 3
      apps/client/src/app/pages/faq/self-hosting/self-hosting-page.component.ts
  100. 1
      apps/client/src/app/pages/features/features-page.component.ts

13
CHANGELOG.md

@ -13,8 +13,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Improved support for automatic deletion of unused asset profiles when deleting activities
- Migrated the coupon redemption to the notification service for prompt dialogs
- Refactored `got` calls to use `AbortSignal.timeout()` without `AbortController()`
- Improved the language localization for German (`de`)
- Eliminated `body-parser` in favor of using `@nestjs/platform-express`
- Upgraded the _Stripe_ dependencies
- Upgraded `angular` from version `18.2.8` to `19.0.5`
- Upgraded `husky` from version `9.1.6` to `9.1.7`
- Upgraded `marked` from version `12.0.2` to `15.0.4`
- Upgraded `ng-extract-i18n-merge` from version `2.12.0` to `2.13.1`
- Upgraded `ngx-device-detector` from version `8.0.0` to `9.0.0`
- Upgraded `ngx-markdown` from version `18.0.0` to `19.0.0`
- Upgraded `Nx` from version `20.1.2` to `20.3.0`
- Upgraded `prisma` from version `6.0.1` to `6.1.0`
- Upgraded `zone.js` from version `0.14.10` to `0.15.0`
## 2.131.0 - 2024-12-25

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

@ -155,18 +155,14 @@ export class InfoService {
private async countDockerHubPulls(): Promise<number> {
try {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, this.configurationService.get('REQUEST_TIMEOUT'));
const { pull_count } = await got(
`https://hub.docker.com/v2/repositories/ghostfolio/ghostfolio`,
{
headers: { 'User-Agent': 'request' },
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(
this.configurationService.get('REQUEST_TIMEOUT')
)
}
).json<any>();
@ -180,15 +176,11 @@ export class InfoService {
private async countGitHubContributors(): Promise<number> {
try {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, this.configurationService.get('REQUEST_TIMEOUT'));
const { body } = await got('https://github.com/ghostfolio/ghostfolio', {
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(
this.configurationService.get('REQUEST_TIMEOUT')
)
});
const $ = cheerio.load(body);
@ -207,18 +199,14 @@ export class InfoService {
private async countGitHubStargazers(): Promise<number> {
try {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, this.configurationService.get('REQUEST_TIMEOUT'));
const { stargazers_count } = await got(
`https://api.github.com/repos/ghostfolio/ghostfolio`,
{
headers: { 'User-Agent': 'request' },
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(
this.configurationService.get('REQUEST_TIMEOUT')
)
}
).json<any>();
@ -335,12 +323,6 @@ export class InfoService {
PROPERTY_BETTER_UPTIME_MONITOR_ID
)) as string;
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, this.configurationService.get('REQUEST_TIMEOUT'));
const { data } = await got(
`https://uptime.betterstack.com/api/v2/monitors/${monitorId}/sla?from=${format(
subDays(new Date(), 90),
@ -353,7 +335,9 @@ export class InfoService {
)}`
},
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(
this.configurationService.get('REQUEST_TIMEOUT')
)
}
).json<any>();

10
apps/api/src/app/logo/logo.service.ts

@ -44,18 +44,14 @@ export class LogoService {
}
private getBuffer(aUrl: string) {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, this.configurationService.get('REQUEST_TIMEOUT'));
return got(
`https://t0.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=${aUrl}&size=64`,
{
headers: { 'User-Agent': 'request' },
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(
this.configurationService.get('REQUEST_TIMEOUT')
)
}
).buffer();
}

5
apps/api/src/app/order/order.service.ts

@ -224,10 +224,7 @@ export class OrderService {
order.symbolProfileId
]);
if (
['FEE', 'INTEREST', 'ITEM', 'LIABILITY'].includes(order.type) ||
symbolProfile.activitiesCount === 0
) {
if (symbolProfile.activitiesCount === 0) {
await this.symbolProfileService.deleteById(order.symbolProfileId);
}

3
apps/api/src/main.ts

@ -7,7 +7,6 @@ import {
import { ConfigService } from '@nestjs/config';
import { NestFactory } from '@nestjs/core';
import type { NestExpressApplication } from '@nestjs/platform-express';
import { json } from 'body-parser';
import helmet from 'helmet';
import { AppModule } from './app/app.module';
@ -48,7 +47,7 @@ async function bootstrap() {
);
// Support 10mb csv/json files for importing activities
app.use(json({ limit: '10mb' }));
app.useBodyParser('json', { limit: '10mb' });
if (configService.get<string>('ENABLE_FEATURE_SUBSCRIPTION') === 'true') {
app.use(

36
apps/api/src/services/data-provider/coingecko/coingecko.service.ts

@ -69,16 +69,12 @@ export class CoinGeckoService implements DataProviderInterface {
};
try {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, this.configurationService.get('REQUEST_TIMEOUT'));
const { name } = await got(`${this.apiUrl}/coins/${symbol}`, {
headers: this.headers,
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(
this.configurationService.get('REQUEST_TIMEOUT')
)
}).json<any>();
response.name = name;
@ -118,12 +114,6 @@ export class CoinGeckoService implements DataProviderInterface {
[symbol: string]: { [date: string]: IDataProviderHistoricalResponse };
}> {
try {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, requestTimeout);
const { prices } = await got(
`${
this.apiUrl
@ -133,7 +123,7 @@ export class CoinGeckoService implements DataProviderInterface {
{
headers: this.headers,
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(requestTimeout)
}
).json<any>();
@ -179,12 +169,6 @@ export class CoinGeckoService implements DataProviderInterface {
}
try {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, requestTimeout);
const quotes = await got(
`${this.apiUrl}/simple/price?ids=${symbols.join(
','
@ -192,7 +176,7 @@ export class CoinGeckoService implements DataProviderInterface {
{
headers: this.headers,
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(requestTimeout)
}
).json<any>();
@ -228,16 +212,12 @@ export class CoinGeckoService implements DataProviderInterface {
let items: LookupItem[] = [];
try {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, this.configurationService.get('REQUEST_TIMEOUT'));
const { coins } = await got(`${this.apiUrl}/search?query=${query}`, {
headers: this.headers,
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(
this.configurationService.get('REQUEST_TIMEOUT')
)
}).json<any>();
items = coins.map(({ id: symbol, name }) => {

8
apps/api/src/services/data-provider/data-enhancer/openfigi/openfigi.service.ts

@ -43,18 +43,12 @@ export class OpenFigiDataEnhancerService implements DataEnhancerInterface {
this.configurationService.get('API_KEY_OPEN_FIGI');
}
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, requestTimeout);
const mappings = await got
.post(`${OpenFigiDataEnhancerService.baseUrl}/v3/mapping`, {
headers,
json: [{ exchCode: exchange, idType: 'TICKER', idValue: ticker }],
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(requestTimeout)
})
.json<any[]>();

38
apps/api/src/services/data-provider/data-enhancer/trackinsight/trackinsight.service.ts

@ -45,34 +45,24 @@ export class TrackinsightDataEnhancerService implements DataEnhancerInterface {
return response;
}
let abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, requestTimeout);
const profile = await got(
`${TrackinsightDataEnhancerService.baseUrl}/funds/${symbol}.json`,
{
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(requestTimeout)
}
)
.json<any>()
.catch(() => {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, this.configurationService.get('REQUEST_TIMEOUT'));
return got(
`${TrackinsightDataEnhancerService.baseUrl}/funds/${
symbol.split('.')?.[0]
}.json`,
{
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(
this.configurationService.get('REQUEST_TIMEOUT')
)
}
)
.json<any>()
@ -87,34 +77,26 @@ export class TrackinsightDataEnhancerService implements DataEnhancerInterface {
response.isin = isin;
}
abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, this.configurationService.get('REQUEST_TIMEOUT'));
const holdings = await got(
`${TrackinsightDataEnhancerService.baseUrl}/holdings/${symbol}.json`,
{
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(
this.configurationService.get('REQUEST_TIMEOUT')
)
}
)
.json<any>()
.catch(() => {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, this.configurationService.get('REQUEST_TIMEOUT'));
return got(
`${TrackinsightDataEnhancerService.baseUrl}/holdings/${
symbol.split('.')?.[0]
}.json`,
{
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(
this.configurationService.get('REQUEST_TIMEOUT')
)
}
)
.json<any>()

34
apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts

@ -91,16 +91,10 @@ export class EodHistoricalDataService implements DataProviderInterface {
}
try {
const abortController = new AbortController();
const response: {
[date: string]: IDataProviderHistoricalResponse;
} = {};
setTimeout(() => {
abortController.abort();
}, requestTimeout);
const historicalResult = await got(
`${this.URL}/div/${symbol}?api_token=${
this.apiKey
@ -110,7 +104,7 @@ export class EodHistoricalDataService implements DataProviderInterface {
)}`,
{
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(requestTimeout)
}
).json<any>();
@ -146,12 +140,6 @@ export class EodHistoricalDataService implements DataProviderInterface {
symbol = this.convertToEodSymbol(symbol);
try {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, requestTimeout);
const response = await got(
`${this.URL}/eod/${symbol}?api_token=${
this.apiKey
@ -161,7 +149,7 @@ export class EodHistoricalDataService implements DataProviderInterface {
)}&period=${granularity}`,
{
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(requestTimeout)
}
).json<any>();
@ -217,19 +205,13 @@ export class EodHistoricalDataService implements DataProviderInterface {
});
try {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, requestTimeout);
const realTimeResponse = await got(
`${this.URL}/real-time/${eodHistoricalDataSymbols[0]}?api_token=${
this.apiKey
}&fmt=json&s=${eodHistoricalDataSymbols.join(',')}`,
{
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(requestTimeout)
}
).json<any>();
@ -418,17 +400,13 @@ export class EodHistoricalDataService implements DataProviderInterface {
})[] = [];
try {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, this.configurationService.get('REQUEST_TIMEOUT'));
const response = await got(
`${this.URL}/search/${aQuery}?api_token=${this.apiKey}`,
{
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(
this.configurationService.get('REQUEST_TIMEOUT')
)
}
).json<any>();

26
apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts

@ -72,17 +72,11 @@ export class FinancialModelingPrepService implements DataProviderInterface {
[symbol: string]: { [date: string]: IDataProviderHistoricalResponse };
}> {
try {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, requestTimeout);
const { historical } = await got(
`${this.URL}/historical-price-full/${symbol}?apikey=${this.apiKey}`,
{
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(requestTimeout)
}
).json<any>();
@ -130,17 +124,11 @@ export class FinancialModelingPrepService implements DataProviderInterface {
}
try {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, requestTimeout);
const quotes = await got(
`${this.URL}/quote/${symbols.join(',')}?apikey=${this.apiKey}`,
{
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(requestTimeout)
}
).json<any>();
@ -176,17 +164,13 @@ export class FinancialModelingPrepService implements DataProviderInterface {
let items: LookupItem[] = [];
try {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, this.configurationService.get('REQUEST_TIMEOUT'));
const result = await got(
`${this.URL}/search?query=${query}&apikey=${this.apiKey}`,
{
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(
this.configurationService.get('REQUEST_TIMEOUT')
)
}
).json<any>();

34
apps/api/src/services/data-provider/ghostfolio/ghostfolio.service.ts

@ -86,12 +86,6 @@ export class GhostfolioService implements DataProviderInterface {
} = {};
try {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, requestTimeout);
const { dividends } = await got(
`${this.URL}/v2/data-providers/ghostfolio/dividends/${symbol}?from=${format(from, DATE_FORMAT)}&granularity=${granularity}&to=${format(
to,
@ -100,7 +94,7 @@ export class GhostfolioService implements DataProviderInterface {
{
headers: await this.getRequestHeaders(),
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(requestTimeout)
}
).json<DividendsResponse>();
@ -136,12 +130,6 @@ export class GhostfolioService implements DataProviderInterface {
[symbol: string]: { [date: string]: IDataProviderHistoricalResponse };
}> {
try {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, requestTimeout);
const { historicalData } = await got(
`${this.URL}/v2/data-providers/ghostfolio/historical/${symbol}?from=${format(from, DATE_FORMAT)}&granularity=${granularity}&to=${format(
to,
@ -150,7 +138,7 @@ export class GhostfolioService implements DataProviderInterface {
{
headers: await this.getRequestHeaders(),
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(requestTimeout)
}
).json<HistoricalResponse>();
@ -204,18 +192,12 @@ export class GhostfolioService implements DataProviderInterface {
}
try {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, requestTimeout);
const { quotes } = await got(
`${this.URL}/v2/data-providers/ghostfolio/quotes?symbols=${symbols.join(',')}`,
{
headers: await this.getRequestHeaders(),
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(requestTimeout)
}
).json<QuotesResponse>();
@ -253,18 +235,14 @@ export class GhostfolioService implements DataProviderInterface {
let searchResult: LookupResponse = { items: [] };
try {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, this.configurationService.get('REQUEST_TIMEOUT'));
searchResult = await got(
`${this.URL}/v2/data-providers/ghostfolio/lookup?query=${query}`,
{
headers: await this.getRequestHeaders(),
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(
this.configurationService.get('REQUEST_TIMEOUT')
)
}
).json<LookupResponse>();
} catch (error) {

10
apps/api/src/services/data-provider/manual/manual.service.ts

@ -275,17 +275,13 @@ export class ManualService implements DataProviderInterface {
scraperConfiguration: ScraperConfiguration
): Promise<number> {
try {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, this.configurationService.get('REQUEST_TIMEOUT'));
let locale = scraperConfiguration.locale;
const { body, headers } = await got(scraperConfiguration.url, {
headers: scraperConfiguration.headers as Headers,
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(
this.configurationService.get('REQUEST_TIMEOUT')
)
});
if (headers['content-type'].includes('application/json')) {

10
apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts

@ -135,12 +135,6 @@ export class RapidApiService implements DataProviderInterface {
oneYearAgo: { value: number; valueText: string };
}> {
try {
const abortController = new AbortController();
setTimeout(() => {
abortController.abort();
}, this.configurationService.get('REQUEST_TIMEOUT'));
const { fgi } = await got(
`https://fear-and-greed-index.p.rapidapi.com/v1/fgi`,
{
@ -150,7 +144,9 @@ export class RapidApiService implements DataProviderInterface {
'x-rapidapi-key': this.configurationService.get('API_KEY_RAPID_API')
},
// @ts-ignore
signal: abortController.signal
signal: AbortSignal.timeout(
this.configurationService.get('REQUEST_TIMEOUT')
)
}
).json<any>();

6
apps/client/.eslintrc.json

@ -16,6 +16,12 @@
{
"files": ["*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts"],
"rules": {
"@angular-eslint/prefer-standalone": "off"
}
}
],
"plugins": ["@angular-eslint/eslint-plugin", "@typescript-eslint"],

3
apps/client/src/app/app.component.ts

@ -38,7 +38,8 @@ import { UserService } from './services/user/user.service';
selector: 'gf-root',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
styleUrls: ['./app.component.scss'],
standalone: false
})
export class AppComponent implements OnDestroy, OnInit {
@HostBinding('class.has-info-message') get getHasMessage() {

3
apps/client/src/app/components/access-table/access-table.component.ts

@ -18,7 +18,8 @@ import { MatTableDataSource } from '@angular/material/table';
selector: 'gf-access-table',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './access-table.component.html',
styleUrls: ['./access-table.component.scss']
styleUrls: ['./access-table.component.scss'],
standalone: false
})
export class AccessTableComponent implements OnChanges {
@Input() accesses: Access[];

3
apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts

@ -37,7 +37,8 @@ import { AccountDetailDialogParams } from './interfaces/interfaces';
selector: 'gf-account-detail-dialog',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: 'account-detail-dialog.html',
styleUrls: ['./account-detail-dialog.component.scss']
styleUrls: ['./account-detail-dialog.component.scss'],
standalone: false
})
export class AccountDetailDialog implements OnDestroy, OnInit {
public accountBalances: AccountBalancesResponse['balances'];

3
apps/client/src/app/components/accounts-table/accounts-table.component.ts

@ -23,7 +23,8 @@ import { Subject, Subscription } from 'rxjs';
selector: 'gf-accounts-table',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './accounts-table.component.html',
styleUrls: ['./accounts-table.component.scss']
styleUrls: ['./accounts-table.component.scss'],
standalone: false
})
export class AccountsTableComponent implements OnChanges, OnDestroy {
@Input() accounts: AccountModel[];

3
apps/client/src/app/components/admin-jobs/admin-jobs.component.ts

@ -27,7 +27,8 @@ import { takeUntil } from 'rxjs/operators';
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'gf-admin-jobs',
styleUrls: ['./admin-jobs.scss'],
templateUrl: './admin-jobs.html'
templateUrl: './admin-jobs.html',
standalone: false
})
export class AdminJobsComponent implements OnDestroy, OnInit {
public DATA_GATHERING_QUEUE_PRIORITY_LOW = DATA_GATHERING_QUEUE_PRIORITY_LOW;

3
apps/client/src/app/components/admin-market-data/admin-market-data.component.ts

@ -48,7 +48,8 @@ import { CreateAssetProfileDialogParams } from './create-asset-profile-dialog/in
host: { class: 'has-fab' },
selector: 'gf-admin-market-data',
styleUrls: ['./admin-market-data.scss'],
templateUrl: './admin-market-data.html'
templateUrl: './admin-market-data.html',
standalone: false
})
export class AdminMarketDataComponent
implements AfterViewInit, OnDestroy, OnInit

3
apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts

@ -42,7 +42,8 @@ import { AssetProfileDialogParams } from './interfaces/interfaces';
selector: 'gf-asset-profile-dialog',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: 'asset-profile-dialog.html',
styleUrls: ['./asset-profile-dialog.component.scss']
styleUrls: ['./asset-profile-dialog.component.scss'],
standalone: false
})
export class AssetProfileDialog implements OnDestroy, OnInit {
public assetProfileClass: string;

3
apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.component.ts

@ -28,7 +28,8 @@ import { CreateAssetProfileDialogMode } from './interfaces/interfaces';
host: { class: 'h-100' },
selector: 'gf-create-asset-profile-dialog',
styleUrls: ['./create-asset-profile-dialog.component.scss'],
templateUrl: 'create-asset-profile-dialog.html'
templateUrl: 'create-asset-profile-dialog.html',
standalone: false
})
export class CreateAssetProfileDialog implements OnInit, OnDestroy {
public createAssetProfileForm: FormGroup;

3
apps/client/src/app/components/admin-overview/admin-overview.component.ts

@ -36,7 +36,8 @@ import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'gf-admin-overview',
styleUrls: ['./admin-overview.scss'],
templateUrl: './admin-overview.html'
templateUrl: './admin-overview.html',
standalone: false
})
export class AdminOverviewComponent implements OnDestroy, OnInit {
public couponDuration: StringValue = '14 days';

3
apps/client/src/app/components/admin-platform/admin-platform.component.ts

@ -29,7 +29,8 @@ import { CreateOrUpdatePlatformDialog } from './create-or-update-platform-dialog
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'gf-admin-platform',
styleUrls: ['./admin-platform.component.scss'],
templateUrl: './admin-platform.component.html'
templateUrl: './admin-platform.component.html',
standalone: false
})
export class AdminPlatformComponent implements OnInit, OnDestroy {
@ViewChild(MatSort) sort: MatSort;

3
apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.component.ts

@ -19,7 +19,8 @@ import { CreateOrUpdatePlatformDialogParams } from './interfaces/interfaces';
host: { class: 'h-100' },
selector: 'gf-create-or-update-platform-dialog',
styleUrls: ['./create-or-update-platform-dialog.scss'],
templateUrl: 'create-or-update-platform-dialog.html'
templateUrl: 'create-or-update-platform-dialog.html',
standalone: false
})
export class CreateOrUpdatePlatformDialog implements OnDestroy {
public platformForm: FormGroup;

6
apps/client/src/app/components/admin-settings/admin-settings.component.ts

@ -30,7 +30,8 @@ import { GfGhostfolioPremiumApiDialogComponent } from './ghostfolio-premium-api-
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'gf-admin-settings',
styleUrls: ['./admin-settings.component.scss'],
templateUrl: './admin-settings.component.html'
templateUrl: './admin-settings.component.html',
standalone: false
})
export class AdminSettingsComponent implements OnDestroy, OnInit {
public defaultDateFormat: string;
@ -100,7 +101,8 @@ export class AdminSettingsComponent implements OnDestroy, OnInit {
autoFocus: false,
data: {
deviceType: this.deviceType,
pricingUrl: this.pricingUrl
pricingUrl: this.pricingUrl,
user: this.user
},
height: this.deviceType === 'mobile' ? '98vh' : undefined,
width: this.deviceType === 'mobile' ? '100vw' : '50rem'

15
apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.component.ts

@ -1,3 +1,4 @@
import { NotificationService } from '@ghostfolio/client/core/notification/notification.service';
import { DataService } from '@ghostfolio/client/services/data.service';
import { PROPERTY_API_KEY_GHOSTFOLIO } from '@ghostfolio/common/config';
import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator';
@ -25,7 +26,6 @@ import { GhostfolioPremiumApiDialogParams } from './interfaces/interfaces';
MatDialogModule
],
selector: 'gf-ghostfolio-premium-api-dialog',
standalone: true,
styleUrls: ['./ghostfolio-premium-api-dialog.scss'],
templateUrl: './ghostfolio-premium-api-dialog.html'
})
@ -33,7 +33,8 @@ export class GfGhostfolioPremiumApiDialogComponent {
public constructor(
@Inject(MAT_DIALOG_DATA) public data: GhostfolioPremiumApiDialogParams,
private dataService: DataService,
public dialogRef: MatDialogRef<GfGhostfolioPremiumApiDialogComponent>
public dialogRef: MatDialogRef<GfGhostfolioPremiumApiDialogComponent>,
private notificationService: NotificationService
) {}
public onCancel() {
@ -41,10 +42,9 @@ export class GfGhostfolioPremiumApiDialogComponent {
}
public onSetGhostfolioApiKey() {
let ghostfolioApiKey = prompt(
$localize`Please enter your Ghostfolio API key:`
);
ghostfolioApiKey = ghostfolioApiKey?.trim();
this.notificationService.prompt({
confirmFn: (value) => {
const ghostfolioApiKey = value?.trim();
if (ghostfolioApiKey) {
this.dataService
@ -55,5 +55,8 @@ export class GfGhostfolioPremiumApiDialogComponent {
this.dialogRef.close();
});
}
},
title: $localize`Please enter your Ghostfolio API key.`
});
}
}

2
apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/ghostfolio-premium-api-dialog.html

@ -31,6 +31,7 @@
mat-flat-button
>Notify me</a
>
@if (data.user?.settings?.isExperimentalFeatures) {
<div>
<small class="text-muted" i18n>or</small>
</div>
@ -42,6 +43,7 @@
>
I have an API key
</button>
}
</div>
</div>

3
apps/client/src/app/components/admin-settings/ghostfolio-premium-api-dialog/interfaces/interfaces.ts

@ -1,4 +1,7 @@
import { User } from '@ghostfolio/common/interfaces';
export interface GhostfolioPremiumApiDialogParams {
deviceType: string;
pricingUrl: string;
user: User;
}

3
apps/client/src/app/components/admin-tag/admin-tag.component.ts

@ -29,7 +29,8 @@ import { CreateOrUpdateTagDialog } from './create-or-update-tag-dialog/create-or
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'gf-admin-tag',
styleUrls: ['./admin-tag.component.scss'],
templateUrl: './admin-tag.component.html'
templateUrl: './admin-tag.component.html',
standalone: false
})
export class AdminTagComponent implements OnInit, OnDestroy {
@ViewChild(MatSort) sort: MatSort;

3
apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.component.ts

@ -19,7 +19,8 @@ import { CreateOrUpdateTagDialogParams } from './interfaces/interfaces';
host: { class: 'h-100' },
selector: 'gf-create-or-update-tag-dialog',
styleUrls: ['./create-or-update-tag-dialog.scss'],
templateUrl: 'create-or-update-tag-dialog.html'
templateUrl: 'create-or-update-tag-dialog.html',
standalone: false
})
export class CreateOrUpdateTagDialog implements OnDestroy {
public tagForm: FormGroup;

3
apps/client/src/app/components/admin-users/admin-users.component.ts

@ -29,7 +29,8 @@ import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'gf-admin-users',
styleUrls: ['./admin-users.scss'],
templateUrl: './admin-users.html'
templateUrl: './admin-users.html',
standalone: false
})
export class AdminUsersComponent implements OnDestroy, OnInit {
@ViewChild(MatPaginator) paginator: MatPaginator;

1
apps/client/src/app/components/asset-profile-icon/asset-profile-icon.component.ts

@ -13,7 +13,6 @@ import { DataSource } from '@prisma/client';
imports: [CommonModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
selector: 'gf-asset-profile-icon',
standalone: true,
styleUrls: ['./asset-profile-icon.component.scss'],
templateUrl: './asset-profile-icon.component.html'
})

3
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts

@ -44,7 +44,8 @@ import annotationPlugin from 'chartjs-plugin-annotation';
selector: 'gf-benchmark-comparator',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './benchmark-comparator.component.html',
styleUrls: ['./benchmark-comparator.component.scss']
styleUrls: ['./benchmark-comparator.component.scss'],
standalone: false
})
export class BenchmarkComparatorComponent implements OnChanges, OnDestroy {
@Input() benchmark: Partial<SymbolProfile>;

3
apps/client/src/app/components/dialog-footer/dialog-footer.component.ts

@ -11,7 +11,8 @@ import {
selector: 'gf-dialog-footer',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './dialog-footer.component.html',
styleUrls: ['./dialog-footer.component.scss']
styleUrls: ['./dialog-footer.component.scss'],
standalone: false
})
export class DialogFooterComponent {
@Input() deviceType: string;

3
apps/client/src/app/components/dialog-header/dialog-header.component.ts

@ -11,7 +11,8 @@ import {
selector: 'gf-dialog-header',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './dialog-header.component.html',
styleUrls: ['./dialog-header.component.scss']
styleUrls: ['./dialog-header.component.scss'],
standalone: false
})
export class DialogHeaderComponent {
@Input() deviceType: string;

3
apps/client/src/app/components/fear-and-greed-index/fear-and-greed-index.component.ts

@ -12,7 +12,8 @@ import {
selector: 'gf-fear-and-greed-index',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './fear-and-greed-index.component.html',
styleUrls: ['./fear-and-greed-index.component.scss']
styleUrls: ['./fear-and-greed-index.component.scss'],
standalone: false
})
export class FearAndGreedIndexComponent implements OnChanges {
@Input() fearAndGreedIndex: number;

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

@ -35,7 +35,8 @@ import { catchError, takeUntil } from 'rxjs/operators';
selector: 'gf-header',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss']
styleUrls: ['./header.component.scss'],
standalone: false
})
export class HeaderComponent implements OnChanges {
@HostListener('window:keydown', ['$event'])

1
apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts

@ -81,7 +81,6 @@ import { HoldingDetailDialogParams } from './interfaces/interfaces';
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
selector: 'gf-holding-detail-dialog',
standalone: true,
styleUrls: ['./holding-detail-dialog.component.scss'],
templateUrl: 'holding-detail-dialog.html'
})

3
apps/client/src/app/components/home-holdings/home-holdings.component.ts

@ -20,7 +20,8 @@ import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'gf-home-holdings',
styleUrls: ['./home-holdings.scss'],
templateUrl: './home-holdings.html'
templateUrl: './home-holdings.html',
standalone: false
})
export class HomeHoldingsComponent implements OnDestroy, OnInit {
public static DEFAULT_HOLDINGS_VIEW_MODE: HoldingsViewMode = 'TABLE';

3
apps/client/src/app/components/home-market/home-market.component.ts

@ -18,7 +18,8 @@ import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'gf-home-market',
styleUrls: ['./home-market.scss'],
templateUrl: './home-market.html'
templateUrl: './home-market.html',
standalone: false
})
export class HomeMarketComponent implements OnDestroy, OnInit {
public benchmarks: Benchmark[];

3
apps/client/src/app/components/home-overview/home-overview.component.ts

@ -20,7 +20,8 @@ import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'gf-home-overview',
styleUrls: ['./home-overview.scss'],
templateUrl: './home-overview.html'
templateUrl: './home-overview.html',
standalone: false
})
export class HomeOverviewComponent implements OnDestroy, OnInit {
public dateRangeOptions = ToggleComponent.DEFAULT_DATE_RANGE_OPTIONS;

3
apps/client/src/app/components/home-summary/home-summary.component.ts

@ -16,7 +16,8 @@ import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'gf-home-summary',
styleUrls: ['./home-summary.scss'],
templateUrl: './home-summary.html'
templateUrl: './home-summary.html',
standalone: false
})
export class HomeSummaryComponent implements OnDestroy, OnInit {
public hasImpersonationId: boolean;

3
apps/client/src/app/components/investment-chart/investment-chart.component.ts

@ -45,7 +45,8 @@ import { isAfter } from 'date-fns';
selector: 'gf-investment-chart',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './investment-chart.component.html',
styleUrls: ['./investment-chart.component.scss']
styleUrls: ['./investment-chart.component.scss'],
standalone: false
})
export class InvestmentChartComponent implements OnChanges, OnDestroy {
@Input() benchmarkDataItems: InvestmentItem[] = [];

3
apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.component.ts

@ -14,7 +14,8 @@ import { Router } from '@angular/router';
selector: 'gf-login-with-access-token-dialog',
changeDetection: ChangeDetectionStrategy.OnPush,
styleUrls: ['./login-with-access-token-dialog.scss'],
templateUrl: 'login-with-access-token-dialog.html'
templateUrl: 'login-with-access-token-dialog.html',
standalone: false
})
export class LoginWithAccessTokenDialog {
public isAccessTokenHidden = true;

3
apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts

@ -24,7 +24,8 @@ import { isNumber } from 'lodash';
selector: 'gf-portfolio-performance',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './portfolio-performance.component.html',
styleUrls: ['./portfolio-performance.component.scss']
styleUrls: ['./portfolio-performance.component.scss'],
standalone: false
})
export class PortfolioPerformanceComponent implements OnChanges {
@Input() deviceType: string;

3
apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts

@ -17,7 +17,8 @@ import { formatDistanceToNow } from 'date-fns';
selector: 'gf-portfolio-summary',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './portfolio-summary.component.html',
styleUrls: ['./portfolio-summary.component.scss']
styleUrls: ['./portfolio-summary.component.scss'],
standalone: false
})
export class PortfolioSummaryComponent implements OnChanges {
@Input() baseCurrency: string;

1
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.component.ts

@ -22,7 +22,6 @@ import { IRuleSettingsDialogParams } from './interfaces/interfaces';
MatSliderModule
],
selector: 'gf-rule-settings-dialog',
standalone: true,
styleUrls: ['./rule-settings-dialog.scss'],
templateUrl: './rule-settings-dialog.html'
})

3
apps/client/src/app/components/rule/rule.component.ts

@ -24,7 +24,8 @@ import { GfRuleSettingsDialogComponent } from './rule-settings-dialog/rule-setti
selector: 'gf-rule',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './rule.component.html',
styleUrls: ['./rule.component.scss']
styleUrls: ['./rule.component.scss'],
standalone: false
})
export class RuleComponent implements OnInit {
@Input() hasPermissionToUpdateUserSettings: boolean;

3
apps/client/src/app/components/rules/rules.component.ts

@ -16,7 +16,8 @@ import {
selector: 'gf-rules',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './rules.component.html',
styleUrls: ['./rules.component.scss']
styleUrls: ['./rules.component.scss'],
standalone: false
})
export class RulesComponent {
@Input() hasPermissionToUpdateUserSettings: boolean;

3
apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts

@ -8,7 +8,8 @@ import { SubscriptionInterstitialDialogParams } from './interfaces/interfaces';
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'
templateUrl: 'subscription-interstitial-dialog.html',
standalone: false
})
export class SubscriptionInterstitialDialog {
private readonly VARIANTS_COUNT = 2;

3
apps/client/src/app/components/toggle/toggle.component.ts

@ -14,7 +14,8 @@ import { FormControl } from '@angular/forms';
selector: 'gf-toggle',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './toggle.component.html',
styleUrls: ['./toggle.component.scss']
styleUrls: ['./toggle.component.scss'],
standalone: false
})
export class ToggleComponent implements OnChanges {
public static DEFAULT_DATE_RANGE_OPTIONS: ToggleOption[] = [

3
apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts

@ -22,7 +22,8 @@ import { CreateOrUpdateAccessDialogParams } from './interfaces/interfaces';
host: { class: 'h-100' },
selector: 'gf-create-or-update-access-dialog',
styleUrls: ['./create-or-update-access-dialog.scss'],
templateUrl: 'create-or-update-access-dialog.html'
templateUrl: 'create-or-update-access-dialog.html',
standalone: false
})
export class CreateOrUpdateAccessDialog implements OnDestroy {
public accessForm: FormGroup;

3
apps/client/src/app/components/user-account-access/user-account-access.component.ts

@ -24,7 +24,8 @@ import { CreateOrUpdateAccessDialog } from './create-or-update-access-dialog/cre
host: { class: 'has-fab' },
selector: 'gf-user-account-access',
styleUrls: ['./user-account-access.scss'],
templateUrl: './user-account-access.html'
templateUrl: './user-account-access.html',
standalone: false
})
export class UserAccountAccessComponent implements OnDestroy, OnInit {
public accessesGet: Access[];

11
apps/client/src/app/components/user-account-membership/user-account-membership.component.ts

@ -26,7 +26,8 @@ import { catchError, switchMap, takeUntil } from 'rxjs/operators';
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'gf-user-account-membership',
styleUrls: ['./user-account-membership.scss'],
templateUrl: './user-account-membership.html'
templateUrl: './user-account-membership.html',
standalone: false
})
export class UserAccountMembershipComponent implements OnDestroy {
public baseCurrency: string;
@ -163,8 +164,9 @@ export class UserAccountMembershipComponent implements OnDestroy {
}
public onRedeemCoupon() {
let couponCode = prompt($localize`Please enter your coupon code:`);
couponCode = couponCode?.trim();
this.notificationService.prompt({
confirmFn: (value) => {
const couponCode = value?.trim();
if (couponCode) {
this.dataService
@ -207,6 +209,9 @@ export class UserAccountMembershipComponent implements OnDestroy {
});
});
}
},
title: $localize`Please enter your coupon code.`
});
}
public ngOnDestroy() {

3
apps/client/src/app/components/user-account-settings/user-account-settings.component.ts

@ -32,7 +32,8 @@ import { catchError, takeUntil } from 'rxjs/operators';
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'gf-user-account-settings',
styleUrls: ['./user-account-settings.scss'],
templateUrl: './user-account-settings.html'
templateUrl: './user-account-settings.html',
standalone: false
})
export class UserAccountSettingsComponent implements OnDestroy, OnInit {
public appearancePlaceholder = $localize`Auto`;

3
apps/client/src/app/components/world-map-chart/world-map-chart.component.ts

@ -14,7 +14,8 @@ import svgMap from 'svgmap';
selector: 'gf-world-map-chart',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './world-map-chart.component.html',
styleUrls: ['./world-map-chart.component.scss']
styleUrls: ['./world-map-chart.component.scss'],
standalone: false
})
export class WorldMapChartComponent implements OnChanges, OnDestroy {
@Input() countries: { [code: string]: { name?: string; value: number } };

1
apps/client/src/app/core/notification/alert-dialog/alert-dialog.component.ts

@ -8,7 +8,6 @@ import { IAlertDialogParams } from './interfaces/interfaces';
@Component({
imports: [CommonModule, MatButtonModule, MatDialogModule],
selector: 'gf-alert-dialog',
standalone: true,
styleUrls: ['./alert-dialog.scss'],
templateUrl: './alert-dialog.html'
})

1
apps/client/src/app/core/notification/confirmation-dialog/confirmation-dialog.component.ts

@ -9,7 +9,6 @@ import { IConfirmDialogParams } from './interfaces/interfaces';
@Component({
imports: [CommonModule, MatButtonModule, MatDialogModule],
selector: 'gf-confirmation-dialog',
standalone: true,
styleUrls: ['./confirmation-dialog.scss'],
templateUrl: './confirmation-dialog.html'
})

1
apps/client/src/app/core/notification/prompt-dialog/prompt-dialog.component.ts

@ -16,7 +16,6 @@ import { MatInputModule } from '@angular/material/input';
MatInputModule
],
selector: 'gf-prompt-dialog',
standalone: true,
templateUrl: './prompt-dialog.html'
})
export class GfPromptDialogComponent {

3
apps/client/src/app/directives/file-drop/file-drop.directive.ts

@ -1,7 +1,8 @@
import { Directive, EventEmitter, HostListener, Output } from '@angular/core';
@Directive({
selector: '[gfFileDrop]'
selector: '[gfFileDrop]',
standalone: false
})
export class FileDropDirective {
@Output() filesDropped = new EventEmitter<FileList>();

3
apps/client/src/app/pages/about/about-page.component.ts

@ -12,7 +12,8 @@ import { takeUntil } from 'rxjs/operators';
host: { class: 'page has-tabs' },
selector: 'gf-about-page',
styleUrls: ['./about-page.scss'],
templateUrl: './about-page.html'
templateUrl: './about-page.html',
standalone: false
})
export class AboutPageComponent implements OnDestroy, OnInit {
public deviceType: string;

3
apps/client/src/app/pages/about/changelog/changelog-page.component.ts

@ -4,7 +4,8 @@ import { Subject } from 'rxjs';
@Component({
selector: 'gf-changelog-page',
styleUrls: ['./changelog-page.scss'],
templateUrl: './changelog-page.html'
templateUrl: './changelog-page.html',
standalone: false
})
export class ChangelogPageComponent implements OnDestroy {
private unsubscribeSubject = new Subject<void>();

3
apps/client/src/app/pages/about/license/license-page.component.ts

@ -4,7 +4,8 @@ import { Subject } from 'rxjs';
@Component({
selector: 'gf-license-page',
styleUrls: ['./license-page.scss'],
templateUrl: './license-page.html'
templateUrl: './license-page.html',
standalone: false
})
export class LicensePageComponent implements OnDestroy {
private unsubscribeSubject = new Subject<void>();

3
apps/client/src/app/pages/about/oss-friends/oss-friends-page.component.ts

@ -6,7 +6,8 @@ const ossFriends = require('../../../../assets/oss-friends.json');
@Component({
selector: 'gf-oss-friends-page',
styleUrls: ['./oss-friends-page.scss'],
templateUrl: './oss-friends-page.html'
templateUrl: './oss-friends-page.html',
standalone: false
})
export class OpenSourceSoftwareFriendsPageComponent implements OnDestroy {
public ossFriends = ossFriends.data;

3
apps/client/src/app/pages/about/overview/about-overview-page.component.ts

@ -10,7 +10,8 @@ import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'gf-about-overview-page',
styleUrls: ['./about-overview-page.scss'],
templateUrl: './about-overview-page.html'
templateUrl: './about-overview-page.html',
standalone: false
})
export class AboutOverviewPageComponent implements OnDestroy, OnInit {
public hasPermissionForStatistics: boolean;

3
apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.component.ts

@ -4,7 +4,8 @@ import { Subject } from 'rxjs';
@Component({
selector: 'gf-privacy-policy-page',
styleUrls: ['./privacy-policy-page.scss'],
templateUrl: './privacy-policy-page.html'
templateUrl: './privacy-policy-page.html',
standalone: false
})
export class PrivacyPolicyPageComponent implements OnDestroy {
private unsubscribeSubject = new Subject<void>();

3
apps/client/src/app/pages/accounts/accounts-page.component.ts

@ -25,7 +25,8 @@ import { TransferBalanceDialog } from './transfer-balance/transfer-balance-dialo
host: { class: 'has-fab page' },
selector: 'gf-accounts-page',
styleUrls: ['./accounts-page.scss'],
templateUrl: './accounts-page.html'
templateUrl: './accounts-page.html',
standalone: false
})
export class AccountsPageComponent implements OnDestroy, OnInit {
public accounts: AccountModel[];

3
apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts

@ -28,7 +28,8 @@ import { CreateOrUpdateAccountDialogParams } from './interfaces/interfaces';
selector: 'gf-create-or-update-account-dialog',
changeDetection: ChangeDetectionStrategy.OnPush,
styleUrls: ['./create-or-update-account-dialog.scss'],
templateUrl: 'create-or-update-account-dialog.html'
templateUrl: 'create-or-update-account-dialog.html',
standalone: false
})
export class CreateOrUpdateAccountDialog implements OnDestroy {
public accountForm: FormGroup;

3
apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.component.ts

@ -24,7 +24,8 @@ import { TransferBalanceDialogParams } from './interfaces/interfaces';
selector: 'gf-transfer-balance-dialog',
changeDetection: ChangeDetectionStrategy.OnPush,
styleUrls: ['./transfer-balance-dialog.scss'],
templateUrl: 'transfer-balance-dialog.html'
templateUrl: 'transfer-balance-dialog.html',
standalone: false
})
export class TransferBalanceDialog implements OnDestroy {
public accounts: Account[] = [];

3
apps/client/src/app/pages/admin/admin-page.component.ts

@ -8,7 +8,8 @@ import { Subject } from 'rxjs';
host: { class: 'page has-tabs' },
selector: 'gf-admin-page',
styleUrls: ['./admin-page.scss'],
templateUrl: './admin-page.html'
templateUrl: './admin-page.html',
standalone: false
})
export class AdminPageComponent implements OnDestroy, OnInit {
public deviceType: string;

1
apps/client/src/app/pages/api/api-page.component.ts

@ -21,7 +21,6 @@ import { map, Observable, Subject, takeUntil } from 'rxjs';
host: { class: 'page' },
imports: [CommonModule],
selector: 'gf-api-page',
standalone: true,
styleUrls: ['./api-page.scss'],
templateUrl: './api-page.html'
})

3
apps/client/src/app/pages/auth/auth-page.component.ts

@ -12,7 +12,8 @@ import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'gf-auth-page',
templateUrl: './auth-page.html',
styleUrls: ['./auth-page.scss']
styleUrls: ['./auth-page.scss'],
standalone: false
})
export class AuthPageComponent implements OnDestroy, OnInit {
private unsubscribeSubject = new Subject<void>();

1
apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.component.ts

@ -6,7 +6,6 @@ import { RouterModule } from '@angular/router';
host: { class: 'page' },
imports: [MatButtonModule, RouterModule],
selector: 'gf-hallo-ghostfolio-page',
standalone: true,
templateUrl: './hallo-ghostfolio-page.html'
})
export class HalloGhostfolioPageComponent {

1
apps/client/src/app/pages/blog/2021/07/hello-ghostfolio/hello-ghostfolio-page.component.ts

@ -6,7 +6,6 @@ import { RouterModule } from '@angular/router';
host: { class: 'page' },
imports: [MatButtonModule, RouterModule],
selector: 'gf-hello-ghostfolio-page',
standalone: true,
templateUrl: './hello-ghostfolio-page.html'
})
export class HelloGhostfolioPageComponent {

1
apps/client/src/app/pages/blog/2022/01/first-months-in-open-source/first-months-in-open-source-page.component.ts

@ -6,7 +6,6 @@ import { RouterModule } from '@angular/router';
host: { class: 'page' },
imports: [MatButtonModule, RouterModule],
selector: 'gf-first-months-in-open-source-page',
standalone: true,
templateUrl: './first-months-in-open-source-page.html'
})
export class FirstMonthsInOpenSourcePageComponent {

1
apps/client/src/app/pages/blog/2022/07/ghostfolio-meets-internet-identity/ghostfolio-meets-internet-identity-page.component.ts

@ -6,7 +6,6 @@ import { RouterModule } from '@angular/router';
host: { class: 'page' },
imports: [MatButtonModule, RouterModule],
selector: 'gf-ghostfolio-meets-internet-identity-page',
standalone: true,
templateUrl: './ghostfolio-meets-internet-identity-page.html'
})
export class GhostfolioMeetsInternetIdentityPageComponent {}

1
apps/client/src/app/pages/blog/2022/07/how-do-i-get-my-finances-in-order/how-do-i-get-my-finances-in-order-page.component.ts

@ -6,7 +6,6 @@ import { RouterModule } from '@angular/router';
host: { class: 'page' },
imports: [MatButtonModule, RouterModule],
selector: 'gf-how-do-i-get-my-finances-in-order-page',
standalone: true,
templateUrl: './how-do-i-get-my-finances-in-order-page.html'
})
export class HowDoIGetMyFinancesInOrderPageComponent {

1
apps/client/src/app/pages/blog/2022/08/500-stars-on-github/500-stars-on-github-page.component.ts

@ -6,7 +6,6 @@ import { RouterModule } from '@angular/router';
host: { class: 'page' },
imports: [MatButtonModule, RouterModule],
selector: 'gf-500-stars-on-github-page',
standalone: true,
templateUrl: './500-stars-on-github-page.html'
})
export class FiveHundredStarsOnGitHubPageComponent {

1
apps/client/src/app/pages/blog/2022/10/hacktoberfest-2022/hacktoberfest-2022-page.component.ts

@ -6,7 +6,6 @@ import { RouterModule } from '@angular/router';
host: { class: 'page' },
imports: [MatButtonModule, RouterModule],
selector: 'gf-hacktoberfest-2022-page',
standalone: true,
templateUrl: './hacktoberfest-2022-page.html'
})
export class Hacktoberfest2022PageComponent {}

1
apps/client/src/app/pages/blog/2022/11/black-friday-2022/black-friday-2022-page.component.ts

@ -8,7 +8,6 @@ import { RouterModule } from '@angular/router';
host: { class: 'page' },
imports: [GfPremiumIndicatorComponent, MatButtonModule, RouterModule],
selector: 'gf-black-friday-2022-page',
standalone: true,
templateUrl: './black-friday-2022-page.html'
})
export class BlackFriday2022PageComponent {

1
apps/client/src/app/pages/blog/2022/12/the-importance-of-tracking-your-personal-finances/the-importance-of-tracking-your-personal-finances-page.component.ts

@ -6,7 +6,6 @@ import { RouterModule } from '@angular/router';
host: { class: 'page' },
imports: [MatButtonModule, RouterModule],
selector: 'gf-the-importance-of-tracking-your-personal-finances-page',
standalone: true,
templateUrl: './the-importance-of-tracking-your-personal-finances-page.html'
})
export class TheImportanceOfTrackingYourPersonalFinancesPageComponent {}

1
apps/client/src/app/pages/blog/2023/01/ghostfolio-auf-sackgeld-vorgestellt/ghostfolio-auf-sackgeld-vorgestellt-page.component.ts

@ -6,7 +6,6 @@ import { RouterModule } from '@angular/router';
host: { class: 'page' },
imports: [MatButtonModule, RouterModule],
selector: 'gf-ghostfolio-auf-sackgeld-vorgestellt-page',
standalone: true,
templateUrl: './ghostfolio-auf-sackgeld-vorgestellt-page.html'
})
export class GhostfolioAufSackgeldVorgestelltPageComponent {}

1
apps/client/src/app/pages/blog/2023/02/ghostfolio-meets-umbrel/ghostfolio-meets-umbrel-page.component.ts

@ -6,7 +6,6 @@ import { RouterModule } from '@angular/router';
host: { class: 'page' },
imports: [MatButtonModule, RouterModule],
selector: 'gf-ghostfolio-meets-umbrel-page',
standalone: true,
templateUrl: './ghostfolio-meets-umbrel-page.html'
})
export class GhostfolioMeetsUmbrelPageComponent {}

1
apps/client/src/app/pages/blog/2023/03/1000-stars-on-github/1000-stars-on-github-page.component.ts

@ -6,7 +6,6 @@ import { RouterModule } from '@angular/router';
host: { class: 'page' },
imports: [MatButtonModule, RouterModule],
selector: 'gf-1000-stars-on-github-page',
standalone: true,
templateUrl: './1000-stars-on-github-page.html'
})
export class ThousandStarsOnGitHubPageComponent {

1
apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.component.ts

@ -6,7 +6,6 @@ import { RouterModule } from '@angular/router';
host: { class: 'page' },
imports: [MatButtonModule, RouterModule],
selector: 'gf-unlock-your-financial-potential-with-ghostfolio-page',
standalone: true,
templateUrl: './unlock-your-financial-potential-with-ghostfolio-page.html'
})
export class UnlockYourFinancialPotentialWithGhostfolioPageComponent {

1
apps/client/src/app/pages/blog/2023/07/exploring-the-path-to-fire/exploring-the-path-to-fire-page.component.ts

@ -6,7 +6,6 @@ import { RouterModule } from '@angular/router';
host: { class: 'page' },
imports: [MatButtonModule, RouterModule],
selector: 'gf-exploring-the-path-to-fire-page-page',
standalone: true,
templateUrl: './exploring-the-path-to-fire-page.html'
})
export class ExploringThePathToFirePageComponent {

1
apps/client/src/app/pages/blog/2023/08/ghostfolio-joins-oss-friends/ghostfolio-joins-oss-friends-page.component.ts

@ -6,7 +6,6 @@ import { RouterModule } from '@angular/router';
host: { class: 'page' },
imports: [MatButtonModule, RouterModule],
selector: 'gf-ghostfolio-joins-oss-friends-page',
standalone: true,
templateUrl: './ghostfolio-joins-oss-friends-page.html'
})
export class GhostfolioJoinsOssFriendsPageComponent {

1
apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts

@ -6,7 +6,6 @@ import { RouterModule } from '@angular/router';
host: { class: 'page' },
imports: [MatButtonModule, RouterModule],
selector: 'gf-ghostfolio-2-page',
standalone: true,
templateUrl: './ghostfolio-2-page.html'
})
export class Ghostfolio2PageComponent {

1
apps/client/src/app/pages/blog/2023/09/hacktoberfest-2023/hacktoberfest-2023-page.component.ts

@ -6,7 +6,6 @@ import { RouterModule } from '@angular/router';
host: { class: 'page' },
imports: [MatButtonModule, RouterModule],
selector: 'gf-hacktoberfest-2023-page',
standalone: true,
templateUrl: './hacktoberfest-2023-page.html'
})
export class Hacktoberfest2023PageComponent {

1
apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts

@ -8,7 +8,6 @@ import { RouterModule } from '@angular/router';
host: { class: 'page' },
imports: [GfPremiumIndicatorComponent, MatButtonModule, RouterModule],
selector: 'gf-black-week-2023-page',
standalone: true,
templateUrl: './black-week-2023-page.html'
})
export class BlackWeek2023PageComponent {

1
apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts

@ -6,7 +6,6 @@ import { RouterModule } from '@angular/router';
host: { class: 'page' },
imports: [MatButtonModule, RouterModule],
selector: 'gf-hacktoberfest-2023-debriefing-page',
standalone: true,
templateUrl: './hacktoberfest-2023-debriefing-page.html'
})
export class Hacktoberfest2023DebriefingPageComponent {

1
apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component.ts

@ -6,7 +6,6 @@ import { RouterModule } from '@angular/router';
host: { class: 'page' },
imports: [MatButtonModule, RouterModule],
selector: 'gf-hacktoberfest-2024-page',
standalone: true,
templateUrl: './hacktoberfest-2024-page.html'
})
export class Hacktoberfest2024PageComponent {

1
apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts

@ -8,7 +8,6 @@ import { RouterModule } from '@angular/router';
host: { class: 'page' },
imports: [GfPremiumIndicatorComponent, MatButtonModule, RouterModule],
selector: 'gf-black-weeks-2024-page',
standalone: true,
templateUrl: './black-weeks-2024-page.html'
})
export class BlackWeeks2024PageComponent {

3
apps/client/src/app/pages/blog/blog-page.component.ts

@ -8,7 +8,8 @@ import { Subject } from 'rxjs';
host: { class: 'page' },
selector: 'gf-blog-page',
styleUrls: ['./blog-page.scss'],
templateUrl: './blog-page.html'
templateUrl: './blog-page.html',
standalone: false
})
export class BlogPageComponent implements OnDestroy {
public hasPermissionForSubscription: boolean;

3
apps/client/src/app/pages/faq/faq-page.component.ts

@ -10,7 +10,8 @@ import { Subject } from 'rxjs';
host: { class: 'page has-tabs' },
selector: 'gf-faq-page',
styleUrls: ['./faq-page.scss'],
templateUrl: './faq-page.html'
templateUrl: './faq-page.html',
standalone: false
})
export class FaqPageComponent implements OnDestroy, OnInit {
public deviceType: string;

3
apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts

@ -8,7 +8,8 @@ import { Subject, takeUntil } from 'rxjs';
host: { class: 'page' },
selector: 'gf-faq-overview-page',
styleUrls: ['./faq-overview-page.scss'],
templateUrl: './faq-overview-page.html'
templateUrl: './faq-overview-page.html',
standalone: false
})
export class FaqOverviewPageComponent implements OnDestroy {
public routerLinkFeatures = ['/' + $localize`:snake-case:features`];

3
apps/client/src/app/pages/faq/saas/saas-page.component.ts

@ -8,7 +8,8 @@ import { Subject, takeUntil } from 'rxjs';
host: { class: 'page' },
selector: 'gf-saas-page',
styleUrls: ['./saas-page.scss'],
templateUrl: './saas-page.html'
templateUrl: './saas-page.html',
standalone: false
})
export class SaasPageComponent implements OnDestroy {
public routerLinkMarkets = ['/' + $localize`:snake-case:markets`];

3
apps/client/src/app/pages/faq/self-hosting/self-hosting-page.component.ts

@ -5,7 +5,8 @@ import { Subject } from 'rxjs';
host: { class: 'page' },
selector: 'gf-self-hosting-page',
styleUrls: ['./self-hosting-page.scss'],
templateUrl: './self-hosting-page.html'
templateUrl: './self-hosting-page.html',
standalone: false
})
export class SelfHostingPageComponent implements OnDestroy {
private unsubscribeSubject = new Subject<void>();

1
apps/client/src/app/pages/features/features-page.component.ts

@ -19,7 +19,6 @@ import { Subject, takeUntil } from 'rxjs';
RouterModule
],
selector: 'gf-features-page',
standalone: true,
styleUrls: ['./features-page.scss'],
templateUrl: './features-page.html'
})

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save