Attila Cseh 1 day ago
committed by GitHub
parent
commit
b71dabcdbd
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 3
      apps/client/eslint.config.cjs
  3. 4
      apps/client/src/app/app.component.ts
  4. 8
      apps/client/src/app/components/admin-settings/admin-settings.component.scss
  5. 2
      apps/client/src/app/components/home-holdings/home-holdings.scss
  6. 2
      apps/client/src/app/components/home-watchlist/create-watchlist-item-dialog/create-watchlist-item-dialog.component.ts
  7. 2
      apps/client/src/app/components/home-watchlist/home-watchlist.component.ts
  8. 2
      apps/client/src/app/components/markets/markets.component.ts
  9. 2
      apps/client/src/app/components/user-account-access/user-account-access.component.ts
  10. 2
      apps/client/src/app/components/user-account-settings/user-account-settings.component.ts
  11. 4
      apps/client/src/app/pages/portfolio/allocations/allocations-page.scss
  12. 3
      apps/client/src/app/pages/user-account/user-account-page.component.ts
  13. 38
      apps/client/src/styles.scss
  14. 6
      apps/client/src/styles/theme.scss
  15. 12
      libs/ui/.storybook/main.js
  16. 3
      libs/ui/eslint.config.cjs
  17. 3
      libs/ui/src/lib/activities-filter/activities-filter.component.ts
  18. 9
      libs/ui/src/lib/activities-table/activities-table.component.ts
  19. 4
      libs/ui/src/lib/activity-type/activity-type.component.ts
  20. 11
      libs/ui/src/lib/assistant/assistant-list-item/assistant-list-item.component.ts
  21. 8
      libs/ui/src/lib/assistant/assistant.component.ts
  22. 4
      libs/ui/src/lib/benchmark/benchmark-detail-dialog/benchmark-detail-dialog.component.ts
  23. 6
      libs/ui/src/lib/benchmark/benchmark.component.ts
  24. 9
      libs/ui/src/lib/currency-selector/currency-selector.component.ts
  25. 5
      libs/ui/src/lib/holdings-table/holdings-table.component.ts
  26. 3
      libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts
  27. 9
      libs/ui/src/lib/shared/abstract-mat-form-field.ts
  28. 9
      libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.ts
  29. 3
      libs/ui/src/lib/top-holdings/top-holdings.component.ts
  30. 2
      libs/ui/src/lib/value/value.component.ts
  31. 57
      nx.json
  32. 13212
      package-lock.json
  33. 90
      package.json

1
CHANGELOG.md

@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Improved the language localization for Catalan (`ca`) - Improved the language localization for Catalan (`ca`)
- Upgraded `countries-and-timezones` from version `3.7.2` to `3.8.0` - Upgraded `countries-and-timezones` from version `3.7.2` to `3.8.0`
- Upgraded `Nx` from version `21.1.2` to `21.2.4`
## 2.183.0 - 2025-07-20 ## 2.183.0 - 2025-07-20

3
apps/client/eslint.config.cjs

