Browse Source

Task/improve Angular template type safety in client (#7763)

* feat(client): resolve type errors

* feat(client): enable strict safe navigation types

* feat(client): resolve type errors

* feat(ui): resolve type errors

* feat(client): default to default locale
pull/4198/merge
Kenrick Tandrian 1 week ago
committed by GitHub
parent
commit
fd1908f9a0
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 8
      apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html
  2. 4
      apps/client/src/app/components/admin-settings/admin-settings.component.html
  3. 3
      apps/client/src/app/components/admin-settings/admin-settings.component.ts
  4. 3
      apps/client/src/app/components/home-holdings/home-holdings.component.ts
  5. 6
      apps/client/src/app/components/home-holdings/home-holdings.html
  6. 2
      apps/client/src/app/components/home-watchlist/home-watchlist.component.ts
  7. 2
      apps/client/src/app/components/home-watchlist/home-watchlist.html
  8. 3
      apps/client/src/app/components/markets/markets.component.ts
  9. 2
      apps/client/src/app/components/markets/markets.html
  10. 2
      apps/client/src/app/components/portfolio-performance/portfolio-performance.component.html
  11. 8
      apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html
  12. 3
      apps/client/src/app/pages/accounts/accounts-page.component.ts
  13. 4
      apps/client/src/app/pages/accounts/accounts-page.html
  14. 2
      apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts
  15. 2
      apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html
  16. 8
      apps/client/src/app/pages/portfolio/allocations/allocations-page.html
  17. 2
      apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html
  18. 2
      apps/client/tsconfig.json
  19. 2
      libs/ui/src/lib/benchmark/benchmark-detail-dialog/benchmark-detail-dialog.html
  20. 8
      libs/ui/src/lib/line-chart/line-chart.component.ts

8
apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html

@ -71,10 +71,10 @@
type="button"
[disabled]="
!canDeleteAssetProfile({
activitiesCount: assetProfile?.activitiesCount,
activitiesCount: assetProfile?.activitiesCount ?? 0,
isBenchmark: isBenchmark,
symbol: data.symbol,
watchedByCount: assetProfile?.watchedByCount
watchedByCount: assetProfile?.watchedByCount ?? 0
})
"
(click)="
@ -272,8 +272,8 @@
>
</div>
@if (
assetProfile?.countries?.length > 0 ||
assetProfile?.sectors?.length > 0
(assetProfile?.countries?.length ?? 0) > 0 ||
(assetProfile?.sectors?.length ?? 0) > 0
) {
@if (
assetProfile?.countries?.length === 1 &&

4
apps/client/src/app/components/admin-settings/admin-settings.component.html

@ -230,13 +230,13 @@
<div class="mb-5 row">
<div class="col">
<h2 class="text-center" i18n>Platforms</h2>
<gf-admin-platform [locale]="user?.settings?.locale" />
<gf-admin-platform [locale]="user?.settings?.locale ?? DEFAULT_LOCALE" />
</div>
</div>
<div class="row">
<div class="col">
<h2 class="text-center" i18n>Tags</h2>
<gf-admin-tag [locale]="user?.settings?.locale" />
<gf-admin-tag [locale]="user?.settings?.locale ?? DEFAULT_LOCALE" />
</div>
</div>
</div>

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

@ -3,6 +3,7 @@ import { GfAdminTagComponent } from '@ghostfolio/client/components/admin-tag/adm
import { GfDataProviderStatusComponent } from '@ghostfolio/client/components/data-provider-status/data-provider-status.component';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import {
DEFAULT_LOCALE,
E_MAIL_LINE_BREAK,
PROPERTY_API_KEY_GHOSTFOLIO
} from '@ghostfolio/common/config';
@ -98,6 +99,8 @@ export class GfAdminSettingsComponent implements OnInit {
public pricingUrl: string;
public user: User;
protected readonly DEFAULT_LOCALE = DEFAULT_LOCALE;
public constructor(
private adminService: AdminService,
private changeDetectorRef: ChangeDetectorRef,

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

@ -1,4 +1,5 @@
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { DEFAULT_LOCALE } from '@ghostfolio/common/config';
import {
AssetProfileIdentifier,
PortfolioPosition,
@ -50,6 +51,8 @@ import { DeviceDetectorService } from 'ngx-device-detector';
export class GfHomeHoldingsComponent implements OnInit {
public static DEFAULT_HOLDINGS_VIEW_MODE: HoldingsViewMode = 'TABLE';
protected readonly DEFAULT_LOCALE = DEFAULT_LOCALE;
protected deviceType: string;
protected hasPermissionToAccessHoldingsChart: boolean;
protected hasPermissionToCreateActivity: boolean;

6
apps/client/src/app/components/home-holdings/home-holdings.html

@ -37,11 +37,11 @@
}
<div [class.d-none]="holdingsViewMode !== 'TABLE'">
<gf-holdings-table
[holdings]="holdings"
[locale]="user?.settings?.locale"
[holdings]="holdings ?? []"
[locale]="user?.settings?.locale ?? DEFAULT_LOCALE"
(holdingClicked)="onHoldingClicked($event)"
/>
@if (hasPermissionToCreateActivity && holdings?.length > 0) {
@if (hasPermissionToCreateActivity && (holdings?.length ?? 0) > 0) {
<div class="text-center">
<a
class="mt-3"

2
apps/client/src/app/components/home-watchlist/home-watchlist.component.ts

@ -44,6 +44,8 @@ import { CreateWatchlistItemDialogParams } from './create-watchlist-item-dialog/
templateUrl: './home-watchlist.html'
})
export class GfHomeWatchlistComponent implements OnInit {
protected readonly DEFAULT_LOCALE = DEFAULT_LOCALE;
protected hasPermissionToCreateWatchlistItem: boolean;
protected hasPermissionToDeleteWatchlistItem: boolean;
protected user: User;

2
apps/client/src/app/components/home-watchlist/home-watchlist.html

@ -13,7 +13,7 @@
[benchmarks]="watchlist"
[deviceType]="deviceType()"
[hasPermissionToDeleteItem]="hasPermissionToDeleteWatchlistItem"
[locale]="user?.settings?.locale || undefined"
[locale]="user?.settings?.locale ?? DEFAULT_LOCALE"
[showIcon]="true"
[user]="user"
(itemDeleted)="onWatchlistItemDeleted($event)"

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

@ -1,4 +1,5 @@
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { DEFAULT_LOCALE } from '@ghostfolio/common/config';
import { resetHours } from '@ghostfolio/common/helper';
import {
Benchmark,
@ -43,6 +44,8 @@ import { DeviceDetectorService } from 'ngx-device-detector';
templateUrl: './markets.html'
})
export class GfMarketsComponent implements OnInit {
protected readonly DEFAULT_LOCALE = DEFAULT_LOCALE;
protected readonly benchmarks = signal<Benchmark[] | undefined>(undefined);
protected readonly deviceType = computed(

2
apps/client/src/app/components/markets/markets.html

@ -52,7 +52,7 @@
<gf-benchmark
[benchmarks]="benchmarks()"
[deviceType]="deviceType()"
[locale]="user?.settings?.locale || undefined"
[locale]="user?.settings?.locale ?? DEFAULT_LOCALE"
[showSymbol]="false"
[user]="user"
/>

2
apps/client/src/app/components/portfolio-performance/portfolio-performance.component.html

@ -1,7 +1,7 @@
<div class="container p-0">
<div class="no-gutters row">
<div class="status-container text-muted text-right">
@if (errors()?.length > 0 && !isLoading()) {
@if ((errors()?.length ?? 0) > 0 && !isLoading()) {
<ion-icon
i18n-title
name="time-outline"

8
apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html

@ -183,7 +183,7 @@
<ng-container i18n>Holdings</ng-container>
@if (
!hasImpersonationId &&
summary?.totalValueInBaseCurrency > 0 &&
(summary?.totalValueInBaseCurrency ?? 0) > 0 &&
user?.settings?.isExperimentalFeatures
) {
<gf-value
@ -261,7 +261,7 @@
<ng-container i18n>Cash</ng-container>
@if (
!hasImpersonationId &&
summary?.totalValueInBaseCurrency > 0 &&
(summary?.totalValueInBaseCurrency ?? 0) > 0 &&
user?.settings?.isExperimentalFeatures
) {
<gf-value
@ -324,7 +324,7 @@
<ng-container i18n>Excluded from Analysis</ng-container>
@if (
!hasImpersonationId &&
summary?.totalValueInBaseCurrency > 0 &&
(summary?.totalValueInBaseCurrency ?? 0) > 0 &&
user?.settings?.isExperimentalFeatures
) {
<gf-value
@ -412,7 +412,7 @@
<ng-container i18n>Emergency Fund</ng-container>
@if (
!hasImpersonationId &&
summary?.totalValueInBaseCurrency > 0 &&
(summary?.totalValueInBaseCurrency ?? 0) > 0 &&
user?.settings?.isExperimentalFeatures
) {
<gf-value

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

@ -1,5 +1,6 @@
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { DEFAULT_LOCALE } from '@ghostfolio/common/config';
import { TransferBalanceDto } from '@ghostfolio/common/dtos';
import { AccountsResponse, User } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
@ -39,6 +40,8 @@ import { GfTransferBalanceDialogComponent } from './transfer-balance/transfer-ba
templateUrl: './accounts-page.html'
})
export class GfAccountsPageComponent implements OnInit {
protected readonly DEFAULT_LOCALE = DEFAULT_LOCALE;
protected accounts: AccountWithValue[] | undefined;
protected activitiesCount = 0;
protected hasPermissionToCreateAccount: boolean;

4
apps/client/src/app/pages/accounts/accounts-page.html

@ -3,12 +3,12 @@
<div class="col">
<h1 class="d-none d-sm-block h3 mb-4 text-center" i18n>Accounts</h1>
<gf-accounts-table
[accounts]="accounts"
[accounts]="accounts ?? []"
[activitiesCount]="activitiesCount"
[baseCurrency]="user?.settings?.baseCurrency"
[hasPermissionToDeleteAccount]="hasPermissionToDeleteAccount"
[hasPermissionToUpdateAccount]="hasPermissionToUpdateAccount"
[locale]="user?.settings?.locale"
[locale]="user?.settings?.locale ?? DEFAULT_LOCALE"
[showActions]="
(hasPermissionToDeleteAccount || hasPermissionToUpdateAccount) &&
!user.settings.isRestrictedView

2
apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts

@ -79,6 +79,8 @@ import { ActivityType } from './types/activity-type.type';
templateUrl: 'create-or-update-activity-dialog.html'
})
export class GfCreateOrUpdateActivityDialogComponent {
protected readonly DEFAULT_LOCALE = DEFAULT_LOCALE;
protected activityForm: FormGroup;
protected readonly assetClassOptions: AssetClassSelectorOption[] =

2
apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html

@ -309,7 +309,7 @@
<gf-value
class="flex-grow-1"
[isCurrency]="true"
[locale]="data.user?.settings?.locale"
[locale]="data.user?.settings?.locale ?? DEFAULT_LOCALE"
[unit]="
activityForm.get('currencyOfUnitPrice')?.value ??
data.user?.settings?.baseCurrency

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

@ -23,9 +23,11 @@
<mat-progress-bar
mode="determinate"
[title]="`${(
portfolioDetails?.summary?.filteredValueInPercentage * 100
(portfolioDetails?.summary?.filteredValueInPercentage ?? 0) * 100
).toFixed(2)}%`"
[value]="portfolioDetails?.summary?.filteredValueInPercentage * 100"
[value]="
(portfolioDetails?.summary?.filteredValueInPercentage ?? 0) * 100
"
/>
</mat-card-content>
</mat-card>
@ -236,7 +238,7 @@
>Other Markets</gf-value
>
</div>
@if (markets?.[UNKNOWN_KEY]?.valueInPercentage > 0) {
@if ((markets?.[UNKNOWN_KEY]?.valueInPercentage ?? 0) > 0) {
<div class="col-xs-12 col-md my-2">
<gf-value
i18n

2
apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html

@ -81,7 +81,7 @@
<button
color="secondary"
mat-flat-button
[cdkCopyToClipboard]="accessToken"
[cdkCopyToClipboard]="accessToken ?? ''"
(click)="enableCreateAccountButton()"
>
<ion-icon class="mr-1" name="copy-outline" />

2
apps/client/tsconfig.json

@ -25,7 +25,7 @@
"strictLiteralTypes": true,
"strictNullInputTypes": true,
"strictOutputEventTypes": true,
"strictSafeNavigationTypes": false,
"strictSafeNavigationTypes": true,
// TODO: Enable stricter rules for this project
"strictTemplates": false
},

2
libs/ui/src/lib/benchmark/benchmark-detail-dialog/benchmark-detail-dialog.html

@ -1,7 +1,7 @@
<gf-dialog-header
position="center"
[deviceType]="data.deviceType"
[title]="assetProfile?.name ?? assetProfile?.symbol"
[title]="assetProfile.name ?? assetProfile.symbol ?? ''"
(closeButtonClicked)="onClose()"
/>

8
libs/ui/src/lib/line-chart/line-chart.component.ts

@ -4,7 +4,11 @@ import {
getValueAxisOptions,
getVerticalHoverLinePlugin
} from '@ghostfolio/common/chart-helper';
import { primaryColorRgb, secondaryColorRgb } from '@ghostfolio/common/config';
import {
DEFAULT_COLOR_SCHEME,
primaryColorRgb,
secondaryColorRgb
} from '@ghostfolio/common/config';
import { getBackgroundColor, getLocale } from '@ghostfolio/common/helper';
import { LineChartItem } from '@ghostfolio/common/interfaces';
import { ColorScheme } from '@ghostfolio/common/types';
@ -52,7 +56,7 @@ export class GfLineChartComponent
{
@Input() benchmarkDataItems: LineChartItem[] = [];
@Input() benchmarkLabel = '';
@Input() colorScheme: ColorScheme;
@Input() colorScheme: ColorScheme = DEFAULT_COLOR_SCHEME;
@Input() currency: string;
@Input() historicalDataItems: LineChartItem[];
@Input() isAnimated = false;

Loading…
Cancel
Save