Browse Source

Task/limit length in various endpoints (#7810)

* Limit length for comment, search query and symbol

* Update changelog
pull/7786/head^2
Thomas Kaul 3 days ago
committed by GitHub
parent
commit
f604a9e906
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 9
      CHANGELOG.md
  2. 4
      apps/api/src/app/account/get-all-accounts.dto.ts
  3. 25
      apps/api/src/app/endpoints/asset-profiles/asset-profiles.controller.ts
  4. 64
      apps/api/src/app/endpoints/asset-profiles/get-asset-profiles.dto.ts
  5. 16
      apps/api/src/app/endpoints/data-providers/ghostfolio/get-lookup.dto.ts
  6. 5
      apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.controller.ts
  7. 4
      apps/api/src/app/portfolio/get-holdings.dto.ts
  8. 16
      apps/api/src/app/symbol/get-lookup.dto.ts
  9. 6
      apps/api/src/app/symbol/symbol.controller.ts
  10. 11
      apps/api/src/dtos/filter.dto.ts
  11. 2
      apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts
  12. 1
      apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html
  13. 7
      apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts
  14. 1
      apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html
  15. 7
      apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts
  16. 1
      apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html
  17. 5
      libs/common/src/lib/config.ts
  18. 3
      libs/common/src/lib/dtos/create-account.dto.ts
  19. 7
      libs/common/src/lib/dtos/create-asset-profile.dto.ts
  20. 7
      libs/common/src/lib/dtos/create-order.dto.ts
  21. 5
      libs/common/src/lib/dtos/create-watchlist-item.dto.ts
  22. 3
      libs/common/src/lib/dtos/update-account.dto.ts
  23. 7
      libs/common/src/lib/dtos/update-asset-profile.dto.ts
  24. 7
      libs/common/src/lib/dtos/update-order.dto.ts
  25. 2
      libs/ui/src/lib/assistant/assistant.component.ts
  26. 1
      libs/ui/src/lib/assistant/assistant.html
  27. 1
      libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html
  28. 2
      libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.ts

9
CHANGELOG.md

@ -7,9 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
### Added
- Introduced a DTO for the query parameters of the asset profiles endpoint
- Introduced a DTO for the query parameters of the symbol lookup endpoints
### Changed
- Hardened the validation of the query parameters (`accounts`, `assetClasses`, `dataSource` and `tags`) in the endpoints with filters
- Introduced a maximum length for the comment in the API endpoints
- Introduced a maximum length for the search query and the symbol in the API endpoints
- Hardened the validation of the query parameters (`accounts`, `assetClasses`, `dataSource` and `tags`) in the API endpoints with filters
### Fixed

4
apps/api/src/app/account/get-all-accounts.dto.ts

@ -1,9 +1,11 @@
import { FilterDto } from '@ghostfolio/api/dtos/filter.dto';
import { SEARCH_QUERY_MAXIMUM_LENGTH } from '@ghostfolio/common/config';
import { IsOptional, IsString } from 'class-validator';
import { IsOptional, IsString, MaxLength } from 'class-validator';
export class GetAllAccountsDto extends FilterDto {
@IsOptional()
@IsString()
@MaxLength(SEARCH_QUERY_MAXIMUM_LENGTH)
query?: string;
}

25
apps/api/src/app/endpoints/asset-profiles/asset-profiles.controller.ts

@ -17,7 +17,7 @@ import {
} from '@ghostfolio/common/interfaces';
import { hasPermission } from '@ghostfolio/common/permissions';
import { permissions } from '@ghostfolio/common/permissions';
import { MarketDataPreset, RequestWithUser } from '@ghostfolio/common/types';
import { RequestWithUser } from '@ghostfolio/common/types';
import {
Body,
@ -27,7 +27,6 @@ import {
HttpException,
Inject,
Param,
ParseIntPipe,
Patch,
Post,
Query,
@ -36,11 +35,12 @@ import {
} from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
import { AssetProfileSplit, DataSource, Prisma } from '@prisma/client';
import { AssetProfileSplit, DataSource } from '@prisma/client';
import { parseISO } from 'date-fns';
import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { AssetProfilesService } from './asset-profiles.service';
import { GetAssetProfilesDto } from './get-asset-profiles.dto';
@AllowDuringImpersonation()
@Controller('asset-profiles')
@ -56,14 +56,17 @@ export class AssetProfilesController {
@HasPermission(permissions.accessAdminControl)
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
public async getAssetProfiles(
@Query('assetSubClasses') filterByAssetSubClasses?: string,
@Query('dataSource') filterByDataSource?: string,
@Query('presetId') presetId?: MarketDataPreset,
@Query('query') filterBySearchQuery?: string,
@Query('skip', new ParseIntPipe({ optional: true })) skip?: number,
@Query('sortColumn') sortColumn?: string,
@Query('sortDirection') sortDirection?: Prisma.SortOrder,
@Query('take', new ParseIntPipe({ optional: true })) take?: number
@Query()
{
assetSubClasses: filterByAssetSubClasses,
dataSource: filterByDataSource,
presetId,
query: filterBySearchQuery,
skip,
sortColumn,
sortDirection,
take
}: GetAssetProfilesDto
): Promise<AssetProfilesResponse> {
const filters = this.apiService.buildFiltersFromQueryParams({
filterByAssetSubClasses,

64
apps/api/src/app/endpoints/asset-profiles/get-asset-profiles.dto.ts

@ -0,0 +1,64 @@
import { SEARCH_QUERY_MAXIMUM_LENGTH } from '@ghostfolio/common/config';
import { MarketDataPreset } from '@ghostfolio/common/types';
import { Prisma } from '@prisma/client';
import { Type } from 'class-transformer';
import {
IsIn,
IsInt,
IsOptional,
IsString,
MaxLength,
Min
} from 'class-validator';
export class GetAssetProfilesDto {
@IsOptional()
@IsString()
assetSubClasses?: string;
@IsOptional()
@IsString()
dataSource?: string;
@IsIn([
'BENCHMARKS',
'CURRENCIES',
'ETF_WITHOUT_COUNTRIES',
'ETF_WITHOUT_SECTORS',
'NO_ACTIVITIES'
] as MarketDataPreset[])
@IsOptional()
presetId?: MarketDataPreset;
@IsOptional()
@IsString()
@MaxLength(SEARCH_QUERY_MAXIMUM_LENGTH)
query?: string;
@IsInt()
@IsOptional()
@Min(0)
@Type(() => Number)
skip?: number;
@IsIn([
'activitiesCount',
'assetClass',
'assetSubClass',
'dataSource',
'symbol'
])
@IsOptional()
sortColumn?: string;
@IsIn(['asc', 'desc'] as Prisma.SortOrder[])
@IsOptional()
sortDirection?: Prisma.SortOrder;
@IsInt()
@IsOptional()
@Min(0)
@Type(() => Number)
take?: number;
}

16
apps/api/src/app/endpoints/data-providers/ghostfolio/get-lookup.dto.ts

@ -0,0 +1,16 @@
import { SEARCH_QUERY_MAXIMUM_LENGTH } from '@ghostfolio/common/config';
import { Transform, TransformFnParams } from 'class-transformer';
import { IsBoolean, IsString, MaxLength } from 'class-validator';
export class GetLookupDto {
@IsBoolean()
@Transform(({ value }: TransformFnParams) => {
return value === 'true';
})
includeIndices? = false;
@IsString()
@MaxLength(SEARCH_QUERY_MAXIMUM_LENGTH)
query? = '';
}

5
apps/api/src/app/endpoints/data-providers/ghostfolio/ghostfolio.controller.ts

@ -32,6 +32,7 @@ import { getReasonPhrase, StatusCodes } from 'http-status-codes';
import { GetDividendsDto } from './get-dividends.dto';
import { GetHistoricalDto } from './get-historical.dto';
import { GetLookupDto } from './get-lookup.dto';
import { GetQuotesDto } from './get-quotes.dto';
import { GhostfolioService } from './ghostfolio.service';
@ -142,10 +143,8 @@ export class GhostfolioController {
@UseGuards(AuthGuard('api-key'), HasPermissionGuard)
@Version('2')
public async lookupSymbol(
@Query('includeIndices') includeIndicesParam = 'false',
@Query('query') query = ''
@Query() { includeIndices, query }: GetLookupDto
): Promise<LookupResponse> {
const includeIndices = includeIndicesParam === 'true';
await this.validateDailyRequestLimit();
try {

4
apps/api/src/app/portfolio/get-holdings.dto.ts

@ -1,7 +1,8 @@
import { DateRangeFilterDto } from '@ghostfolio/api/dtos/date-range-filter.dto';
import { SEARCH_QUERY_MAXIMUM_LENGTH } from '@ghostfolio/common/config';
import { HoldingType } from '@ghostfolio/common/types';
import { IsIn, IsOptional, IsString } from 'class-validator';
import { IsIn, IsOptional, IsString, MaxLength } from 'class-validator';
export class GetHoldingsDto extends DateRangeFilterDto {
@IsIn(['ACTIVE', 'CLOSED'] as HoldingType[])
@ -10,5 +11,6 @@ export class GetHoldingsDto extends DateRangeFilterDto {
@IsOptional()
@IsString()
@MaxLength(SEARCH_QUERY_MAXIMUM_LENGTH)
query?: string;
}

16
apps/api/src/app/symbol/get-lookup.dto.ts

@ -0,0 +1,16 @@
import { SEARCH_QUERY_MAXIMUM_LENGTH } from '@ghostfolio/common/config';
import { Transform, TransformFnParams } from 'class-transformer';
import { IsBoolean, IsString, MaxLength } from 'class-validator';
export class GetLookupDto {
@IsBoolean()
@Transform(({ value }: TransformFnParams) => {
return value === 'true';
})
includeIndices? = false;
@IsString()
@MaxLength(SEARCH_QUERY_MAXIMUM_LENGTH)
query? = '';
}

6
apps/api/src/app/symbol/symbol.controller.ts

@ -27,6 +27,7 @@ import { isValid, parseISO } from 'date-fns';
import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { isEmpty } from 'lodash';
import { GetLookupDto } from './get-lookup.dto';
import { SymbolService } from './symbol.service';
@Controller('symbol')
@ -43,11 +44,8 @@ export class SymbolController {
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
@UseInterceptors(TransformDataSourceInResponseInterceptor)
public async lookupSymbol(
@Query('includeIndices') includeIndicesParam = 'false',
@Query('query') query = ''
@Query() { includeIndices, query }: GetLookupDto
): Promise<LookupResponse> {
const includeIndices = includeIndicesParam === 'true';
try {
return this.symbolService.lookup({
includeIndices,

11
apps/api/src/dtos/filter.dto.ts

@ -1,6 +1,14 @@
import { SYMBOL_MAXIMUM_LENGTH } from '@ghostfolio/common/config';
import { AssetClass, DataSource } from '@prisma/client';
import { Transform, TransformFnParams } from 'class-transformer';
import { IsEnum, IsOptional, IsString, IsUUID } from 'class-validator';
import {
IsEnum,
IsOptional,
IsString,
IsUUID,
MaxLength
} from 'class-validator';
import { isString } from 'lodash';
export class FilterDto {
@ -24,6 +32,7 @@ export class FilterDto {
@IsOptional()
@IsString()
@MaxLength(SYMBOL_MAXIMUM_LENGTH)
symbol?: string;
@IsOptional()

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

@ -2,6 +2,7 @@ import { AdminMarketDataService } from '@ghostfolio/client/components/admin-mark
import { UserService } from '@ghostfolio/client/services/user/user.service';
import {
ASSET_CLASS_MAPPING,
COMMENT_MAXIMUM_LENGTH,
PROPERTY_IS_DATA_GATHERING_ENABLED
} from '@ghostfolio/common/config';
import { UpdateAssetProfileDto } from '@ghostfolio/common/dtos';
@ -229,6 +230,7 @@ export class GfAssetProfileDialogComponent implements OnInit {
protected readonly canDeleteAssetProfile = canDeleteAssetProfile;
protected canEditAssetProfile = true;
protected readonly COMMENT_MAXIMUM_LENGTH = COMMENT_MAXIMUM_LENGTH;
protected countries: {
[code: string]: { name: string; value: number };

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

@ -467,6 +467,7 @@
cdkTextareaAutosize
formControlName="comment"
matInput
[maxlength]="COMMENT_MAXIMUM_LENGTH"
(keyup.enter)="$event.stopPropagation()"
></textarea>
</mat-form-field>

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

@ -1,6 +1,9 @@
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { TAG_ID_DRAFT } from '@ghostfolio/common/config';
import {
COMMENT_MAXIMUM_LENGTH,
TAG_ID_DRAFT
} from '@ghostfolio/common/config';
import { CreateAccountDto, UpdateAccountDto } from '@ghostfolio/common/dtos';
import { getStringOrNull } from '@ghostfolio/common/helper';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
@ -62,6 +65,8 @@ import { CreateOrUpdateAccountDialogParams } from './interfaces/interfaces';
templateUrl: 'create-or-update-account-dialog.html'
})
export class GfCreateOrUpdateAccountDialogComponent {
protected readonly COMMENT_MAXIMUM_LENGTH = COMMENT_MAXIMUM_LENGTH;
protected accountForm: FormGroup;
protected currencies: string[] = [];
protected filteredPlatforms: Observable<Platform[]> | undefined;

1
apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html

@ -91,6 +91,7 @@
cdkTextareaAutosize
formControlName="comment"
matInput
[maxlength]="COMMENT_MAXIMUM_LENGTH"
(keyup.enter)="$event.stopPropagation()"
></textarea>
</mat-form-field>

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

@ -1,6 +1,10 @@
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
import { UserService } from '@ghostfolio/client/services/user/user.service';
import { ASSET_CLASS_MAPPING, DEFAULT_LOCALE } from '@ghostfolio/common/config';
import {
ASSET_CLASS_MAPPING,
COMMENT_MAXIMUM_LENGTH,
DEFAULT_LOCALE
} from '@ghostfolio/common/config';
import { CreateOrderDto, UpdateOrderDto } from '@ghostfolio/common/dtos';
import {
getDateFormatString,
@ -79,6 +83,7 @@ import { ActivityType } from './types/activity-type.type';
templateUrl: 'create-or-update-activity-dialog.html'
})
export class GfCreateOrUpdateActivityDialogComponent {
protected readonly COMMENT_MAXIMUM_LENGTH = COMMENT_MAXIMUM_LENGTH;
protected readonly DEFAULT_LOCALE = DEFAULT_LOCALE;
protected activityForm: FormGroup;

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

@ -255,6 +255,7 @@
cdkTextareaAutosize
formControlName="comment"
matInput
[maxlength]="COMMENT_MAXIMUM_LENGTH"
(keyup.enter)="$event.stopPropagation()"
></textarea>
</mat-form-field>

5
libs/common/src/lib/config.ts

@ -60,6 +60,8 @@ export const BULL_BOARD_ROUTE = '/admin/queues';
export const CACHE_TTL_NO_CACHE = 1;
export const CACHE_TTL_INFINITE = 0;
export const COMMENT_MAXIMUM_LENGTH = 2000;
export const DATA_GATHERING_QUEUE = 'DATA_GATHERING_QUEUE';
export const DATA_GATHERING_QUEUE_PRIORITY_HIGH = 1;
export const DATA_GATHERING_QUEUE_PRIORITY_LOW = Number.MAX_SAFE_INTEGER;
@ -342,6 +344,7 @@ export const REPLACE_NAME_PARTS = [
'Xtrackers (IE) Plc -'
];
export const SEARCH_QUERY_MAXIMUM_LENGTH = 255;
export const SEARCH_QUERY_MINIMUM_LENGTH = 2;
export const SECTORS = [
@ -378,6 +381,8 @@ export const SUPPORTED_LANGUAGE_CODES = [
'zh'
] as const;
export const SYMBOL_MAXIMUM_LENGTH = 255;
export const TAG_ID_DEMO = 'efa08cb3-9b9d-4974-ac68-db13a19c4874';
export const TAG_ID_DRAFT = '0c077abd-eca2-4cbb-818c-6cefbf2d169a';
export const TAG_ID_EMERGENCY_FUND = '4452656d-9fa4-4bd0-ba38-70492e31d180';

3
libs/common/src/lib/dtos/create-account.dto.ts

@ -1,3 +1,4 @@
import { COMMENT_MAXIMUM_LENGTH } from '@ghostfolio/common/config';
import { IsCurrencyCode } from '@ghostfolio/common/validators/is-currency-code';
import { Transform, TransformFnParams } from 'class-transformer';
@ -7,6 +8,7 @@ import {
IsNumber,
IsOptional,
IsString,
MaxLength,
ValidateIf
} from 'class-validator';
import { isString } from 'lodash';
@ -22,6 +24,7 @@ export class CreateAccountDto {
@IsOptional()
@IsString()
@MaxLength(COMMENT_MAXIMUM_LENGTH)
@Transform(({ value }: TransformFnParams) =>
isString(value) ? value.trim() : value
)

7
libs/common/src/lib/dtos/create-asset-profile.dto.ts

@ -1,3 +1,7 @@
import {
COMMENT_MAXIMUM_LENGTH,
SYMBOL_MAXIMUM_LENGTH
} from '@ghostfolio/common/config';
import { IsCurrencyCode } from '@ghostfolio/common/validators/is-currency-code';
import { AssetClass, AssetSubClass, DataSource, Prisma } from '@prisma/client';
@ -9,6 +13,7 @@ import {
IsOptional,
IsString,
IsUrl,
MaxLength,
ValidateNested
} from 'class-validator';
@ -27,6 +32,7 @@ export class CreateAssetProfileDto {
@IsOptional()
@IsString()
@MaxLength(COMMENT_MAXIMUM_LENGTH)
comment?: string;
@IsArray()
@ -82,6 +88,7 @@ export class CreateAssetProfileDto {
sectors?: Prisma.InputJsonArray;
@IsString()
@MaxLength(SYMBOL_MAXIMUM_LENGTH)
symbol: string;
@IsOptional()

7
libs/common/src/lib/dtos/create-order.dto.ts

@ -1,3 +1,7 @@
import {
COMMENT_MAXIMUM_LENGTH,
SYMBOL_MAXIMUM_LENGTH
} from '@ghostfolio/common/config';
import { IsAfter1970Constraint } from '@ghostfolio/common/validator-constraints/is-after-1970';
import { IsCurrencyCode } from '@ghostfolio/common/validators/is-currency-code';
@ -12,6 +16,7 @@ import {
IsNumber,
IsOptional,
IsString,
MaxLength,
Min,
Validate
} from 'class-validator';
@ -32,6 +37,7 @@ export class CreateOrderDto {
@IsOptional()
@IsString()
@MaxLength(COMMENT_MAXIMUM_LENGTH)
@Transform(({ value }: TransformFnParams) =>
isString(value) ? value.trim() : value
)
@ -61,6 +67,7 @@ export class CreateOrderDto {
quantity: number;
@IsString()
@MaxLength(SYMBOL_MAXIMUM_LENGTH)
symbol: string;
@ArrayUnique()

5
libs/common/src/lib/dtos/create-watchlist-item.dto.ts

@ -1,10 +1,13 @@
import { SYMBOL_MAXIMUM_LENGTH } from '@ghostfolio/common/config';
import { DataSource } from '@prisma/client';
import { IsEnum, IsString } from 'class-validator';
import { IsEnum, IsString, MaxLength } from 'class-validator';
export class CreateWatchlistItemDto {
@IsEnum(DataSource)
dataSource: DataSource;
@IsString()
@MaxLength(SYMBOL_MAXIMUM_LENGTH)
symbol: string;
}

3
libs/common/src/lib/dtos/update-account.dto.ts

@ -1,3 +1,4 @@
import { COMMENT_MAXIMUM_LENGTH } from '@ghostfolio/common/config';
import { IsCurrencyCode } from '@ghostfolio/common/validators/is-currency-code';
import { Transform, TransformFnParams } from 'class-transformer';
@ -7,6 +8,7 @@ import {
IsNumber,
IsOptional,
IsString,
MaxLength,
ValidateIf
} from 'class-validator';
import { isString } from 'lodash';
@ -22,6 +24,7 @@ export class UpdateAccountDto {
@IsOptional()
@IsString()
@MaxLength(COMMENT_MAXIMUM_LENGTH)
@Transform(({ value }: TransformFnParams) =>
isString(value) ? value.trim() : value
)

7
libs/common/src/lib/dtos/update-asset-profile.dto.ts

@ -1,3 +1,7 @@
import {
COMMENT_MAXIMUM_LENGTH,
SYMBOL_MAXIMUM_LENGTH
} from '@ghostfolio/common/config';
import { IsCurrencyCode } from '@ghostfolio/common/validators/is-currency-code';
import {
@ -16,6 +20,7 @@ import {
IsOptional,
IsString,
IsUrl,
MaxLength,
ValidateNested
} from 'class-validator';
@ -35,6 +40,7 @@ export class UpdateAssetProfileDto {
@IsOptional()
@IsString()
@MaxLength(COMMENT_MAXIMUM_LENGTH)
comment?: string | null;
@IsArray()
@ -83,6 +89,7 @@ export class UpdateAssetProfileDto {
@IsOptional()
@IsString()
@MaxLength(SYMBOL_MAXIMUM_LENGTH)
symbol?: string;
@IsObject()

7
libs/common/src/lib/dtos/update-order.dto.ts

@ -1,3 +1,7 @@
import {
COMMENT_MAXIMUM_LENGTH,
SYMBOL_MAXIMUM_LENGTH
} from '@ghostfolio/common/config';
import { IsAfter1970Constraint } from '@ghostfolio/common/validator-constraints/is-after-1970';
import { IsCurrencyCode } from '@ghostfolio/common/validators/is-currency-code';
@ -11,6 +15,7 @@ import {
IsNumber,
IsOptional,
IsString,
MaxLength,
Min,
Validate
} from 'class-validator';
@ -31,6 +36,7 @@ export class UpdateOrderDto {
@IsOptional()
@IsString()
@MaxLength(COMMENT_MAXIMUM_LENGTH)
@Transform(({ value }: TransformFnParams) =>
isString(value) ? value.trim() : value
)
@ -62,6 +68,7 @@ export class UpdateOrderDto {
quantity: number;
@IsString()
@MaxLength(SYMBOL_MAXIMUM_LENGTH)
symbol: string;
@ArrayUnique()

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

@ -1,3 +1,4 @@
import { SEARCH_QUERY_MAXIMUM_LENGTH } from '@ghostfolio/common/config';
import { Filter, PortfolioPosition, User } from '@ghostfolio/common/interfaces';
import { InternalRoute } from '@ghostfolio/common/routes/interfaces/internal-route.interface';
import { internalRoutes } from '@ghostfolio/common/routes/routes';
@ -130,6 +131,7 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit {
);
public searchFormControl = new FormControl('');
public readonly SEARCH_QUERY_MAXIMUM_LENGTH = SEARCH_QUERY_MAXIMUM_LENGTH;
public searchResults: SearchResults = {
accounts: [],

1
libs/ui/src/lib/assistant/assistant.html

@ -13,6 +13,7 @@
name="search"
type="text"
[formControl]="searchFormControl"
[maxlength]="SEARCH_QUERY_MAXIMUM_LENGTH"
[placeholder]="placeholder"
/>
@if (deviceType !== 'mobile' && !searchFormControl.value) {

1
libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html

@ -4,6 +4,7 @@
matInput
[formControl]="control"
[matAutocomplete]="symbolAutocomplete"
[maxlength]="SEARCH_QUERY_MAXIMUM_LENGTH"
/>
<mat-autocomplete

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

@ -1,3 +1,4 @@
import { SEARCH_QUERY_MAXIMUM_LENGTH } from '@ghostfolio/common/config';
import { LookupItem } from '@ghostfolio/common/interfaces';
import { DataService } from '@ghostfolio/ui/services';
@ -86,6 +87,7 @@ export class GfSymbolAutocompleteComponent
public readonly control = new FormControl();
public lookupItems: (LookupItem & { assetSubClassString: string })[] = [];
public readonly SEARCH_QUERY_MAXIMUM_LENGTH = SEARCH_QUERY_MAXIMUM_LENGTH;
protected readonly symbolAutocomplete =
viewChild.required<MatAutocomplete>('symbolAutocomplete');

Loading…
Cancel
Save