@ -30,7 +30,8 @@ module.exports = [
prefix: 'gf', prefix: 'gf',
style: 'camelCase' style: 'camelCase'
} }
] ],
'@angular-eslint/prefer-inject': 'off'
} }
}, },
{ {

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

@ -6,7 +6,6 @@ import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { internalRoutes, publicRoutes } from '@ghostfolio/common/routes/routes'; import { internalRoutes, publicRoutes } from '@ghostfolio/common/routes/routes';
import { ColorScheme } from '@ghostfolio/common/types'; import { ColorScheme } from '@ghostfolio/common/types';
import { DOCUMENT } from '@angular/common';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
ChangeDetectorRef, ChangeDetectorRef,
@ -14,7 +13,8 @@ import {
HostBinding, HostBinding,
Inject, Inject,
OnDestroy, OnDestroy,
OnInit OnInit,
DOCUMENT
} from '@angular/core'; } from '@angular/core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';

8
apps/client/src/app/components/admin-settings/admin-settings.component.scss

@ -10,7 +10,7 @@
} }
.mat-mdc-card { .mat-mdc-card {
--mdc-outlined-card-container-color: whitesmoke; --mat-card-outlined-container-color: whitesmoke;
.mat-mdc-card-actions { .mat-mdc-card-actions {
min-height: 0; min-height: 0;
@ -18,8 +18,8 @@
} }
.mat-mdc-progress-bar { .mat-mdc-progress-bar {
--mdc-linear-progress-active-indicator-height: 0.5rem; --mat-progress-bar-active-indicator-height: 0.5rem;
--mdc-linear-progress-track-height: 0.5rem; --mat-progress-bar-track-height: 0.5rem;
border-radius: 0.25rem; border-radius: 0.25rem;
::ng-deep { ::ng-deep {
@ -32,6 +32,6 @@
:host-context(.theme-dark) { :host-context(.theme-dark) {
.mat-mdc-card { .mat-mdc-card {
--mdc-outlined-card-container-color: #222222; --mat-card-outlined-container-color: #222222;
} }
} }

2
apps/client/src/app/components/home-holdings/home-holdings.scss

@ -3,7 +3,7 @@
.mat-button-toggle-group { .mat-button-toggle-group {
.mat-button-toggle-appearance-standard { .mat-button-toggle-appearance-standard {
--mat-standard-button-toggle-height: 1.5rem; --mat-button-toggle-height: 1.5rem;
} }
} }
} }

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

@ -1,6 +1,5 @@
import { GfSymbolAutocompleteComponent } from '@ghostfolio/ui/symbol-autocomplete'; import { GfSymbolAutocompleteComponent } from '@ghostfolio/ui/symbol-autocomplete';
import { CommonModule } from '@angular/common';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
Component, Component,
@ -26,7 +25,6 @@ import { Subject } from 'rxjs';
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'h-100' }, host: { class: 'h-100' },
imports: [ imports: [
CommonModule,
FormsModule, FormsModule,
GfSymbolAutocompleteComponent, GfSymbolAutocompleteComponent,
MatButtonModule, MatButtonModule,

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

@ -11,7 +11,6 @@ import { BenchmarkTrend } from '@ghostfolio/common/types';
import { GfBenchmarkComponent } from '@ghostfolio/ui/benchmark'; import { GfBenchmarkComponent } from '@ghostfolio/ui/benchmark';
import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator';
import { CommonModule } from '@angular/common';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
ChangeDetectorRef, ChangeDetectorRef,
@ -36,7 +35,6 @@ import { CreateWatchlistItemDialogParams } from './create-watchlist-item-dialog/
@Component({ @Component({
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ imports: [
CommonModule,
GfBenchmarkComponent, GfBenchmarkComponent,
GfPremiumIndicatorComponent, GfPremiumIndicatorComponent,
IonIcon, IonIcon,

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

@ -14,7 +14,6 @@ import { FearAndGreedIndexMode } from '@ghostfolio/common/types';
import { GfBenchmarkComponent } from '@ghostfolio/ui/benchmark'; import { GfBenchmarkComponent } from '@ghostfolio/ui/benchmark';
import { GfLineChartComponent } from '@ghostfolio/ui/line-chart'; import { GfLineChartComponent } from '@ghostfolio/ui/line-chart';
import { CommonModule } from '@angular/common';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
ChangeDetectorRef, ChangeDetectorRef,
@ -30,7 +29,6 @@ import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ imports: [
CommonModule,
GfBenchmarkComponent, GfBenchmarkComponent,
GfFearAndGreedIndexModule, GfFearAndGreedIndexModule,
GfLineChartComponent, GfLineChartComponent,

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

@ -9,7 +9,6 @@ import { Access, User } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator';
import { CommonModule } from '@angular/common';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
ChangeDetectorRef, ChangeDetectorRef,
@ -38,7 +37,6 @@ import { GfCreateOrUpdateAccessDialogModule } from './create-or-update-access-di
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'has-fab' }, host: { class: 'has-fab' },
imports: [ imports: [
CommonModule,
GfAccessTableComponent, GfAccessTableComponent,
GfCreateOrUpdateAccessDialogModule, GfCreateOrUpdateAccessDialogModule,
GfPremiumIndicatorComponent, GfPremiumIndicatorComponent,

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

@ -13,7 +13,6 @@ import { downloadAsFile } from '@ghostfolio/common/helper';
import { User } from '@ghostfolio/common/interfaces'; import { User } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { CommonModule } from '@angular/common';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
ChangeDetectorRef, ChangeDetectorRef,
@ -50,7 +49,6 @@ import { catchError, takeUntil } from 'rxjs/operators';
@Component({ @Component({
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ imports: [
CommonModule,
FormsModule, FormsModule,
IonIcon, IonIcon,
MatButtonModule, MatButtonModule,

4
apps/client/src/app/pages/portfolio/allocations/allocations-page.scss

@ -31,8 +31,8 @@
} }
.mat-mdc-progress-bar { .mat-mdc-progress-bar {
--mdc-linear-progress-active-indicator-height: 0.5rem; --mat-progress-bar-active-indicator-height: 0.5rem;
--mdc-linear-progress-track-height: 0.5rem; --mat-progress-bar-track-height: 0.5rem;
border-radius: 0.25rem; border-radius: 0.25rem;
::ng-deep { ::ng-deep {

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

@ -2,7 +2,6 @@ import { UserService } from '@ghostfolio/client/services/user/user.service';
import { TabConfiguration, User } from '@ghostfolio/common/interfaces'; import { TabConfiguration, User } from '@ghostfolio/common/interfaces';
import { internalRoutes } from '@ghostfolio/common/routes/routes'; import { internalRoutes } from '@ghostfolio/common/routes/routes';
import { CommonModule } from '@angular/common';
import { import {
ChangeDetectorRef, ChangeDetectorRef,
Component, Component,
@ -20,7 +19,7 @@ import { Subject, takeUntil } from 'rxjs';
@Component({ @Component({
host: { class: 'page has-tabs' }, host: { class: 'page has-tabs' },
imports: [CommonModule, IonIcon, MatTabsModule, RouterModule], imports: [IonIcon, MatTabsModule, RouterModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA], schemas: [CUSTOM_ELEMENTS_SCHEMA],
selector: 'gf-user-account-page', selector: 'gf-user-account-page',
styleUrls: ['./user-account-page.scss'], styleUrls: ['./user-account-page.scss'],

38
apps/client/src/styles.scss

@ -237,10 +237,10 @@ body {
} }
.mat-mdc-dialog-container { .mat-mdc-dialog-container {
--mdc-dialog-container-color: var(--dark-background); --mat-dialog-container-color: var(--dark-background);
.mdc-dialog__content { .mdc-dialog__content {
--mdc-dialog-supporting-text-color: rgba(var(--light-primary-text)); --mat-dialog-supporting-text-color: rgba(var(--light-primary-text));
} }
} }
@ -252,13 +252,13 @@ body {
} }
.mat-mdc-card { .mat-mdc-card {
--mdc-elevated-card-container-color: var(--dark-background); --mat-card-elevated-container-color: var(--dark-background);
--mdc-outlined-card-container-color: var(--dark-background); --mat-card-outlined-container-color: var(--dark-background);
} }
.mat-mdc-fab { .mat-mdc-fab {
&.mat-primary { &.mat-primary {
--mdc-fab-icon-color: rgba(var(--dark-primary-text)); --mat-fab-icon-color: rgba(var(--dark-primary-text));
--mat-mdc-fab-color: rgba(var(--dark-primary-text)); --mat-mdc-fab-color: rgba(var(--dark-primary-text));
} }
} }
@ -270,16 +270,14 @@ body {
.mdc-button { .mdc-button {
&.mat-accent, &.mat-accent,
&.mat-primary { &.mat-primary {
--mdc-filled-button-label-text-color: rgba(var(--dark-primary-text)); --mat-button-filled-label-text-color: rgba(var(--dark-primary-text));
} }
} }
.page { .page {
&.has-tabs { &.has-tabs {
.mat-mdc-tab-nav-bar { .mat-mdc-tab-nav-bar {
--mat-tab-header-inactive-label-text-color: rgba( --mat-tab-inactive-label-text-color: rgba(var(--light-primary-text));
var(--light-primary-text)
);
} }
@media (min-width: 576px) { @media (min-width: 576px) {
@ -430,7 +428,7 @@ ngx-skeleton-loader {
.mat-mdc-dialog-container { .mat-mdc-dialog-container {
.mdc-dialog__content { .mdc-dialog__content {
--mdc-dialog-supporting-text-color: rgba(var(--dark-primary-text)); --mat-dialog-supporting-text-color: rgba(var(--dark-primary-text));
} }
} }
@ -445,7 +443,7 @@ ngx-skeleton-loader {
color: var(--mat-mdc-fab-color, inherit) !important; color: var(--mat-mdc-fab-color, inherit) !important;
&.mat-primary { &.mat-primary {
--mdc-fab-icon-color: rgba(var(--light-primary-text)); --mat-fab-icon-color: rgba(var(--light-primary-text));
--mat-mdc-fab-color: rgba(var(--light-primary-text)); --mat-mdc-fab-color: rgba(var(--light-primary-text));
} }
} }
@ -507,7 +505,7 @@ ngx-skeleton-loader {
.mdc-button { .mdc-button {
&.mat-accent, &.mat-accent,
&.mat-primary { &.mat-primary {
--mdc-filled-button-label-text-color: rgba(var(--light-primary-text)); --mat-button-filled-label-text-color: rgba(var(--light-primary-text));
} }
} }
@ -557,12 +555,10 @@ ngx-skeleton-loader {
} }
.mat-mdc-tab-nav-bar { .mat-mdc-tab-nav-bar {
--mat-tab-header-active-focus-indicator-color: transparent; --mat-tab-active-focus-indicator-color: transparent;
--mat-tab-header-active-hover-indicator-color: transparent; --mat-tab-active-hover-indicator-color: transparent;
--mat-tab-header-inactive-label-text-color: rgba( --mat-tab-inactive-label-text-color: rgba(var(--dark-primary-text));
var(--dark-primary-text) --mat-tab-active-indicator-color: transparent;
);
--mdc-tab-indicator-active-indicator-color: transparent;
} }
.mat-mdc-tab-nav-panel { .mat-mdc-tab-nav-panel {
@ -571,7 +567,7 @@ ngx-skeleton-loader {
@media (max-width: 575.98px) { @media (max-width: 575.98px) {
.mat-mdc-tab-link { .mat-mdc-tab-link {
--mdc-secondary-navigation-tab-container-height: 3rem; --mat-tab-container-height: 3rem;
} }
} }
@ -582,8 +578,8 @@ ngx-skeleton-loader {
background-color: rgba(var(--palette-foreground-base), 0.02); background-color: rgba(var(--palette-foreground-base), 0.02);
padding: 2rem 0; padding: 2rem 0;
width: 14rem; width: 14rem;
--mat-tab-header-label-text-tracking: normal; --mat-tab-label-text-tracking: normal;
--mdc-secondary-navigation-tab-container-height: 2rem; --mat-tab-container-height: 2rem;
.mat-mdc-tab-links { .mat-mdc-tab-links {
flex-direction: column; flex-direction: column;

6
apps/client/src/styles/theme.scss

@ -116,7 +116,7 @@ $gf-theme-dark: mat.m2-define-dark-theme(
--gf-theme-secondary-500-rgb: 78, 208, 94; --gf-theme-secondary-500-rgb: 78, 208, 94;
--mat-dialog-container-small-max-width: 96vw; --mat-dialog-container-small-max-width: 96vw;
--mdc-filled-button-label-text-tracking: normal; --mat-button-filled-label-text-tracking: normal;
--mdc-outlined-button-label-text-tracking: normal; --mat-button-outlined-label-text-tracking: normal;
--mdc-text-button-label-text-tracking: normal; --mat-button-text-label-text-tracking: normal;
} }

12
libs/ui/.storybook/main.js

@ -1,8 +1,12 @@
import { createRequire } from 'node:module';
import { dirname, join } from 'node:path';
const require = createRequire(import.meta.url);
/** @type {import('@storybook/angular').StorybookConfig} */ /** @type {import('@storybook/angular').StorybookConfig} */
const config = { const config = {
addons: ['@storybook/addon-essentials'], addons: [getAbsolutePath('@storybook/addon-docs')],
framework: { framework: {
name: '@storybook/angular', name: getAbsolutePath('@storybook/angular'),
options: {} options: {}
}, },
staticDirs: [ staticDirs: [
@ -19,3 +23,7 @@ export default config;
// To customize your webpack configuration you can use the webpackFinal field. // To customize your webpack configuration you can use the webpackFinal field.
// Check https://storybook.js.org/docs/react/builders/webpack#extending-storybooks-webpack-config // Check https://storybook.js.org/docs/react/builders/webpack#extending-storybooks-webpack-config
// and https://nx.dev/packages/storybook/documents/custom-builder-configs // and https://nx.dev/packages/storybook/documents/custom-builder-configs
function getAbsolutePath(value) {
return dirname(require.resolve(join(value, 'package.json')));
}

3
libs/ui/eslint.config.cjs

@ -40,7 +40,8 @@ module.exports = [
style: 'kebab-case' style: 'kebab-case'
} }
], ],
'@angular-eslint/prefer-standalone': 'off' '@angular-eslint/prefer-standalone': 'off',
'@angular-eslint/prefer-inject': 'off'
}, },
languageOptions: { languageOptions: {
parserOptions: { parserOptions: {

3
libs/ui/src/lib/activities-filter/activities-filter.component.ts

@ -1,6 +1,5 @@
import { GfSymbolModule } from '@ghostfolio/client/pipes/symbol/symbol.module'; import { GfSymbolModule } from '@ghostfolio/client/pipes/symbol/symbol.module';
import { Filter, FilterGroup } from '@ghostfolio/common/interfaces'; import { Filter, FilterGroup } from '@ghostfolio/common/interfaces';
import { translate } from '@ghostfolio/ui/i18n';
import { COMMA, ENTER } from '@angular/cdk/keycodes'; import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
@ -34,6 +33,8 @@ import { groupBy } from 'lodash';
import { BehaviorSubject, Observable, Subject } from 'rxjs'; import { BehaviorSubject, Observable, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { translate } from '../i18n';
@Component({ @Component({
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ imports: [

9
libs/ui/src/lib/activities-table/activities-table.component.ts

@ -6,10 +6,6 @@ import { DEFAULT_PAGE_SIZE } from '@ghostfolio/common/config';
import { getDateFormatString, getLocale } from '@ghostfolio/common/helper'; import { getDateFormatString, getLocale } from '@ghostfolio/common/helper';
import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces'; import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces';
import { OrderWithAccount } from '@ghostfolio/common/types'; import { OrderWithAccount } from '@ghostfolio/common/types';
import { GfActivityTypeComponent } from '@ghostfolio/ui/activity-type';
import { GfEntityLogoComponent } from '@ghostfolio/ui/entity-logo';
import { GfNoTransactionsInfoComponent } from '@ghostfolio/ui/no-transactions-info';
import { GfValueComponent } from '@ghostfolio/ui/value';
import { SelectionModel } from '@angular/cdk/collections'; import { SelectionModel } from '@angular/cdk/collections';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
@ -62,6 +58,11 @@ import {
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { Subject, Subscription, takeUntil } from 'rxjs'; import { Subject, Subscription, takeUntil } from 'rxjs';
import { GfActivityTypeComponent } from '../activity-type/activity-type.component';
import { GfEntityLogoComponent } from '../entity-logo/entity-logo.component';
import { GfNoTransactionsInfoComponent } from '../no-transactions-info/no-transactions-info.component';
import { GfValueComponent } from '../value/value.component';
@Component({ @Component({
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ imports: [

4
libs/ui/src/lib/activity-type/activity-type.component.ts

@ -1,5 +1,3 @@
import { translate } from '@ghostfolio/ui/i18n';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { import {
CUSTOM_ELEMENTS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA,
@ -20,6 +18,8 @@ import {
hammerOutline hammerOutline
} from 'ionicons/icons'; } from 'ionicons/icons';
import { translate } from '../i18n';
@Component({ @Component({
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule, IonIcon], imports: [CommonModule, IonIcon],

11
libs/ui/src/lib/assistant/assistant-list-item/assistant-list-item.component.ts

@ -1,10 +1,5 @@
import { GfSymbolModule } from '@ghostfolio/client/pipes/symbol/symbol.module'; import { GfSymbolModule } from '@ghostfolio/client/pipes/symbol/symbol.module';
import { internalRoutes } from '@ghostfolio/common/routes/routes'; import { internalRoutes } from '@ghostfolio/common/routes/routes';
import { SearchMode } from '@ghostfolio/ui/assistant/enums/search-mode';
import {
IAssetSearchResultItem,
ISearchResultItem
} from '@ghostfolio/ui/assistant/interfaces/interfaces';
import { FocusableOption } from '@angular/cdk/a11y'; import { FocusableOption } from '@angular/cdk/a11y';
import { import {
@ -21,6 +16,12 @@ import {
} from '@angular/core'; } from '@angular/core';
import { Params, RouterModule } from '@angular/router'; import { Params, RouterModule } from '@angular/router';
import { SearchMode } from '../enums/search-mode';
import {
IAssetSearchResultItem,
ISearchResultItem
} from '../interfaces/interfaces';
@Component({ @Component({
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
imports: [GfSymbolModule, RouterModule], imports: [GfSymbolModule, RouterModule],

8
libs/ui/src/lib/assistant/assistant.component.ts

@ -6,11 +6,8 @@ import { Filter, PortfolioPosition, User } from '@ghostfolio/common/interfaces';
import { InternalRoute } from '@ghostfolio/common/routes/interfaces/internal-route.interface'; import { InternalRoute } from '@ghostfolio/common/routes/interfaces/internal-route.interface';
import { internalRoutes } from '@ghostfolio/common/routes/routes'; import { internalRoutes } from '@ghostfolio/common/routes/routes';
import { DateRange } from '@ghostfolio/common/types'; import { DateRange } from '@ghostfolio/common/types';
import { GfEntityLogoComponent } from '@ghostfolio/ui/entity-logo';
import { translate } from '@ghostfolio/ui/i18n';
import { FocusKeyManager } from '@angular/cdk/a11y'; import { FocusKeyManager } from '@angular/cdk/a11y';
import { CommonModule } from '@angular/common';
import { import {
CUSTOM_ELEMENTS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA,
ChangeDetectionStrategy, ChangeDetectionStrategy,
@ -63,6 +60,8 @@ import {
tap tap
} from 'rxjs/operators'; } from 'rxjs/operators';
import { GfEntityLogoComponent } from '../entity-logo/entity-logo.component';
import { translate } from '../i18n';
import { GfAssistantListItemComponent } from './assistant-list-item/assistant-list-item.component'; import { GfAssistantListItemComponent } from './assistant-list-item/assistant-list-item.component';
import { SearchMode } from './enums/search-mode'; import { SearchMode } from './enums/search-mode';
import { import {
@ -74,7 +73,6 @@ import {
@Component({ @Component({
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ imports: [
CommonModule,
FormsModule, FormsModule,
GfAssistantListItemComponent, GfAssistantListItemComponent,
GfEntityLogoComponent, GfEntityLogoComponent,
@ -529,7 +527,7 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
} }
public onChangeDateRange(dateRangeString: string) { public onChangeDateRange(dateRangeString: string) {
this.dateRangeChanged.emit(dateRangeString as DateRange); this.dateRangeChanged.emit(dateRangeString);
} }
public onCloseAssistant() { public onCloseAssistant() {

4
libs/ui/src/lib/benchmark/benchmark-detail-dialog/benchmark-detail-dialog.component.ts

@ -6,8 +6,6 @@ import {
AdminMarketDataDetails, AdminMarketDataDetails,
LineChartItem LineChartItem
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { GfLineChartComponent } from '@ghostfolio/ui/line-chart';
import { GfValueComponent } from '@ghostfolio/ui/value';
import { import {
CUSTOM_ELEMENTS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA,
@ -27,6 +25,8 @@ import { format } from 'date-fns';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { GfLineChartComponent } from '../../line-chart/line-chart.component';
import { GfValueComponent } from '../../value/value.component';
import { BenchmarkDetailDialogParams } from './interfaces/interfaces'; import { BenchmarkDetailDialogParams } from './interfaces/interfaces';
@Component({ @Component({

6
libs/ui/src/lib/benchmark/benchmark.component.ts

@ -6,9 +6,6 @@ import {
Benchmark, Benchmark,
User User
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { translate } from '@ghostfolio/ui/i18n';
import { GfTrendIndicatorComponent } from '@ghostfolio/ui/trend-indicator';
import { GfValueComponent } from '@ghostfolio/ui/value';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { import {
@ -35,6 +32,9 @@ import { get, isNumber } from 'lodash';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { Subject, takeUntil } from 'rxjs'; import { Subject, takeUntil } from 'rxjs';
import { translate } from '../i18n';
import { GfTrendIndicatorComponent } from '../trend-indicator/trend-indicator.component';
import { GfValueComponent } from '../value/value.component';
import { GfBenchmarkDetailDialogComponent } from './benchmark-detail-dialog/benchmark-detail-dialog.component'; import { GfBenchmarkDetailDialogComponent } from './benchmark-detail-dialog/benchmark-detail-dialog.component';
import { BenchmarkDetailDialogParams } from './benchmark-detail-dialog/interfaces/interfaces'; import { BenchmarkDetailDialogParams } from './benchmark-detail-dialog/interfaces/interfaces';

9
libs/ui/src/lib/currency-selector/currency-selector.component.ts

@ -1,5 +1,3 @@
import { AbstractMatFormField } from '@ghostfolio/ui/shared/abstract-mat-form-field';
import { FocusMonitor } from '@angular/cdk/a11y'; import { FocusMonitor } from '@angular/cdk/a11y';
import { import {
CUSTOM_ELEMENTS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA,
@ -10,7 +8,8 @@ import {
Input, Input,
OnDestroy, OnDestroy,
OnInit, OnInit,
ViewChild ViewChild,
DoCheck
} from '@angular/core'; } from '@angular/core';
import { import {
FormControl, FormControl,
@ -32,6 +31,8 @@ import { MatInput, MatInputModule } from '@angular/material/input';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { map, startWith, takeUntil } from 'rxjs/operators'; import { map, startWith, takeUntil } from 'rxjs/operators';
import { AbstractMatFormField } from '../shared/abstract-mat-form-field';
@Component({ @Component({
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
host: { host: {
@ -58,7 +59,7 @@ import { map, startWith, takeUntil } from 'rxjs/operators';
}) })
export class GfCurrencySelectorComponent export class GfCurrencySelectorComponent
extends AbstractMatFormField<string> extends AbstractMatFormField<string>
implements OnInit, OnDestroy implements OnInit, OnDestroy, DoCheck
{ {
@Input() private currencies: string[] = []; @Input() private currencies: string[] = [];
@Input() private formControlName: string; @Input() private formControlName: string;

5
libs/ui/src/lib/holdings-table/holdings-table.component.ts

@ -4,8 +4,6 @@ import {
AssetProfileIdentifier, AssetProfileIdentifier,
PortfolioPosition PortfolioPosition
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { GfEntityLogoComponent } from '@ghostfolio/ui/entity-logo';
import { GfValueComponent } from '@ghostfolio/ui/value';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { import {
@ -28,6 +26,9 @@ import { AssetSubClass } from '@prisma/client';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { Subject, Subscription } from 'rxjs'; import { Subject, Subscription } from 'rxjs';
import { GfEntityLogoComponent } from '../entity-logo/entity-logo.component';
import { GfValueComponent } from '../value/value.component';
@Component({ @Component({
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ imports: [

3
libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts

@ -6,7 +6,6 @@ import {
PortfolioPosition PortfolioPosition
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { ColorScheme } from '@ghostfolio/common/types'; import { ColorScheme } from '@ghostfolio/common/types';
import { translate } from '@ghostfolio/ui/i18n';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { import {
@ -33,6 +32,8 @@ import { isUUID } from 'class-validator';
import Color from 'color'; import Color from 'color';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { translate } from '../i18n';
const { const {
blue, blue,
cyan, cyan,

9
libs/ui/src/lib/shared/abstract-mat-form-field.ts

@ -17,7 +17,6 @@ import { Subject } from 'rxjs';
template: '', template: '',
standalone: false standalone: false
}) })
// eslint-disable-next-line @angular-eslint/component-class-suffix
export abstract class AbstractMatFormField<T> export abstract class AbstractMatFormField<T>
implements ControlValueAccessor, DoCheck, MatFormFieldControl<T>, OnDestroy implements ControlValueAccessor, DoCheck, MatFormFieldControl<T>, OnDestroy
{ {
@ -35,7 +34,7 @@ export abstract class AbstractMatFormField<T>
protected onChange?: (value: T) => void; protected onChange?: (value: T) => void;
protected onTouched?: () => void; protected onTouched?: () => void;
private static nextId: number = 0; private static nextId = 0;
protected constructor( protected constructor(
protected _elementRef: ElementRef, protected _elementRef: ElementRef,
@ -83,7 +82,7 @@ export abstract class AbstractMatFormField<T>
return !this._value; return !this._value;
} }
public _placeholder: string = ''; public _placeholder = '';
public get placeholder() { public get placeholder() {
return this._placeholder; return this._placeholder;
@ -95,7 +94,7 @@ export abstract class AbstractMatFormField<T>
this.stateChanges.next(); this.stateChanges.next();
} }
public _required: boolean = false; public _required = false;
public get required() { public get required() {
return ( return (
@ -110,7 +109,7 @@ export abstract class AbstractMatFormField<T>
this.stateChanges.next(); this.stateChanges.next();
} }
public _disabled: boolean = false; public _disabled = false;
public get disabled() { public get disabled() {
if (this.ngControl?.disabled !== null) { if (this.ngControl?.disabled !== null) {

9
libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.ts

@ -1,8 +1,6 @@
import { GfSymbolModule } from '@ghostfolio/client/pipes/symbol/symbol.module'; import { GfSymbolModule } from '@ghostfolio/client/pipes/symbol/symbol.module';
import { DataService } from '@ghostfolio/client/services/data.service'; import { DataService } from '@ghostfolio/client/services/data.service';
import { LookupItem } from '@ghostfolio/common/interfaces'; import { LookupItem } from '@ghostfolio/common/interfaces';
import { translate } from '@ghostfolio/ui/i18n';
import { AbstractMatFormField } from '@ghostfolio/ui/shared/abstract-mat-form-field';
import { FocusMonitor } from '@angular/cdk/a11y'; import { FocusMonitor } from '@angular/cdk/a11y';
import { import {
@ -16,7 +14,8 @@ import {
OnDestroy, OnDestroy,
OnInit, OnInit,
SimpleChanges, SimpleChanges,
ViewChild ViewChild,
DoCheck
} from '@angular/core'; } from '@angular/core';
import { import {
FormControl, FormControl,
@ -45,7 +44,9 @@ import {
takeUntil takeUntil
} from 'rxjs/operators'; } from 'rxjs/operators';
import { translate } from '../i18n';
import { GfPremiumIndicatorComponent } from '../premium-indicator'; import { GfPremiumIndicatorComponent } from '../premium-indicator';
import { AbstractMatFormField } from '../shared/abstract-mat-form-field';
@Component({ @Component({
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
@ -76,7 +77,7 @@ import { GfPremiumIndicatorComponent } from '../premium-indicator';
}) })
export class GfSymbolAutocompleteComponent export class GfSymbolAutocompleteComponent
extends AbstractMatFormField<LookupItem> extends AbstractMatFormField<LookupItem>
implements OnChanges, OnDestroy, OnInit implements OnChanges, OnDestroy, OnInit, DoCheck
{ {
@Input() public defaultLookupItems: LookupItem[] = []; @Input() public defaultLookupItems: LookupItem[] = [];
@Input() public isLoading = false; @Input() public isLoading = false;

3
libs/ui/src/lib/top-holdings/top-holdings.component.ts

@ -4,7 +4,6 @@ import {
AssetProfileIdentifier, AssetProfileIdentifier,
HoldingWithParents HoldingWithParents
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { GfValueComponent } from '@ghostfolio/ui/value';
import { import {
animate, animate,
@ -31,6 +30,8 @@ import { MatTableDataSource, MatTableModule } from '@angular/material/table';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { GfValueComponent } from '../value/value.component';
@Component({ @Component({
animations: [ animations: [
trigger('detailExpand', [ trigger('detailExpand', [

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

@ -48,7 +48,7 @@ export class GfValueComponent implements OnChanges {
if (isNumber(this.value)) { if (isNumber(this.value)) {
this.isNumber = true; this.isNumber = true;
this.isString = false; this.isString = false;
this.absoluteValue = Math.abs(this.value as number); this.absoluteValue = Math.abs(this.value);
if (this.colorizeSign) { if (this.colorizeSign) {
if (this.isCurrency) { if (this.isCurrency) {

57
nx.json

@ -10,8 +10,61 @@
"linter": "eslint", "linter": "eslint",
"unitTestRunner": "jest" "unitTestRunner": "jest"
}, },
"@nx/angular:component": {}, "@nx/angular:component": {
"@nx/nest": {} "type": "component"
},
"@nx/nest": {},
"@schematics/angular:component": {
"type": "component"
},
"@nx/angular:directive": {
"type": "directive"
},
"@schematics/angular:directive": {
"type": "directive"
},
"@nx/angular:service": {
"type": "service"
},
"@schematics/angular:service": {
"type": "service"
},
"@nx/angular:scam": {
"type": "component"
},
"@nx/angular:scam-directive": {
"type": "directive"
},
"@nx/angular:guard": {
"typeSeparator": "."
},
"@schematics/angular:guard": {
"typeSeparator": "."
},
"@nx/angular:interceptor": {
"typeSeparator": "."
},
"@schematics/angular:interceptor": {
"typeSeparator": "."
},
"@nx/angular:module": {
"typeSeparator": "."
},
"@schematics/angular:module": {
"typeSeparator": "."
},
"@nx/angular:pipe": {
"typeSeparator": "."
},
"@schematics/angular:pipe": {
"typeSeparator": "."
},
"@nx/angular:resolver": {
"typeSeparator": "."
},
"@schematics/angular:resolver": {
"typeSeparator": "."
}
}, },
"$schema": "./node_modules/nx/schemas/nx-schema.json", "$schema": "./node_modules/nx/schemas/nx-schema.json",
"targetDefaults": { "targetDefaults": {

13212
package-lock.json

File diff suppressed because it is too large

90
package.json

@ -56,17 +56,17 @@
"workspace-generator": "nx workspace-generator" "workspace-generator": "nx workspace-generator"
}, },
"dependencies": { "dependencies": {
"@angular/animations": "19.2.1", "@angular/animations": "20.0.7",
"@angular/cdk": "19.2.2", "@angular/cdk": "20.0.6",
"@angular/common": "19.2.1", "@angular/common": "20.0.7",
"@angular/compiler": "19.2.1", "@angular/compiler": "20.0.7",
"@angular/core": "19.2.1", "@angular/core": "20.0.7",
"@angular/forms": "19.2.1", "@angular/forms": "20.0.7",
"@angular/material": "19.2.2", "@angular/material": "20.0.6",
"@angular/platform-browser": "19.2.1", "@angular/platform-browser": "20.0.7",
"@angular/platform-browser-dynamic": "19.2.1", "@angular/platform-browser-dynamic": "20.0.7",
"@angular/router": "19.2.1", "@angular/router": "20.0.7",
"@angular/service-worker": "19.2.1", "@angular/service-worker": "20.0.7",
"@codewithdan/observable-store": "2.2.15", "@codewithdan/observable-store": "2.2.15",
"@date-fns/utc": "2.1.0", "@date-fns/utc": "2.1.0",
"@dfinity/agent": "0.15.7", "@dfinity/agent": "0.15.7",
@ -123,10 +123,10 @@
"marked": "15.0.4", "marked": "15.0.4",
"ms": "3.0.0-canary.1", "ms": "3.0.0-canary.1",
"ng-extract-i18n-merge": "2.15.1", "ng-extract-i18n-merge": "2.15.1",
"ngx-device-detector": "9.0.0", "ngx-device-detector": "10.0.2",
"ngx-markdown": "19.0.0", "ngx-markdown": "20.0.0",
"ngx-skeleton-loader": "11.2.1", "ngx-skeleton-loader": "11.2.1",
"ngx-stripe": "19.7.0", "ngx-stripe": "20.7.0",
"open-color": "1.9.1", "open-color": "1.9.1",
"papaparse": "5.3.1", "papaparse": "5.3.1",
"passport": "0.7.0", "passport": "0.7.0",
@ -143,37 +143,35 @@
"zone.js": "0.15.1" "zone.js": "0.15.1"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "19.2.1", "@angular-devkit/build-angular": "20.0.6",
"@angular-devkit/core": "19.2.1", "@angular-devkit/core": "20.0.6",
"@angular-devkit/schematics": "19.2.1", "@angular-devkit/schematics": "20.0.6",
"@angular-eslint/eslint-plugin": "19.2.1", "@angular-eslint/eslint-plugin": "20.1.1",
"@angular-eslint/eslint-plugin-template": "19.2.1", "@angular-eslint/eslint-plugin-template": "20.1.1",
"@angular-eslint/template-parser": "19.2.1", "@angular-eslint/template-parser": "20.1.1",
"@angular/cli": "19.2.1", "@angular/cli": "20.0.6",
"@angular/compiler-cli": "19.2.1", "@angular/compiler-cli": "20.0.7",
"@angular/language-service": "19.2.1", "@angular/language-service": "20.0.7",
"@angular/localize": "19.2.1", "@angular/localize": "20.0.7",
"@angular/pwa": "19.2.1", "@angular/pwa": "20.0.6",
"@eslint/eslintrc": "3.3.1", "@eslint/eslintrc": "3.3.1",
"@eslint/js": "9.24.0", "@eslint/js": "9.24.0",
"@nestjs/schematics": "11.0.5", "@nestjs/schematics": "11.0.5",
"@nestjs/testing": "11.1.3", "@nestjs/testing": "11.1.3",
"@nx/angular": "21.1.2", "@nx/angular": "21.2.4",
"@nx/cypress": "21.1.2", "@nx/cypress": "21.2.4",
"@nx/eslint-plugin": "21.1.2", "@nx/eslint-plugin": "21.2.4",
"@nx/jest": "21.1.2", "@nx/jest": "21.2.4",
"@nx/js": "21.1.2", "@nx/js": "21.2.4",
"@nx/module-federation": "21.1.2", "@nx/module-federation": "21.2.4",
"@nx/nest": "21.1.2", "@nx/nest": "21.2.4",
"@nx/node": "21.1.2", "@nx/node": "21.2.4",
"@nx/storybook": "21.1.2", "@nx/storybook": "21.2.4",
"@nx/web": "21.1.2", "@nx/web": "21.2.4",
"@nx/workspace": "21.1.2", "@nx/workspace": "21.2.4",
"@schematics/angular": "19.2.1", "@schematics/angular": "20.0.6",
"@storybook/addon-essentials": "8.6.12", "@storybook/addon-docs": "9.0.17",
"@storybook/addon-interactions": "8.6.12", "@storybook/angular": "9.0.17",
"@storybook/angular": "8.6.12",
"@storybook/core-server": "8.6.12",
"@trivago/prettier-plugin-sort-imports": "5.2.2", "@trivago/prettier-plugin-sort-imports": "5.2.2",
"@types/big.js": "6.2.2", "@types/big.js": "6.2.2",
"@types/google-spreadsheet": "3.1.5", "@types/google-spreadsheet": "3.1.5",
@ -190,12 +188,12 @@
"eslint-config-prettier": "10.1.1", "eslint-config-prettier": "10.1.1",
"eslint-plugin-cypress": "4.2.0", "eslint-plugin-cypress": "4.2.0",
"eslint-plugin-import": "2.31.0", "eslint-plugin-import": "2.31.0",
"eslint-plugin-storybook": "0.12.0", "eslint-plugin-storybook": "9.0.17",
"husky": "9.1.7", "husky": "9.1.7",
"jest": "29.7.0", "jest": "29.7.0",
"jest-environment-jsdom": "29.7.0", "jest-environment-jsdom": "29.7.0",
"jest-preset-angular": "14.4.2", "jest-preset-angular": "14.6.0",
"nx": "21.1.2", "nx": "21.2.4",
"prettier": "3.6.2", "prettier": "3.6.2",
"prettier-plugin-organize-attributes": "1.0.0", "prettier-plugin-organize-attributes": "1.0.0",
"prisma": "6.11.1", "prisma": "6.11.1",
@ -203,11 +201,11 @@
"react-dom": "18.2.0", "react-dom": "18.2.0",
"replace-in-file": "8.3.0", "replace-in-file": "8.3.0",
"shx": "0.3.4", "shx": "0.3.4",
"storybook": "8.6.12", "storybook": "9.0.17",
"ts-jest": "29.1.0", "ts-jest": "29.1.0",
"ts-node": "10.9.2", "ts-node": "10.9.2",
"tslib": "2.8.1", "tslib": "2.8.1",
"typescript": "5.7.3", "typescript": "5.8.3",
"webpack-bundle-analyzer": "4.10.2" "webpack-bundle-analyzer": "4.10.2"
}, },
"engines": { "engines": {

Loading…
Cancel
Save