Compare commits

..

15 Commits

Author SHA1 Message Date
nityanandagohain
c946cfbdfd Merge remote-tracking branch 'origin/main' into issue_4360 2026-04-24 15:51:44 +05:30
nityanandagohain
32391acfc8 fix: correct table name 2026-04-24 15:47:51 +05:30
nityanandagohain
437ce412c6 fix: use mustnewuuid 2026-04-24 00:19:02 +05:30
nityanandagohain
040872fa41 fix: address comments 2026-04-23 19:08:42 +05:30
nityanandagohain
c28f6cd1a3 fix: types 2026-04-23 16:51:30 +05:30
nityanandagohain
70e37817b9 fix: remove nullable 2026-04-23 16:41:26 +05:30
nityanandagohain
c5645c38c4 Merge remote-tracking branch 'origin/main' into issue_4360 2026-04-23 16:37:17 +05:30
nityanandagohain
5c7c262d4e fix: address comments 2026-04-23 16:34:45 +05:30
nityanandagohain
07cb56c548 fix: new updates 2026-04-22 22:27:24 +05:30
nityanandagohain
6e382aa363 fix: more changes 2026-04-22 14:02:44 +05:30
nityanandagohain
115ee70a9a fix: minor changes 2026-04-22 00:00:51 +05:30
Nityananda Gohain
a58a3d4a68 Merge branch 'main' into issue_4360 2026-04-20 17:54:38 +05:30
nityanandagohain
6899eb0124 fix: changes 2026-04-20 17:53:42 +05:30
nityanandagohain
de5bec0195 Merge remote-tracking branch 'origin/main' into issue_4360 2026-04-20 16:41:58 +05:30
nityanandagohain
e359b03c25 feat: 1.Types for ai-o11y ricing rules 2026-04-12 17:14:18 +05:30
550 changed files with 3732 additions and 2084 deletions

View File

@@ -2508,6 +2508,155 @@ components:
- list
- grouped_list
type: string
LlmpricingruletypesGettablePricingRules:
properties:
items:
items:
$ref: '#/components/schemas/LlmpricingruletypesLLMPricingRule'
nullable: true
type: array
limit:
type: integer
offset:
type: integer
total:
type: integer
required:
- items
- total
- offset
- limit
type: object
LlmpricingruletypesLLMPricingRule:
properties:
cacheMode:
$ref: '#/components/schemas/LlmpricingruletypesLLMPricingRuleCacheMode'
costCacheRead:
format: double
type: number
costCacheWrite:
format: double
type: number
costInput:
format: double
type: number
costOutput:
format: double
type: number
createdAt:
format: date-time
type: string
createdBy:
type: string
enabled:
type: boolean
id:
type: string
isOverride:
type: boolean
modelName:
type: string
modelPattern:
items:
type: string
nullable: true
type: array
orgId:
type: string
sourceId:
type: string
syncedAt:
format: date-time
nullable: true
type: string
unit:
$ref: '#/components/schemas/LlmpricingruletypesLLMPricingRuleUnit'
updatedAt:
format: date-time
type: string
updatedBy:
type: string
required:
- id
- orgId
- modelName
- modelPattern
- unit
- cacheMode
- costInput
- costOutput
- costCacheRead
- costCacheWrite
- isOverride
- enabled
type: object
LlmpricingruletypesLLMPricingRuleCacheMode:
enum:
- subtract
- additive
- unknown
type: string
LlmpricingruletypesLLMPricingRuleUnit:
enum:
- per_million_tokens
type: string
LlmpricingruletypesUpdatableLLMPricingRule:
properties:
cacheMode:
$ref: '#/components/schemas/LlmpricingruletypesLLMPricingRuleCacheMode'
costCacheRead:
format: double
type: number
costCacheWrite:
format: double
type: number
costInput:
format: double
type: number
costOutput:
format: double
type: number
enabled:
type: boolean
id:
nullable: true
type: string
isOverride:
nullable: true
type: boolean
modelName:
type: string
modelPattern:
items:
type: string
nullable: true
type: array
sourceId:
nullable: true
type: string
unit:
$ref: '#/components/schemas/LlmpricingruletypesLLMPricingRuleUnit'
required:
- modelName
- modelPattern
- unit
- cacheMode
- costInput
- costOutput
- costCacheRead
- costCacheWrite
- enabled
type: object
LlmpricingruletypesUpdatableLLMPricingRules:
properties:
rules:
items:
$ref: '#/components/schemas/LlmpricingruletypesUpdatableLLMPricingRule'
nullable: true
type: array
required:
- rules
type: object
MetricsexplorertypesInspectMetricsRequest:
properties:
end:
@@ -7332,6 +7481,218 @@ paths:
summary: Create bulk invite
tags:
- users
/api/v1/llm_pricing_rules:
get:
deprecated: false
description: Returns all LLM pricing rules for the authenticated org, with pagination.
operationId: ListLLMPricingRules
parameters:
- in: query
name: offset
schema:
type: integer
- in: query
name: limit
schema:
type: integer
responses:
"200":
content:
application/json:
schema:
properties:
data:
$ref: '#/components/schemas/LlmpricingruletypesGettablePricingRules'
status:
type: string
required:
- status
- data
type: object
description: OK
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Bad Request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- VIEWER
- tokenizer:
- VIEWER
summary: List pricing rules
tags:
- llmpricingrules
put:
deprecated: false
description: Single write endpoint used by both the user and the Zeus sync job.
Per-rule match is by id, then sourceId, then insert. Override rows (is_override=true)
are fully preserved when the request does not provide isOverride; only synced_at
is stamped.
operationId: UpdateLLMPricingRules
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/LlmpricingruletypesUpdatableLLMPricingRules'
responses:
"204":
description: No Content
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Bad Request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- ADMIN
- tokenizer:
- ADMIN
summary: Bulk update pricing rules
tags:
- llmpricingrules
/api/v1/llm_pricing_rules/{id}:
delete:
deprecated: false
description: Hard-deletes a pricing rule. If auto-synced, it will be recreated
on the next sync cycle.
operationId: DeleteLLMPricingRule
parameters:
- in: path
name: id
required: true
schema:
type: string
responses:
"204":
description: No Content
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Not Found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- ADMIN
- tokenizer:
- ADMIN
summary: Delete a pricing rule
tags:
- llmpricingrules
get:
deprecated: false
description: Returns a single LLM pricing rule by ID.
operationId: GetLLMPricingRule
parameters:
- in: path
name: id
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
properties:
data:
$ref: '#/components/schemas/LlmpricingruletypesLLMPricingRule'
status:
type: string
required:
- status
- data
type: object
description: OK
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Not Found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- VIEWER
- tokenizer:
- VIEWER
summary: Get a pricing rule
tags:
- llmpricingrules
/api/v1/logs/promote_paths:
get:
deprecated: false

View File

@@ -60,7 +60,7 @@ function PrivateRoute({ children }: PrivateRouteProps): JSX.Element {
if (org && org.length > 0 && org[0].id !== undefined) {
return org[0];
}
return;
return undefined;
}, [org]);
const { data: usersData, isFetching: isFetchingUsers } = useListUsers({
@@ -192,7 +192,7 @@ function PrivateRoute({ children }: PrivateRouteProps): JSX.Element {
if (isPrivate) {
if (isLoggedInState) {
const route = routePermission[key];
if (route && route.some((e) => e === user.role) === undefined) {
if (route && route.find((e) => e === user.role) === undefined) {
return <Redirect to={ROUTES.UN_AUTHORIZED} />;
}
} else {

View File

@@ -320,12 +320,12 @@ function App(): JSX.Element {
}),
],
// Performance Monitoring
tracesSampleRate: 1, // Capture 100% of the transactions
tracesSampleRate: 1.0, // Capture 100% of the transactions
// Set 'tracePropagationTargets' to control for which URLs distributed tracing should be enabled
tracePropagationTargets: [],
// Session Replay
replaysSessionSampleRate: 0.1, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production.
replaysOnErrorSampleRate: 1, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur.
replaysOnErrorSampleRate: 1.0, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur.
beforeSend(event) {
const sessionReplayUrl = posthog.get_session_replay_url?.({
withTimestamp: true,

View File

@@ -24,7 +24,7 @@ export function ErrorResponseHandler(error: AxiosError): ErrorResponse {
const { errors, error } = data;
const errorMessage =
Array.isArray(errors) && errors.length > 0 ? errors[0].msg : error;
Array.isArray(errors) && errors.length >= 1 ? errors[0].msg : error;
return {
statusCode,

View File

@@ -21,12 +21,12 @@ const dashboardVariablesQuery = async (
});
const timeVariables: Record<string, number> = {
start_timestamp_ms: Number.parseInt(start, 10) * 1e3,
end_timestamp_ms: Number.parseInt(end, 10) * 1e3,
start_timestamp_nano: Number.parseInt(start, 10) * 1e9,
end_timestamp_nano: Number.parseInt(end, 10) * 1e9,
start_timestamp: Number.parseInt(start, 10),
end_timestamp: Number.parseInt(end, 10),
start_timestamp_ms: parseInt(start, 10) * 1e3,
end_timestamp_ms: parseInt(end, 10) * 1e3,
start_timestamp_nano: parseInt(start, 10) * 1e9,
end_timestamp_nano: parseInt(end, 10) * 1e9,
start_timestamp: parseInt(start, 10),
end_timestamp: parseInt(end, 10),
};
const payload = { ...props };

View File

@@ -104,7 +104,7 @@ describe('getFieldKeys API', () => {
const result = await getFieldKeys('traces');
// Verify the returned structure matches SuccessResponseV2 format
expect(result).toStrictEqual({
expect(result).toEqual({
httpStatusCode: 200,
data: mockSuccessResponse.data.data,
});

View File

@@ -199,7 +199,7 @@ describe('getFieldValues API', () => {
const result = await getFieldValues('traces', 'service.name');
// Verify the returned structure matches SuccessResponseV2 format
expect(result).toStrictEqual({
expect(result).toEqual({
httpStatusCode: 200,
data: expect.objectContaining({
values: expect.any(Object),

View File

@@ -0,0 +1,398 @@
/**
* ! Do not edit manually
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'yarn generate:api'
* SigNoz
*/
import { useMutation, useQuery } from 'react-query';
import type {
InvalidateOptions,
MutationFunction,
QueryClient,
QueryFunction,
QueryKey,
UseMutationOptions,
UseMutationResult,
UseQueryOptions,
UseQueryResult,
} from 'react-query';
import type {
DeleteLLMPricingRulePathParameters,
GetLLMPricingRule200,
GetLLMPricingRulePathParameters,
ListLLMPricingRules200,
ListLLMPricingRulesParams,
LlmpricingruletypesUpdatableLLMPricingRulesDTO,
RenderErrorResponseDTO,
} from '../sigNoz.schemas';
import { GeneratedAPIInstance } from '../../../generatedAPIInstance';
import type { ErrorType, BodyType } from '../../../generatedAPIInstance';
/**
* Returns all LLM pricing rules for the authenticated org, with pagination.
* @summary List pricing rules
*/
export const listLLMPricingRules = (
params?: ListLLMPricingRulesParams,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<ListLLMPricingRules200>({
url: `/api/v1/llm_pricing_rules`,
method: 'GET',
params,
signal,
});
};
export const getListLLMPricingRulesQueryKey = (
params?: ListLLMPricingRulesParams,
) => {
return [`/api/v1/llm_pricing_rules`, ...(params ? [params] : [])] as const;
};
export const getListLLMPricingRulesQueryOptions = <
TData = Awaited<ReturnType<typeof listLLMPricingRules>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
params?: ListLLMPricingRulesParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listLLMPricingRules>>,
TError,
TData
>;
},
) => {
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getListLLMPricingRulesQueryKey(params);
const queryFn: QueryFunction<
Awaited<ReturnType<typeof listLLMPricingRules>>
> = ({ signal }) => listLLMPricingRules(params, signal);
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof listLLMPricingRules>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type ListLLMPricingRulesQueryResult = NonNullable<
Awaited<ReturnType<typeof listLLMPricingRules>>
>;
export type ListLLMPricingRulesQueryError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary List pricing rules
*/
export function useListLLMPricingRules<
TData = Awaited<ReturnType<typeof listLLMPricingRules>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
params?: ListLLMPricingRulesParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listLLMPricingRules>>,
TError,
TData
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getListLLMPricingRulesQueryOptions(params, options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
query.queryKey = queryOptions.queryKey;
return query;
}
/**
* @summary List pricing rules
*/
export const invalidateListLLMPricingRules = async (
queryClient: QueryClient,
params?: ListLLMPricingRulesParams,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getListLLMPricingRulesQueryKey(params) },
options,
);
return queryClient;
};
/**
* Single write endpoint used by both the user and the Zeus sync job. Per-rule match is by id, then sourceId, then insert. Override rows (is_override=true) are fully preserved when the request does not provide isOverride; only synced_at is stamped.
* @summary Bulk update pricing rules
*/
export const updateLLMPricingRules = (
llmpricingruletypesUpdatableLLMPricingRulesDTO: BodyType<LlmpricingruletypesUpdatableLLMPricingRulesDTO>,
) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/llm_pricing_rules`,
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
data: llmpricingruletypesUpdatableLLMPricingRulesDTO,
});
};
export const getUpdateLLMPricingRulesMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateLLMPricingRules>>,
TError,
{ data: BodyType<LlmpricingruletypesUpdatableLLMPricingRulesDTO> },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof updateLLMPricingRules>>,
TError,
{ data: BodyType<LlmpricingruletypesUpdatableLLMPricingRulesDTO> },
TContext
> => {
const mutationKey = ['updateLLMPricingRules'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof updateLLMPricingRules>>,
{ data: BodyType<LlmpricingruletypesUpdatableLLMPricingRulesDTO> }
> = (props) => {
const { data } = props ?? {};
return updateLLMPricingRules(data);
};
return { mutationFn, ...mutationOptions };
};
export type UpdateLLMPricingRulesMutationResult = NonNullable<
Awaited<ReturnType<typeof updateLLMPricingRules>>
>;
export type UpdateLLMPricingRulesMutationBody =
BodyType<LlmpricingruletypesUpdatableLLMPricingRulesDTO>;
export type UpdateLLMPricingRulesMutationError =
ErrorType<RenderErrorResponseDTO>;
/**
* @summary Bulk update pricing rules
*/
export const useUpdateLLMPricingRules = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateLLMPricingRules>>,
TError,
{ data: BodyType<LlmpricingruletypesUpdatableLLMPricingRulesDTO> },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof updateLLMPricingRules>>,
TError,
{ data: BodyType<LlmpricingruletypesUpdatableLLMPricingRulesDTO> },
TContext
> => {
const mutationOptions = getUpdateLLMPricingRulesMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Hard-deletes a pricing rule. If auto-synced, it will be recreated on the next sync cycle.
* @summary Delete a pricing rule
*/
export const deleteLLMPricingRule = ({
id,
}: DeleteLLMPricingRulePathParameters) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/llm_pricing_rules/${id}`,
method: 'DELETE',
});
};
export const getDeleteLLMPricingRuleMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteLLMPricingRule>>,
TError,
{ pathParams: DeleteLLMPricingRulePathParameters },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof deleteLLMPricingRule>>,
TError,
{ pathParams: DeleteLLMPricingRulePathParameters },
TContext
> => {
const mutationKey = ['deleteLLMPricingRule'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof deleteLLMPricingRule>>,
{ pathParams: DeleteLLMPricingRulePathParameters }
> = (props) => {
const { pathParams } = props ?? {};
return deleteLLMPricingRule(pathParams);
};
return { mutationFn, ...mutationOptions };
};
export type DeleteLLMPricingRuleMutationResult = NonNullable<
Awaited<ReturnType<typeof deleteLLMPricingRule>>
>;
export type DeleteLLMPricingRuleMutationError =
ErrorType<RenderErrorResponseDTO>;
/**
* @summary Delete a pricing rule
*/
export const useDeleteLLMPricingRule = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteLLMPricingRule>>,
TError,
{ pathParams: DeleteLLMPricingRulePathParameters },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof deleteLLMPricingRule>>,
TError,
{ pathParams: DeleteLLMPricingRulePathParameters },
TContext
> => {
const mutationOptions = getDeleteLLMPricingRuleMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Returns a single LLM pricing rule by ID.
* @summary Get a pricing rule
*/
export const getLLMPricingRule = (
{ id }: GetLLMPricingRulePathParameters,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<GetLLMPricingRule200>({
url: `/api/v1/llm_pricing_rules/${id}`,
method: 'GET',
signal,
});
};
export const getGetLLMPricingRuleQueryKey = ({
id,
}: GetLLMPricingRulePathParameters) => {
return [`/api/v1/llm_pricing_rules/${id}`] as const;
};
export const getGetLLMPricingRuleQueryOptions = <
TData = Awaited<ReturnType<typeof getLLMPricingRule>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
{ id }: GetLLMPricingRulePathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getLLMPricingRule>>,
TError,
TData
>;
},
) => {
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getGetLLMPricingRuleQueryKey({ id });
const queryFn: QueryFunction<
Awaited<ReturnType<typeof getLLMPricingRule>>
> = ({ signal }) => getLLMPricingRule({ id }, signal);
return {
queryKey,
queryFn,
enabled: !!id,
...queryOptions,
} as UseQueryOptions<
Awaited<ReturnType<typeof getLLMPricingRule>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type GetLLMPricingRuleQueryResult = NonNullable<
Awaited<ReturnType<typeof getLLMPricingRule>>
>;
export type GetLLMPricingRuleQueryError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Get a pricing rule
*/
export function useGetLLMPricingRule<
TData = Awaited<ReturnType<typeof getLLMPricingRule>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
{ id }: GetLLMPricingRulePathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof getLLMPricingRule>>,
TError,
TData
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getGetLLMPricingRuleQueryOptions({ id }, options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
query.queryKey = queryOptions.queryKey;
return query;
}
/**
* @summary Get a pricing rule
*/
export const invalidateGetLLMPricingRule = async (
queryClient: QueryClient,
{ id }: GetLLMPricingRulePathParameters,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getGetLLMPricingRuleQueryKey({ id }) },
options,
);
return queryClient;
};

View File

@@ -3278,6 +3278,173 @@ export enum InframonitoringtypesResponseTypeDTO {
list = 'list',
grouped_list = 'grouped_list',
}
export interface LlmpricingruletypesGettablePricingRulesDTO {
/**
* @type array
* @nullable true
*/
items: LlmpricingruletypesLLMPricingRuleDTO[] | null;
/**
* @type integer
*/
limit: number;
/**
* @type integer
*/
offset: number;
/**
* @type integer
*/
total: number;
}
export interface LlmpricingruletypesLLMPricingRuleDTO {
cacheMode: LlmpricingruletypesLLMPricingRuleCacheModeDTO;
/**
* @type number
* @format double
*/
costCacheRead: number;
/**
* @type number
* @format double
*/
costCacheWrite: number;
/**
* @type number
* @format double
*/
costInput: number;
/**
* @type number
* @format double
*/
costOutput: number;
/**
* @type string
* @format date-time
*/
createdAt?: Date;
/**
* @type string
*/
createdBy?: string;
/**
* @type boolean
*/
enabled: boolean;
/**
* @type string
*/
id: string;
/**
* @type boolean
*/
isOverride: boolean;
/**
* @type string
*/
modelName: string;
/**
* @type array
* @nullable true
*/
modelPattern: string[] | null;
/**
* @type string
*/
orgId: string;
/**
* @type string
*/
sourceId?: string;
/**
* @type string
* @format date-time
* @nullable true
*/
syncedAt?: Date | null;
unit: LlmpricingruletypesLLMPricingRuleUnitDTO;
/**
* @type string
* @format date-time
*/
updatedAt?: Date;
/**
* @type string
*/
updatedBy?: string;
}
export enum LlmpricingruletypesLLMPricingRuleCacheModeDTO {
subtract = 'subtract',
additive = 'additive',
unknown = 'unknown',
}
export enum LlmpricingruletypesLLMPricingRuleUnitDTO {
per_million_tokens = 'per_million_tokens',
}
export interface LlmpricingruletypesUpdatableLLMPricingRuleDTO {
cacheMode: LlmpricingruletypesLLMPricingRuleCacheModeDTO;
/**
* @type number
* @format double
*/
costCacheRead: number;
/**
* @type number
* @format double
*/
costCacheWrite: number;
/**
* @type number
* @format double
*/
costInput: number;
/**
* @type number
* @format double
*/
costOutput: number;
/**
* @type boolean
*/
enabled: boolean;
/**
* @type string
* @nullable true
*/
id?: string | null;
/**
* @type boolean
* @nullable true
*/
isOverride?: boolean | null;
/**
* @type string
*/
modelName: string;
/**
* @type array
* @nullable true
*/
modelPattern: string[] | null;
/**
* @type string
* @nullable true
*/
sourceId?: string | null;
unit: LlmpricingruletypesLLMPricingRuleUnitDTO;
}
export interface LlmpricingruletypesUpdatableLLMPricingRulesDTO {
/**
* @type array
* @nullable true
*/
rules: LlmpricingruletypesUpdatableLLMPricingRuleDTO[] | null;
}
export interface MetricsexplorertypesInspectMetricsRequestDTO {
/**
* @type integer
@@ -6654,6 +6821,41 @@ export type CreateInvite201 = {
status: string;
};
export type ListLLMPricingRulesParams = {
/**
* @type integer
* @description undefined
*/
offset?: number;
/**
* @type integer
* @description undefined
*/
limit?: number;
};
export type ListLLMPricingRules200 = {
data: LlmpricingruletypesGettablePricingRulesDTO;
/**
* @type string
*/
status: string;
};
export type DeleteLLMPricingRulePathParameters = {
id: string;
};
export type GetLLMPricingRulePathParameters = {
id: string;
};
export type GetLLMPricingRule200 = {
data: LlmpricingruletypesLLMPricingRuleDTO;
/**
* @type string
*/
status: string;
};
export type ListPromotedAndIndexedPaths200 = {
/**
* @type array

View File

@@ -32,7 +32,7 @@ export const interceptorsResponse = (
): Promise<AxiosResponse<any>> => {
if ((value.config as any)?.metadata) {
const duration =
Date.now() - (value.config as any).metadata.startTime;
new Date().getTime() - (value.config as any).metadata.startTime;
if (duration > RESPONSE_TIMEOUT_THRESHOLD && value.config.url !== '/event') {
eventEmitter.emit(Events.SLOW_API_WARNING, true, {
@@ -55,7 +55,7 @@ export const interceptorsRequestResponse = (
): InternalAxiosRequestConfig => {
// Attach metadata safely (not sent with the request)
Object.defineProperty(value, 'metadata', {
value: { startTime: Date.now() },
value: { startTime: new Date().getTime() },
enumerable: false, // Prevents it from being included in the request
});
@@ -143,7 +143,7 @@ export const interceptorRejected = async (
Logout();
}
}
} catch {
} catch (error) {
Logout();
}
}
@@ -160,7 +160,7 @@ export const interceptorRejected = async (
const interceptorRejectedBase = async (
value: AxiosResponse<any>,
): Promise<AxiosResponse<any>> => { throw value; };
): Promise<AxiosResponse<any>> => Promise.reject(value);
const instance = axios.create({
baseURL: `${ENVIRONMENT.baseURL}${apiV1}`,

View File

@@ -76,10 +76,10 @@ describe('interceptorRejected', () => {
}
const mockAxiosFn = (axios as unknown) as jest.Mock;
expect(mockAxiosFn.mock.calls).toHaveLength(1);
expect(mockAxiosFn.mock.calls.length).toBe(1);
const retryCallConfig = mockAxiosFn.mock.calls[0][0];
expect(Array.isArray(JSON.parse(retryCallConfig.data))).toBe(true);
expect(JSON.parse(retryCallConfig.data)).toStrictEqual(arrayPayload);
expect(JSON.parse(retryCallConfig.data)).toEqual(arrayPayload);
});
it('should preserve object payload structure when retrying a 401 request', async () => {
@@ -112,9 +112,9 @@ describe('interceptorRejected', () => {
}
const mockAxiosFn = (axios as unknown) as jest.Mock;
expect(mockAxiosFn.mock.calls).toHaveLength(1);
expect(mockAxiosFn.mock.calls.length).toBe(1);
const retryCallConfig = mockAxiosFn.mock.calls[0][0];
expect(JSON.parse(retryCallConfig.data)).toStrictEqual(objectPayload);
expect(JSON.parse(retryCallConfig.data)).toEqual(objectPayload);
});
it('should handle undefined data gracefully when retrying', async () => {
@@ -145,7 +145,7 @@ describe('interceptorRejected', () => {
}
const mockAxiosFn = (axios as unknown) as jest.Mock;
expect(mockAxiosFn.mock.calls).toHaveLength(1);
expect(mockAxiosFn.mock.calls.length).toBe(1);
const retryCallConfig = mockAxiosFn.mock.calls[0][0];
expect(retryCallConfig.data).toBeUndefined();
});

View File

@@ -37,11 +37,11 @@ export const downloadExportData = async (
const filename =
response.headers['content-disposition']
?.split('filename=')[1]
?.replaceAll(/["']/g, '') || `exported_data.${props.format || 'txt'}`;
?.replace(/["']/g, '') || `exported_data.${props.format || 'txt'}`;
link.setAttribute('download', filename);
document.body.append(link);
document.body.appendChild(link);
link.click();
link.remove();
URL.revokeObjectURL(url);

View File

@@ -101,7 +101,7 @@ describe('convertV5ResponseToLegacy', () => {
const q = result.payload.data.result[0];
expect(q.queryName).toBe('A');
expect(q.legend).toBe('{{service.name}}');
expect(q.series?.[0]).toStrictEqual(
expect(q.series?.[0]).toEqual(
expect.objectContaining({
labels: { 'service.name': 'adservice' },
values: [
@@ -190,7 +190,7 @@ describe('convertV5ResponseToLegacy', () => {
expect(result.payload.data.resultType).toBe('scalar');
const [tableEntry] = result.payload.data.result;
expect(tableEntry.table?.columns).toStrictEqual([
expect(tableEntry.table?.columns).toEqual([
{
name: 'service.name',
queryName: 'A',
@@ -206,7 +206,7 @@ describe('convertV5ResponseToLegacy', () => {
},
{ name: 'F1', queryName: 'F1', isValueColumn: true, id: 'F1' },
]);
expect(tableEntry.table?.rows?.[0]).toStrictEqual({
expect(tableEntry.table?.rows?.[0]).toEqual({
data: {
'service.name': 'adservice',
'A.count()': 606,
@@ -263,7 +263,7 @@ describe('convertV5ResponseToLegacy', () => {
expect(result.payload.data.resultType).toBe('scalar');
const [tableEntry] = result.payload.data.result;
expect(tableEntry.table?.columns).toStrictEqual([
expect(tableEntry.table?.columns).toEqual([
{
name: 'service.name',
queryName: 'A',
@@ -273,7 +273,7 @@ describe('convertV5ResponseToLegacy', () => {
// Single aggregation: name resolves to legend, id resolves to queryName
{ name: '{{service.name}}', queryName: 'A', isValueColumn: true, id: 'A' },
]);
expect(tableEntry.table?.rows?.[0]).toStrictEqual({
expect(tableEntry.table?.rows?.[0]).toEqual({
data: {
'service.name': 'adservice',
A: 580,

View File

@@ -85,7 +85,7 @@ function convertTimeSeriesData(
const { index, alias } = aggregation;
const seriesData = aggregation[seriesKey];
if (!seriesData || seriesData.length === 0) {
if (!seriesData || !seriesData.length) {
return [];
}

View File

@@ -104,7 +104,7 @@ describe('prepareQueryRangePayloadV5', () => {
const result = prepareQueryRangePayloadV5(props);
expect(result).toStrictEqual(
expect(result).toEqual(
expect.objectContaining({
legendMap: { A: 'Legend A', F1: 'Formula Legend' },
queryPayload: expect.objectContaining({
@@ -154,7 +154,7 @@ describe('prepareQueryRangePayloadV5', () => {
);
// Legend map combines builder and formulas
expect(result.legendMap).toStrictEqual({ A: 'Legend A', F1: 'Formula Legend' });
expect(result.legendMap).toEqual({ A: 'Legend A', F1: 'Formula Legend' });
const payload: QueryRangePayloadV5 = result.queryPayload;
@@ -166,7 +166,7 @@ describe('prepareQueryRangePayloadV5', () => {
expect(payload.formatOptions?.fillGaps).toBe(true);
// Variables mapped as { key: { value } }
expect(payload.variables).toStrictEqual({
expect(payload.variables).toEqual({
svc: { value: 'api' },
count: { value: 5 },
flag: { value: true },
@@ -226,7 +226,7 @@ describe('prepareQueryRangePayloadV5', () => {
const result = prepareQueryRangePayloadV5(props);
expect(result).toStrictEqual(
expect(result).toEqual(
expect.objectContaining({
legendMap: { A: 'LP' },
queryPayload: expect.objectContaining({
@@ -255,7 +255,7 @@ describe('prepareQueryRangePayloadV5', () => {
}),
);
expect(result.legendMap).toStrictEqual({ A: 'LP' });
expect(result.legendMap).toEqual({ A: 'LP' });
const payload: QueryRangePayloadV5 = result.queryPayload;
expect(payload.requestType).toBe('time_series');
@@ -296,7 +296,7 @@ describe('prepareQueryRangePayloadV5', () => {
const result = prepareQueryRangePayloadV5(props);
expect(result).toStrictEqual(
expect(result).toEqual(
expect.objectContaining({
legendMap: { Q: 'LC' },
queryPayload: expect.objectContaining({
@@ -324,7 +324,7 @@ describe('prepareQueryRangePayloadV5', () => {
}),
);
expect(result.legendMap).toStrictEqual({ Q: 'LC' });
expect(result.legendMap).toEqual({ Q: 'LC' });
const payload: QueryRangePayloadV5 = result.queryPayload;
expect(payload.requestType).toBe('scalar');
@@ -353,7 +353,7 @@ describe('prepareQueryRangePayloadV5', () => {
const result = prepareQueryRangePayloadV5(props);
expect(result).toStrictEqual(
expect(result).toEqual(
expect.objectContaining({
legendMap: {},
queryPayload: expect.objectContaining({
@@ -397,7 +397,7 @@ describe('prepareQueryRangePayloadV5', () => {
const result = prepareQueryRangePayloadV5(props);
expect(result).toStrictEqual(
expect(result).toEqual(
expect.objectContaining({
legendMap: { A: 'Legend A' },
queryPayload: expect.objectContaining({
@@ -471,7 +471,7 @@ describe('prepareQueryRangePayloadV5', () => {
const result = prepareQueryRangePayloadV5(props);
expect(result).toStrictEqual(
expect(result).toEqual(
expect.objectContaining({
legendMap: { A: 'Legend A' },
queryPayload: expect.objectContaining({
@@ -585,7 +585,7 @@ describe('prepareQueryRangePayloadV5', () => {
const result = prepareQueryRangePayloadV5(props);
expect(result).toStrictEqual(
expect(result).toEqual(
expect.objectContaining({
legendMap: { A: '{{service.name}}' },
queryPayload: expect.objectContaining({
@@ -684,7 +684,7 @@ describe('prepareQueryRangePayloadV5', () => {
const result = prepareQueryRangePayloadV5(props);
expect(result.legendMap).toStrictEqual({ A: 'Legend A' });
expect(result.legendMap).toEqual({ A: 'Legend A' });
expect(result.queryPayload.compositeQuery.queries).toHaveLength(1);
const builderQuery = result.queryPayload.compositeQuery.queries.find(
@@ -694,7 +694,7 @@ describe('prepareQueryRangePayloadV5', () => {
expect(logSpec.name).toBe('A');
expect(logSpec.signal).toBe('logs');
expect(logSpec.filter).toStrictEqual({
expect(logSpec.filter).toEqual({
expression:
"service.name = 'payment-service' AND http.status_code >= 400 AND message contains 'error'",
});
@@ -731,7 +731,7 @@ describe('prepareQueryRangePayloadV5', () => {
(q) => q.type === 'builder_query',
) as QueryEnvelope;
const logSpec = builderQuery.spec as LogBuilderQuery;
expect(logSpec.filter).toStrictEqual({ expression: 'http.status_code >= 500' });
expect(logSpec.filter).toEqual({ expression: 'http.status_code >= 500' });
});
it('derives expression from filters when filter is undefined', () => {
@@ -775,7 +775,7 @@ describe('prepareQueryRangePayloadV5', () => {
(q) => q.type === 'builder_query',
) as QueryEnvelope;
const logSpec = builderQuery.spec as LogBuilderQuery;
expect(logSpec.filter).toStrictEqual({ expression: "service.name = 'checkout'" });
expect(logSpec.filter).toEqual({ expression: "service.name = 'checkout'" });
});
it('prefers filter.expression over filters when both are present', () => {
@@ -819,7 +819,7 @@ describe('prepareQueryRangePayloadV5', () => {
(q) => q.type === 'builder_query',
) as QueryEnvelope;
const logSpec = builderQuery.spec as LogBuilderQuery;
expect(logSpec.filter).toStrictEqual({ expression: "service.name = 'frontend'" });
expect(logSpec.filter).toEqual({ expression: "service.name = 'frontend'" });
});
it('returns empty expression when neither filter nor filters provided', () => {
@@ -853,7 +853,7 @@ describe('prepareQueryRangePayloadV5', () => {
(q) => q.type === 'builder_query',
) as QueryEnvelope;
const logSpec = builderQuery.spec as LogBuilderQuery;
expect(logSpec.filter).toStrictEqual({ expression: '' });
expect(logSpec.filter).toEqual({ expression: '' });
});
it('returns empty expression when filters provided with empty items', () => {
@@ -887,6 +887,6 @@ describe('prepareQueryRangePayloadV5', () => {
(q) => q.type === 'builder_query',
) as QueryEnvelope;
const logSpec = builderQuery.spec as LogBuilderQuery;
expect(logSpec.filter).toStrictEqual({ expression: '' });
expect(logSpec.filter).toEqual({ expression: '' });
});
});

View File

@@ -243,7 +243,7 @@ export function parseAggregations(
let alias = match[2] || availableAlias; // Use provided alias or availableAlias if not matched
if (alias) {
// Remove quotes if present
alias = alias.replaceAll(/^['"]|['"]$/g, '');
alias = alias.replace(/^['"]|['"]$/g, '');
result.push({ expression: expr, alias });
} else {
result.push({ expression: expr });
@@ -634,8 +634,8 @@ export const prepareQueryRangePayloadV5 = ({
// Create V5 payload
const queryPayload: QueryRangePayloadV5 = {
schemaVersion: 'v1',
start: startTime ? startTime * 1e3 : Number.parseInt(start, 10) * 1e3,
end: endTime ? endTime * 1e3 : Number.parseInt(end, 10) * 1e3,
start: startTime ? startTime * 1e3 : parseInt(start, 10) * 1e3,
end: endTime ? endTime * 1e3 : parseInt(end, 10) * 1e3,
requestType,
compositeQuery: {
queries,

View File

@@ -13,7 +13,7 @@ function AppLoading(): JSX.Element {
try {
const theme = get(LOCALSTORAGE.THEME);
return theme !== THEME_MODE.LIGHT; // Return true for dark, false for light
} catch {
} catch (error) {
// If localStorage is not available, default to dark theme
return true;
}

View File

@@ -23,7 +23,7 @@ describe('AppLoading', () => {
it('should render loading screen with dark theme by default', () => {
// Mock localStorage to return dark theme (or undefined for default)
mockGet.mockReturnValue();
mockGet.mockReturnValue(undefined);
render(<AppLoading />);
@@ -40,7 +40,7 @@ describe('AppLoading', () => {
it('should have proper structure and content', () => {
// Mock localStorage to return dark theme
mockGet.mockReturnValue();
mockGet.mockReturnValue(undefined);
render(<AppLoading />);

View File

@@ -51,7 +51,7 @@ export function FilterSelect({
// Memoize options to include the typed value if not present
const mergedOptions = useMemo(() => {
if (
searchValue.trim().length > 0 &&
!!searchValue.trim().length &&
!options.some((opt) => opt.value === searchValue)
) {
return [{ value: searchValue, label: searchValue }, ...options];

View File

@@ -57,7 +57,7 @@ export const useGetValueFromWidget = (
return 'Error';
}
const value = Number.parseFloat(
const value = parseFloat(
query.data?.payload?.data?.newResult?.data?.result?.[0]?.series?.[0]
?.values?.[0]?.value || 'NaN',
);

View File

@@ -104,11 +104,11 @@ export const createFiltersFromData = (
op: string;
value: string;
}> => {
const excludeKeys = new Set(['A', 'A_without_unit']);
const excludeKeys = ['A', 'A_without_unit'];
return (
Object.entries(data)
.filter(([key]) => !excludeKeys.has(key))
.filter(([key]) => !excludeKeys.includes(key))
// eslint-disable-next-line sonarjs/no-identical-functions
.map(([key, value]) => ({
id: uuidv4(),

View File

@@ -440,8 +440,8 @@ function ClientSideQBSearch(
const values: Array<string | number | boolean> = [];
const { tagValue } = getTagToken(searchValue);
if (isArray(tagValue)) {
if (!isEmpty(tagValue.at(-1))) {
values.push(tagValue.at(-1));
if (!isEmpty(tagValue[tagValue.length - 1])) {
values.push(tagValue[tagValue.length - 1]);
}
} else if (!isEmpty(tagValue)) {
values.push(tagValue);
@@ -488,7 +488,7 @@ function ClientSideQBSearch(
const computedTagValue =
tag.value &&
Array.isArray(tag.value) &&
tag.value.at(-1) === ''
tag.value[tag.value.length - 1] === ''
? tag.value?.slice(0, -1)
: tag.value ?? '';
filterTags.items.push({
@@ -610,7 +610,7 @@ function ClientSideQBSearch(
searchValue={searchValue}
className={className}
rootClassName="query-builder-search client-side-qb-search"
disabled={attributeKeys.length === 0}
disabled={!attributeKeys.length}
style={selectStyle}
onSearch={handleSearch}
onSelect={handleDropdownSelect}

View File

@@ -147,7 +147,7 @@ function CustomTimePicker({
return `Last ${selectedTime}`;
}
const value = Number.parseInt(match[1], 10);
const value = parseInt(match[1], 10);
const unit = match[2];
// Map unit abbreviations to full words
@@ -312,7 +312,7 @@ function CustomTimePicker({
const match = inputValue.match(/^(\d+)([mhdw])$/) as RegExpMatchArray;
const value = Number.parseInt(match[1], 10);
const value = parseInt(match[1], 10);
const unit = match[2];
const currentTime = dayjs();

View File

@@ -21,7 +21,7 @@ interface RangePickerModalProps {
setIsOpen: Dispatch<SetStateAction<boolean>>;
onCustomDateHandler: (
dateTimeRange: DateTimeRangeType,
lexicalContext?: LexicalContext ,
lexicalContext?: LexicalContext | undefined,
) => void;
selectedTime: string;
onTimeChange?: (

View File

@@ -82,7 +82,7 @@ const createTimezoneEntry = (
name: displayName,
value,
offset,
searchIndex: offset.replaceAll(/ /g, ''),
searchIndex: offset.replace(/ /g, ''),
...(hasDivider && { hasDivider }),
};
};

View File

@@ -13,7 +13,7 @@ import '@testing-library/jest-dom';
import { DownloadFormats, DownloadRowCounts } from './constants';
import DownloadOptionsMenu from './DownloadOptionsMenu';
const mockDownloadExportData = jest.fn().mockResolvedValue();
const mockDownloadExportData = jest.fn().mockResolvedValue(undefined);
jest.mock('api/v1/download/downloadExportData', () => ({
downloadExportData: (...args: any[]): any => mockDownloadExportData(...args),
default: (...args: any[]): any => mockDownloadExportData(...args),
@@ -94,7 +94,7 @@ describe.each([
const testId = `periscope-btn-download-${dataSource}`;
beforeEach(() => {
mockDownloadExportData.mockReset().mockResolvedValue();
mockDownloadExportData.mockReset().mockResolvedValue(undefined);
(message.success as jest.Mock).mockReset();
(message.error as jest.Mock).mockReset();
mockUseQueryBuilder.mockReturnValue({
@@ -213,7 +213,7 @@ describe.each([
const callArgs = mockDownloadExportData.mock.calls[0][0];
const query = callArgs.body.compositeQuery.queries[0];
expect(query.spec.groupBy).toBeUndefined();
expect(query.spec.having).toStrictEqual({ expression: '' });
expect(query.spec.having).toEqual({ expression: '' });
});
});
@@ -238,7 +238,7 @@ describe.each([
expect(mockDownloadExportData).toHaveBeenCalledTimes(1);
const callArgs = mockDownloadExportData.mock.calls[0][0];
const query = callArgs.body.compositeQuery.queries[0];
expect(query.spec.selectFields).toStrictEqual([
expect(query.spec.selectFields).toEqual([
expect.objectContaining({
name: 'http.status',
fieldDataType: 'int64',
@@ -322,7 +322,7 @@ describe('DownloadOptionsMenu for traces with queryTraceOperator', () => {
const testId = `periscope-btn-download-${dataSource}`;
beforeEach(() => {
mockDownloadExportData.mockReset().mockResolvedValue();
mockDownloadExportData.mockReset().mockResolvedValue(undefined);
(message.success as jest.Mock).mockReset();
});

View File

@@ -6,39 +6,39 @@ jest.mock('react-dnd', () => ({
}));
describe('Utils testing of DraggableTableRow component', () => {
it('Should dropHandler return true', () => {
test('Should dropHandler return true', () => {
const monitor = {
isOver: jest.fn().mockReturnValueOnce(true),
} as never;
const dropDataTruthy = dropHandler(monitor);
expect(dropDataTruthy).toStrictEqual({ isOver: true });
expect(dropDataTruthy).toEqual({ isOver: true });
});
it('Should dropHandler return false', () => {
test('Should dropHandler return false', () => {
const monitor = {
isOver: jest.fn().mockReturnValueOnce(false),
} as never;
const dropDataFalsy = dropHandler(monitor);
expect(dropDataFalsy).toStrictEqual({ isOver: false });
expect(dropDataFalsy).toEqual({ isOver: false });
});
it('Should dragHandler return true', () => {
test('Should dragHandler return true', () => {
const monitor = {
isDragging: jest.fn().mockReturnValueOnce(true),
} as never;
const dragDataTruthy = dragHandler(monitor);
expect(dragDataTruthy).toStrictEqual({ isDragging: true });
expect(dragDataTruthy).toEqual({ isDragging: true });
});
it('Should dragHandler return false', () => {
test('Should dragHandler return false', () => {
const monitor = {
isDragging: jest.fn().mockReturnValueOnce(false),
} as never;
const dragDataFalsy = dragHandler(monitor);
expect(dragDataFalsy).toStrictEqual({ isDragging: false });
expect(dragDataFalsy).toEqual({ isDragging: false });
});
});

View File

@@ -361,10 +361,12 @@ describe('EditMemberDrawer', () => {
await user.click(screen.getByRole('button', { name: /delete member/i }));
await expect(screen.findByText(/are you sure you want to delete/i)).resolves.toBeInTheDocument();
expect(
await screen.findByText(/are you sure you want to delete/i),
).toBeInTheDocument();
const confirmBtns = screen.getAllByRole('button', { name: /delete member/i });
await user.click(confirmBtns.at(-1));
await user.click(confirmBtns[confirmBtns.length - 1]);
await waitFor(() => {
expect(mockDeleteMutate).toHaveBeenCalledWith({
@@ -439,10 +441,12 @@ describe('EditMemberDrawer', () => {
await user.click(screen.getByRole('button', { name: /revoke invite/i }));
await expect(screen.findByText(/Are you sure you want to revoke the invite/i)).resolves.toBeInTheDocument();
expect(
await screen.findByText(/Are you sure you want to revoke the invite/i),
).toBeInTheDocument();
const confirmBtns = screen.getAllByRole('button', { name: /revoke invite/i });
await user.click(confirmBtns.at(-1));
await user.click(confirmBtns[confirmBtns.length - 1]);
await waitFor(() => {
expect(mockDeleteMutate).toHaveBeenCalledWith({
@@ -549,7 +553,7 @@ describe('EditMemberDrawer', () => {
const confirmBtns = screen.getAllByRole('button', {
name: /delete member/i,
});
await user.click(confirmBtns.at(-1));
await user.click(confirmBtns[confirmBtns.length - 1]);
await waitFor(() => {
expect(showErrorModal).toHaveBeenCalledWith(
@@ -580,7 +584,7 @@ describe('EditMemberDrawer', () => {
const confirmBtns = screen.getAllByRole('button', {
name: /revoke invite/i,
});
await user.click(confirmBtns.at(-1));
await user.click(confirmBtns[confirmBtns.length - 1]);
await waitFor(() => {
expect(showErrorModal).toHaveBeenCalledWith(

View File

@@ -180,7 +180,7 @@ it('should close the modal when the onCancel event is triggered', async () => {
await waitFor(() => {
// check if the modal is not visible
const modal = document.querySelectorAll('.ant-modal');
const modal = document.getElementsByClassName('ant-modal');
const style = window.getComputedStyle(modal[0]);
expect(style.display).toBe('none');
});

View File

@@ -34,7 +34,7 @@ export const getViewDetailsUsingViewKey: GetViewDetailsUsingViewKey = (
const query = mapQueryDataFromApi(compositeQuery);
return { query, name, id, panelType: compositeQuery.panelType, extraData };
}
return;
return undefined;
};
export const omitIdFromQuery = (query: Query | null): any => ({
@@ -198,7 +198,7 @@ export const deleteViewHandler = ({
export const trimViewName = (viewName: string): string => {
if (viewName.length > 20) {
return `${viewName.slice(0, 20)}...`;
return `${viewName.substring(0, 20)}...`;
}
return viewName;
};

View File

@@ -9,7 +9,7 @@ const getOrCreateLegendList = (
id: string,
isLonger: boolean,
): HTMLUListElement => {
const legendContainer = document.querySelector(`#${id}`);
const legendContainer = document.getElementById(id);
let listContainer = legendContainer?.querySelector('ul');
if (!listContainer) {
@@ -26,7 +26,7 @@ const getOrCreateLegendList = (
listContainer.style.flexWrap = 'wrap';
listContainer.style.justifyContent = 'center';
listContainer.style.fontSize = '0.75rem';
legendContainer?.append(listContainer);
legendContainer?.appendChild(listContainer);
}
return listContainer;
@@ -64,7 +64,7 @@ export const legend = (id: string, isLonger: boolean): Plugin<ChartType> => ({
// li.style.marginTop = '5px';
li.onclick = (): void => {
// @ts-expect-error
// @ts-ignore
const { type } = chart.config;
if (type === 'pie' || type === 'doughnut') {
// Pie and doughnut charts only have a single dataset and visibility is per item
@@ -101,11 +101,11 @@ export const legend = (id: string, isLonger: boolean): Plugin<ChartType> => ({
textContainer.style.textDecoration = item.hidden ? 'line-through' : '';
const text = document.createTextNode(item.text);
textContainer.append(text);
textContainer.appendChild(text);
li.append(boxSpan);
li.append(textContainer);
ul.append(li);
li.appendChild(boxSpan);
li.appendChild(textContainer);
ul.appendChild(li);
}
});
},

View File

@@ -9,7 +9,7 @@ describe('xAxisConfig for Chart', () => {
const start = dayjs();
const end = start.add(10, 'millisecond');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toStrictEqual(
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.millisecond,
);
}
@@ -17,7 +17,7 @@ describe('xAxisConfig for Chart', () => {
const start = dayjs();
const end = start.add(10, 'second');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toStrictEqual(
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.second,
);
}
@@ -25,7 +25,7 @@ describe('xAxisConfig for Chart', () => {
const start = dayjs();
const end = start.add(10, 'minute');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toStrictEqual(
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.minute,
);
}
@@ -33,7 +33,7 @@ describe('xAxisConfig for Chart', () => {
const start = dayjs();
const end = start.add(10, 'hour');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toStrictEqual(
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.hour,
);
}
@@ -41,7 +41,7 @@ describe('xAxisConfig for Chart', () => {
const start = dayjs();
const end = start.add(10, 'day');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toStrictEqual(
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.day,
);
}
@@ -49,7 +49,7 @@ describe('xAxisConfig for Chart', () => {
const start = dayjs();
const end = start.add(10, 'week');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toStrictEqual(
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.week,
);
}
@@ -57,7 +57,7 @@ describe('xAxisConfig for Chart', () => {
const start = dayjs();
const end = start.add(10, 'month');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toStrictEqual(
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.month,
);
}
@@ -65,7 +65,7 @@ describe('xAxisConfig for Chart', () => {
const start = dayjs();
const end = start.add(10, 'year');
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toStrictEqual(
expect(convertTimeRange(start.valueOf(), end.valueOf()).unitName).toEqual(
TIME_UNITS.year,
);
}

View File

@@ -7,7 +7,7 @@ const testFullPrecisionGetYAxisFormattedValue = (
): string => getYAxisFormattedValue(value, format, PrecisionOptionsEnum.FULL);
describe('getYAxisFormattedValue - none (full precision legacy assertions)', () => {
it('large integers and decimals', () => {
test('large integers and decimals', () => {
expect(testFullPrecisionGetYAxisFormattedValue('250034', 'none')).toBe(
'250034',
);
@@ -22,7 +22,7 @@ describe('getYAxisFormattedValue - none (full precision legacy assertions)', ()
);
});
it('preserves leading zeros after decimal until first non-zero', () => {
test('preserves leading zeros after decimal until first non-zero', () => {
expect(testFullPrecisionGetYAxisFormattedValue('1.0000234', 'none')).toBe(
'1.0000234',
);
@@ -31,7 +31,7 @@ describe('getYAxisFormattedValue - none (full precision legacy assertions)', ()
);
});
it('trims to three significant decimals and removes trailing zeros', () => {
test('trims to three significant decimals and removes trailing zeros', () => {
expect(
testFullPrecisionGetYAxisFormattedValue('0.000000250034', 'none'),
).toBe('0.000000250034');
@@ -55,7 +55,7 @@ describe('getYAxisFormattedValue - none (full precision legacy assertions)', ()
).toBe('0.00000025');
});
it('whole numbers normalize', () => {
test('whole numbers normalize', () => {
expect(testFullPrecisionGetYAxisFormattedValue('1000', 'none')).toBe('1000');
expect(testFullPrecisionGetYAxisFormattedValue('99.5458', 'none')).toBe(
'99.5458',
@@ -68,7 +68,7 @@ describe('getYAxisFormattedValue - none (full precision legacy assertions)', ()
);
});
it('strip redundant decimal zeros', () => {
test('strip redundant decimal zeros', () => {
expect(testFullPrecisionGetYAxisFormattedValue('1000.000', 'none')).toBe(
'1000',
);
@@ -78,7 +78,7 @@ describe('getYAxisFormattedValue - none (full precision legacy assertions)', ()
expect(testFullPrecisionGetYAxisFormattedValue('1.000', 'none')).toBe('1');
});
it('edge values', () => {
test('edge values', () => {
expect(testFullPrecisionGetYAxisFormattedValue('0', 'none')).toBe('0');
expect(testFullPrecisionGetYAxisFormattedValue('-0', 'none')).toBe('0');
expect(testFullPrecisionGetYAxisFormattedValue('Infinity', 'none')).toBe('∞');
@@ -92,7 +92,7 @@ describe('getYAxisFormattedValue - none (full precision legacy assertions)', ()
expect(testFullPrecisionGetYAxisFormattedValue('abc123', 'none')).toBe('NaN');
});
it('small decimals keep precision as-is', () => {
test('small decimals keep precision as-is', () => {
expect(testFullPrecisionGetYAxisFormattedValue('0.0001', 'none')).toBe(
'0.0001',
);
@@ -104,7 +104,7 @@ describe('getYAxisFormattedValue - none (full precision legacy assertions)', ()
);
});
it('simple decimals preserved', () => {
test('simple decimals preserved', () => {
expect(testFullPrecisionGetYAxisFormattedValue('0.1', 'none')).toBe('0.1');
expect(testFullPrecisionGetYAxisFormattedValue('0.2', 'none')).toBe('0.2');
expect(testFullPrecisionGetYAxisFormattedValue('0.3', 'none')).toBe('0.3');
@@ -115,7 +115,7 @@ describe('getYAxisFormattedValue - none (full precision legacy assertions)', ()
});
describe('getYAxisFormattedValue - units (full precision legacy assertions)', () => {
it('ms', () => {
test('ms', () => {
expect(testFullPrecisionGetYAxisFormattedValue('1500', 'ms')).toBe('1.5 s');
expect(testFullPrecisionGetYAxisFormattedValue('500', 'ms')).toBe('500 ms');
expect(testFullPrecisionGetYAxisFormattedValue('60000', 'ms')).toBe('1 min');
@@ -127,19 +127,19 @@ describe('getYAxisFormattedValue - units (full precision legacy assertions)', ()
);
});
it('s', () => {
test('s', () => {
expect(testFullPrecisionGetYAxisFormattedValue('90', 's')).toBe('1.5 mins');
expect(testFullPrecisionGetYAxisFormattedValue('30', 's')).toBe('30 s');
expect(testFullPrecisionGetYAxisFormattedValue('3600', 's')).toBe('1 hour');
});
it('m', () => {
test('m', () => {
expect(testFullPrecisionGetYAxisFormattedValue('90', 'm')).toBe('1.5 hours');
expect(testFullPrecisionGetYAxisFormattedValue('30', 'm')).toBe('30 min');
expect(testFullPrecisionGetYAxisFormattedValue('1440', 'm')).toBe('1 day');
});
it('bytes', () => {
test('bytes', () => {
expect(testFullPrecisionGetYAxisFormattedValue('1024', 'bytes')).toBe(
'1 KiB',
);
@@ -149,7 +149,7 @@ describe('getYAxisFormattedValue - units (full precision legacy assertions)', ()
);
});
it('mbytes', () => {
test('mbytes', () => {
expect(testFullPrecisionGetYAxisFormattedValue('1024', 'mbytes')).toBe(
'1 GiB',
);
@@ -161,7 +161,7 @@ describe('getYAxisFormattedValue - units (full precision legacy assertions)', ()
);
});
it('kbytes', () => {
test('kbytes', () => {
expect(testFullPrecisionGetYAxisFormattedValue('1024', 'kbytes')).toBe(
'1 MiB',
);
@@ -173,7 +173,7 @@ describe('getYAxisFormattedValue - units (full precision legacy assertions)', ()
);
});
it('short', () => {
test('short', () => {
expect(testFullPrecisionGetYAxisFormattedValue('1000', 'short')).toBe('1 K');
expect(testFullPrecisionGetYAxisFormattedValue('1500', 'short')).toBe(
'1.5 K',
@@ -201,7 +201,7 @@ describe('getYAxisFormattedValue - units (full precision legacy assertions)', ()
);
});
it('percent', () => {
test('percent', () => {
expect(testFullPrecisionGetYAxisFormattedValue('0.15', 'percent')).toBe(
'0.15%',
);
@@ -235,7 +235,7 @@ describe('getYAxisFormattedValue - units (full precision legacy assertions)', ()
).toBe('1.005555555595959%');
});
it('ratio', () => {
test('ratio', () => {
expect(testFullPrecisionGetYAxisFormattedValue('0.5', 'ratio')).toBe(
'0.5 ratio',
);
@@ -247,7 +247,7 @@ describe('getYAxisFormattedValue - units (full precision legacy assertions)', ()
);
});
it('temperature units', () => {
test('temperature units', () => {
expect(testFullPrecisionGetYAxisFormattedValue('25', 'celsius')).toBe(
'25 °C',
);
@@ -267,13 +267,13 @@ describe('getYAxisFormattedValue - units (full precision legacy assertions)', ()
);
});
it('ms edge cases', () => {
test('ms edge cases', () => {
expect(testFullPrecisionGetYAxisFormattedValue('0', 'ms')).toBe('0 ms');
expect(testFullPrecisionGetYAxisFormattedValue('-1500', 'ms')).toBe('-1.5 s');
expect(testFullPrecisionGetYAxisFormattedValue('Infinity', 'ms')).toBe('∞');
});
it('bytes edge cases', () => {
test('bytes edge cases', () => {
expect(testFullPrecisionGetYAxisFormattedValue('0', 'bytes')).toBe('0 B');
expect(testFullPrecisionGetYAxisFormattedValue('-1024', 'bytes')).toBe(
'-1 KiB',
@@ -282,7 +282,7 @@ describe('getYAxisFormattedValue - units (full precision legacy assertions)', ()
});
describe('getYAxisFormattedValue - precision option tests', () => {
it('precision 0 drops decimal part', () => {
test('precision 0 drops decimal part', () => {
expect(getYAxisFormattedValue('1.2345', 'none', 0)).toBe('1');
expect(getYAxisFormattedValue('0.9999', 'none', 0)).toBe('0');
expect(getYAxisFormattedValue('12345.6789', 'none', 0)).toBe('12345');
@@ -294,7 +294,7 @@ describe('getYAxisFormattedValue - precision option tests', () => {
// with unit
expect(getYAxisFormattedValue('4353.81', 'ms', 0)).toBe('4 s');
});
it('precision 1,2,3,4 decimals', () => {
test('precision 1,2,3,4 decimals', () => {
expect(getYAxisFormattedValue('1.2345', 'none', 1)).toBe('1.2');
expect(getYAxisFormattedValue('1.2345', 'none', 2)).toBe('1.23');
expect(getYAxisFormattedValue('1.2345', 'none', 3)).toBe('1.234');
@@ -345,7 +345,7 @@ describe('getYAxisFormattedValue - precision option tests', () => {
expect(getYAxisFormattedValue('0.123456', 'percent', 4)).toBe('0.1235%'); // approximation
});
it('precision full uses up to DEFAULT_SIGNIFICANT_DIGITS significant digits', () => {
test('precision full uses up to DEFAULT_SIGNIFICANT_DIGITS significant digits', () => {
expect(
getYAxisFormattedValue(
'0.00002625429914148441',

View File

@@ -109,8 +109,8 @@ export const useXAxisTimeUnit = (
};
const time = getTimeStamp(timeStamp as Date | number);
minTimeLocal = Math.min(Number.parseInt(time.toString(), 10), minTimeLocal);
maxTimeLocal = Math.max(Number.parseInt(time.toString(), 10), maxTimeLocal);
minTimeLocal = Math.min(parseInt(time.toString(), 10), minTimeLocal);
maxTimeLocal = Math.max(parseInt(time.toString(), 10), maxTimeLocal);
});
localTime = {

View File

@@ -25,7 +25,7 @@ export const getYAxisFormattedValue = (
format: string,
precision: PrecisionOption = 2, // default precision requested
): string => {
const numValue = Number.parseFloat(value);
const numValue = parseFloat(value);
// Handle non-numeric or special values first.
if (isNaN(numValue)) {
@@ -79,10 +79,10 @@ export const getYAxisFormattedValue = (
}
const formatter = getValueFormat(format);
const formattedValue = formatter(numValue, computeDecimals());
const formattedValue = formatter(numValue, computeDecimals(), undefined);
if (formattedValue.text && formattedValue.text.includes('.')) {
formattedValue.text = formatDecimalWithLeadingZeros(
Number.parseFloat(formattedValue.text),
parseFloat(formattedValue.text),
precision,
);
}

View File

@@ -284,7 +284,7 @@ describe('GuardAuthZ', () => {
expect(
screen.getAllByText(
new RegExp(permission.replaceAll(/[.*+?^${}()|[\]\\]/g, '\\$&')),
new RegExp(permission.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')),
).length,
).toBeGreaterThan(0);
expect(screen.queryByText('Protected Content')).not.toBeInTheDocument();

View File

@@ -90,9 +90,11 @@ describe('InviteMembersModal', () => {
screen.getByRole('button', { name: /invite team members/i }),
);
await expect(screen.findByText(
expect(
await screen.findByText(
'Please enter valid emails and select roles for team members',
)).resolves.toBeInTheDocument();
),
).toBeInTheDocument();
});
it('shows email-only message when email is invalid but role is selected', async () => {
@@ -110,7 +112,9 @@ describe('InviteMembersModal', () => {
screen.getByRole('button', { name: /invite team members/i }),
);
await expect(screen.findByText('Please enter valid emails for team members')).resolves.toBeInTheDocument();
expect(
await screen.findByText('Please enter valid emails for team members'),
).toBeInTheDocument();
});
it('shows role-only message when email is valid but role is missing', async () => {
@@ -126,7 +130,9 @@ describe('InviteMembersModal', () => {
screen.getByRole('button', { name: /invite team members/i }),
);
await expect(screen.findByText('Please select roles for team members')).resolves.toBeInTheDocument();
expect(
await screen.findByText('Please select roles for team members'),
).toBeInTheDocument();
});
});
@@ -198,7 +204,7 @@ describe('InviteMembersModal', () => {
await user.type(emailInputs[1], 'bob@signoz.io');
await user.click(screen.getAllByText('Select roles')[0]);
const editorOptions = await screen.findAllByText('Editor');
await user.click(editorOptions.at(-1));
await user.click(editorOptions[editorOptions.length - 1]);
await user.click(
screen.getByRole('button', { name: /invite team members/i }),
@@ -250,7 +256,7 @@ describe('InviteMembersModal', () => {
await user.type(emailInputs[1], 'bob@signoz.io');
await user.click(screen.getAllByText('Select roles')[0]);
const editorOptions = await screen.findAllByText('Editor');
await user.click(editorOptions.at(-1));
await user.click(editorOptions[editorOptions.length - 1]);
await user.click(
screen.getByRole('button', { name: /invite team members/i }),

View File

@@ -26,7 +26,7 @@ function QueryBuilderSearchWrapper({
const tagFiltersLength = tagFilters.items.length;
if (
(!tagFiltersLength && (!filters || filters.items.length === 0)) ||
(!tagFiltersLength && (!filters || !filters.items.length)) ||
tagFiltersLength === filters?.items.length ||
!contextQuery
) {

View File

@@ -163,7 +163,7 @@ function LogDetailInner({
}, [log.id, logs, onNavigateLog, onScrollToLog, selectedView]);
const listQuery = useMemo(() => {
if (!stagedQuery || stagedQuery.builder.queryData.length === 0) {
if (!stagedQuery || stagedQuery.builder.queryData.length < 1) {
return null;
}

View File

@@ -27,7 +27,7 @@ describe('getLogIndicatorType', () => {
expect(getLogIndicatorType(log)).toBe('TRACE');
});
it('severity_text should be used when severity_number is absent', () => {
it('severity_text should be used when severity_number is absent ', () => {
const log = {
date: '2024-02-29T12:34:46Z',
timestamp: 1646115296,
@@ -157,7 +157,7 @@ describe('logIndicatorBySeverityNumber', () => {
];
logLevelExpectations.forEach((e) => {
for (let sevNum = e.minSevNumber; sevNum <= e.maxSevNumber; sevNum++) {
const sevText = (Math.random() + 1).toString(36).slice(2);
const sevText = (Math.random() + 1).toString(36).substring(2);
const log = {
date: '2024-02-29T12:34:46Z',

View File

@@ -55,7 +55,7 @@ export const useTableView = (props: UseTableViewProps): UseTableViewResult => {
title: name,
dataIndex: name,
accessorKey: name,
id: name.toLowerCase().replaceAll(/\./g, '_'),
id: name.toLowerCase().replace(/\./g, '_'),
key: name,
render: (field): ColumnTypeRender<Record<string, unknown>> => ({
props: {

View File

@@ -77,7 +77,7 @@ function OptionsMenu({
};
const handleSearchValueChange = useDebouncedFn((event): void => {
// @ts-expect-error
// @ts-ignore
const value = event?.target?.value || '';
if (addColumn && addColumn?.onSearch) {

View File

@@ -72,7 +72,7 @@ describe('LogsFormatOptionsMenu (unit)', () => {
fireEvent.click(formatButton);
const getMenuItems = (): Element[] =>
[...document.querySelectorAll('.menu-items .item')];
Array.from(document.querySelectorAll('.menu-items .item'));
const findItemByLabel = (label: string): Element | undefined =>
getMenuItems().find((el) => (el.textContent || '').includes(label));
@@ -136,7 +136,9 @@ describe('LogsFormatOptionsMenu (unit)', () => {
fireEvent.click(fontButton);
// Choose MEDIUM
const optionButtons = [...document.querySelectorAll('.font-size-dropdown .option-btn')];
const optionButtons = Array.from(
document.querySelectorAll('.font-size-dropdown .option-btn'),
);
const mediumBtn = optionButtons[1] as HTMLElement;
fireEvent.click(mediumBtn);

View File

@@ -50,7 +50,7 @@ function Code({
const match = /language-(\w+)/.exec(className || '');
return !inline && match ? (
<SyntaxHighlighter
// @ts-expect-error
// @ts-ignore
style={a11yDark}
language={match[1]}
PreTag="div"
@@ -115,7 +115,7 @@ function MarkdownRenderer({
className={className}
rehypePlugins={[rehypeRaw as any]}
components={{
// @ts-expect-error
// @ts-ignore
a: Link,
pre: ({ children }) =>
Pre({

View File

@@ -26,9 +26,9 @@ function MessagingQueueHealthCheck({
isFetching: consumerLoading,
} = useOnboardingStatus(
{
enabled: serviceToInclude.filter(
enabled: !!serviceToInclude.filter(
(service) => service === MessagingQueueHealthCheckService.Consumers,
).length > 0,
).length,
},
MessagingQueueHealthCheckService.Consumers,
);
@@ -40,9 +40,9 @@ function MessagingQueueHealthCheck({
isFetching: producerLoading,
} = useOnboardingStatus(
{
enabled: serviceToInclude.filter(
enabled: !!serviceToInclude.filter(
(service) => service === MessagingQueueHealthCheckService.Producers,
).length > 0,
).length,
},
MessagingQueueHealthCheckService.Producers,
);
@@ -54,9 +54,9 @@ function MessagingQueueHealthCheck({
isFetching: kafkaLoading,
} = useOnboardingStatus(
{
enabled: serviceToInclude.filter(
enabled: !!serviceToInclude.filter(
(service) => service === MessagingQueueHealthCheckService.Kafka,
).length > 0,
).length,
},
MessagingQueueHealthCheckService.Kafka,
);

View File

@@ -607,7 +607,7 @@ const CustomMultiSelect: React.FC<CustomMultiSelectProps> = ({
try {
const parts = text.split(
new RegExp(
`(${searchQuery.replaceAll(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')})`,
`(${searchQuery.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')})`,
'gi',
),
);
@@ -615,7 +615,7 @@ const CustomMultiSelect: React.FC<CustomMultiSelectProps> = ({
<>
{parts.map((part, i) => {
// Create a unique key that doesn't rely on array index
const uniqueKey = `${text.slice(0, 3)}-${part.slice(0, 3)}-${i}`;
const uniqueKey = `${text.substring(0, 3)}-${part.substring(0, 3)}-${i}`;
return part.toLowerCase() === searchQuery.toLowerCase() ? (
<span key={uniqueKey} className="highlight-text">
@@ -819,7 +819,7 @@ const CustomMultiSelect: React.FC<CustomMultiSelectProps> = ({
const getLastVisibleChipIndex = useCallback((): number => {
const visibleIndices = getVisibleChipIndices();
return visibleIndices.length > 0
? visibleIndices.at(-1)
? visibleIndices[visibleIndices.length - 1]
: -1;
}, [getVisibleChipIndices]);

View File

@@ -152,7 +152,7 @@ const CustomSelect: React.FC<CustomSelectProps> = ({
try {
const parts = text.split(
new RegExp(
`(${searchQuery.replaceAll(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')})`,
`(${searchQuery.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')})`,
'gi',
),
);
@@ -160,7 +160,7 @@ const CustomSelect: React.FC<CustomSelectProps> = ({
<>
{parts.map((part, i) => {
// Create a deterministic but unique key
const uniqueKey = `${text.slice(0, 3)}-${part.slice(0, 3)}-${i}`;
const uniqueKey = `${text.substring(0, 3)}-${part.substring(0, 3)}-${i}`;
return part.toLowerCase() === searchQuery.toLowerCase() ? (
<span key={uniqueKey} className="highlight-text">

View File

@@ -61,7 +61,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 1. CUSTOM VALUES SUPPORT =====
describe('Custom Values Support (CS)', () => {
it('CS-01: Custom values persist in selected state', async () => {
test('CS-01: Custom values persist in selected state', async () => {
const { rerender } = renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -87,7 +87,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
expect(screen.getByText('another-custom')).toBeInTheDocument();
});
it('CS-02: Partial matches create custom values', async () => {
test('CS-02: Partial matches create custom values', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -129,7 +129,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
expect(combobox).toBeInTheDocument();
});
it('CS-03: Exact match filtering behavior', async () => {
test('CS-03: Exact match filtering behavior', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -154,14 +154,14 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
await waitFor(() => {
// Check for highlighted "frontend" text
const highlightedElements = document.querySelectorAll('.highlight-text');
const highlightTexts = [...highlightedElements].map(
const highlightTexts = Array.from(highlightedElements).map(
(el) => el.textContent,
);
expect(highlightTexts).toContain('Frontend');
// Frontend option should be visible in dropdown - use a simpler approach
const optionLabels = document.querySelectorAll('.option-label-text');
const hasFrontendOption = [...optionLabels].some((label) =>
const hasFrontendOption = Array.from(optionLabels).some((label) =>
label.textContent?.includes('Frontend'),
);
expect(hasFrontendOption).toBe(true);
@@ -176,7 +176,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
it('CS-04: Search filtering with "end" pattern', async () => {
test('CS-04: Search filtering with "end" pattern', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -201,19 +201,19 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
await waitFor(() => {
// Check for highlighted "end" text in the options
const highlightedElements = document.querySelectorAll('.highlight-text');
const highlightTexts = [...highlightedElements].map(
const highlightTexts = Array.from(highlightedElements).map(
(el) => el.textContent,
);
expect(highlightTexts).toContain('end');
// Check that Frontend and Backend options are present with highlighted text
const optionLabels = document.querySelectorAll('.option-label-text');
const hasFrontendOption = [...optionLabels].some(
const hasFrontendOption = Array.from(optionLabels).some(
(label) =>
label.textContent?.includes('Front') &&
label.textContent?.includes('end'),
);
const hasBackendOption = [...optionLabels].some(
const hasBackendOption = Array.from(optionLabels).some(
(label) =>
label.textContent?.includes('Back') && label.textContent?.includes('end'),
);
@@ -222,10 +222,10 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
expect(hasBackendOption).toBe(true);
// Other options should be filtered out
const hasDatabaseOption = [...optionLabels].some((label) =>
const hasDatabaseOption = Array.from(optionLabels).some((label) =>
label.textContent?.includes('Database'),
);
const hasApiGatewayOption = [...optionLabels].some((label) =>
const hasApiGatewayOption = Array.from(optionLabels).some((label) =>
label.textContent?.includes('API Gateway'),
);
@@ -234,7 +234,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
it('CS-05: Comma-separated values behavior', async () => {
test('CS-05: Comma-separated values behavior', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -281,7 +281,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 2. SEARCH AND FILTERING =====
describe('Search and Filtering (SF)', () => {
it('SF-01: Selected values pushed to top', async () => {
test('SF-01: Selected values pushed to top', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -298,14 +298,14 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
expect(dropdown).toBeInTheDocument();
const options = dropdown?.querySelectorAll('.option-label-text') || [];
const optionTexts = [...options].map((el) => el.textContent);
const optionTexts = Array.from(options).map((el) => el.textContent);
// Database should be at the top (after ALL option if present)
expect(optionTexts[0]).toBe('Database');
});
});
it('SF-02: Filtering with search text', async () => {
test('SF-02: Filtering with search text', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -332,14 +332,14 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
await waitFor(() => {
// Check for highlighted text within the Frontend option
const highlightedElements = document.querySelectorAll('.highlight-text');
const highlightTexts = [...highlightedElements].map(
const highlightTexts = Array.from(highlightedElements).map(
(el) => el.textContent,
);
expect(highlightTexts).toContain('Front');
// Should show Frontend option (highlighted) - use a simpler approach
const optionLabels = document.querySelectorAll('.option-label-text');
const hasFrontendOption = [...optionLabels].some((label) =>
const hasFrontendOption = Array.from(optionLabels).some((label) =>
label.textContent?.includes('Frontend'),
);
expect(hasFrontendOption).toBe(true);
@@ -350,7 +350,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
it('SF-03: Highlighting search matches', async () => {
test('SF-03: Highlighting search matches', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -374,14 +374,14 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// Should highlight matching text in options
await waitFor(() => {
const highlightedElements = document.querySelectorAll('.highlight-text');
const highlightTexts = [...highlightedElements].map(
const highlightTexts = Array.from(highlightedElements).map(
(el) => el.textContent,
);
expect(highlightTexts).toContain('end');
});
});
it('SF-04: Search with no results', async () => {
test('SF-04: Search with no results', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -424,7 +424,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 3. KEYBOARD NAVIGATION =====
describe('Keyboard Navigation (KN)', () => {
it('KN-01: Arrow key navigation in dropdown', async () => {
test('KN-01: Arrow key navigation in dropdown', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -465,7 +465,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
it('KN-02: Tab navigation to dropdown', async () => {
test('KN-02: Tab navigation to dropdown', async () => {
renderWithVirtuoso(
<div>
<input data-testid="prev-input" />
@@ -515,7 +515,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
it('KN-03: Enter selection in dropdown', async () => {
test('KN-03: Enter selection in dropdown', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -540,7 +540,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
expect(mockOnChange).toHaveBeenCalledWith(['frontend'], ['frontend']);
});
it('KN-04: Chip deletion with keyboard', async () => {
test('KN-04: Chip deletion with keyboard', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -586,7 +586,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 5. UI/UX BEHAVIORS =====
describe('UI/UX Behaviors (UI)', () => {
it('UI-01: Loading state does not block interaction', async () => {
test('UI-01: Loading state does not block interaction', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} loading />,
);
@@ -603,7 +603,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
it('UI-02: Component remains editable in all states', async () => {
test('UI-02: Component remains editable in all states', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} loading />,
);
@@ -634,7 +634,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
expect(combobox).not.toBeDisabled();
});
it('UI-03: Toggle/Only labels in dropdown', async () => {
test('UI-03: Toggle/Only labels in dropdown', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -656,7 +656,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
it('UI-04: Should display values with loading info at bottom', async () => {
test('UI-04: Should display values with loading info at bottom', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} loading />,
);
@@ -677,7 +677,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
it('UI-05: Error state display in footer', async () => {
test('UI-05: Error state display in footer', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -696,7 +696,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
it('UI-06: No data state display', async () => {
test('UI-06: No data state display', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={[]}
@@ -716,7 +716,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 6. CLEAR ACTIONS =====
describe('Clear Actions (CA)', () => {
it('CA-01: Ctrl+A selects all chips', async () => {
test('CA-01: Ctrl+A selects all chips', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -760,7 +760,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
it('CA-02: Clear icon removes all selections', async () => {
test('CA-02: Clear icon removes all selections', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -777,7 +777,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
}
});
it('CA-03: Individual chip removal', async () => {
test('CA-03: Individual chip removal', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -790,7 +790,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
const removeButtons = document.querySelectorAll(
'.ant-select-selection-item-remove',
);
expect(removeButtons).toHaveLength(2);
expect(removeButtons.length).toBe(2);
await user.click(removeButtons[1] as Element);
@@ -804,7 +804,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 7. SAVE AND SELECTION TRIGGERS =====
describe('Save and Selection Triggers (ST)', () => {
it('ST-01: ESC triggers save action', async () => {
test('ST-01: ESC triggers save action', async () => {
const mockDropdownChange = jest.fn();
renderWithVirtuoso(
@@ -837,7 +837,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
it('ST-02: Mouse selection works', async () => {
test('ST-02: Mouse selection works', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -859,7 +859,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
);
});
it('ST-03: ENTER in input field creates custom value', async () => {
test('ST-03: ENTER in input field creates custom value', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -892,7 +892,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
it('ST-04: Search text persistence', async () => {
test('ST-04: Search text persistence', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -932,7 +932,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 8. SPECIAL OPTIONS AND STATES =====
describe('Special Options and States (SO)', () => {
it('SO-01: ALL option appears first and separated', async () => {
test('SO-01: ALL option appears first and separated', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -954,7 +954,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
it('SO-02: ALL selection behavior', async () => {
test('SO-02: ALL selection behavior', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -981,7 +981,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
);
});
it('SO-03: ALL tag display when all selected', () => {
test('SO-03: ALL tag display when all selected', () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -996,7 +996,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
expect(screen.queryByText('frontend')).not.toBeInTheDocument();
});
it('SO-04: Footer information display', async () => {
test('SO-04: Footer information display', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -1017,7 +1017,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== GROUPED OPTIONS SUPPORT =====
describe('Grouped Options Support', () => {
it('handles grouped options correctly', async () => {
test('handles grouped options correctly', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockGroupedOptions} onChange={mockOnChange} />,
);
@@ -1041,7 +1041,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== ACCESSIBILITY TESTS =====
describe('Accessibility', () => {
it('has proper ARIA attributes', async () => {
test('has proper ARIA attributes', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -1058,7 +1058,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
it('supports screen reader navigation', async () => {
test('supports screen reader navigation', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -1079,7 +1079,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 9. ADVANCED KEYBOARD NAVIGATION =====
describe('Advanced Keyboard Navigation (AKN)', () => {
it('AKN-01: Shift + Arrow + Del chip deletion', async () => {
test('AKN-01: Shift + Arrow + Del chip deletion', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -1137,7 +1137,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
expect(combobox).toHaveFocus();
});
it('AKN-03: Mouse out closes dropdown', async () => {
test('AKN-03: Mouse out closes dropdown', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -1164,7 +1164,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 10. ADVANCED FILTERING AND HIGHLIGHTING =====
describe('Advanced Filtering and Highlighting (AFH)', () => {
it('AFH-01: Highlighted values pushed to top', async () => {
test('AFH-01: Highlighted values pushed to top', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -1189,14 +1189,14 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
await waitFor(() => {
// Check for highlighted text
const highlightedElements = document.querySelectorAll('.highlight-text');
const highlightTexts = [...highlightedElements].map(
const highlightTexts = Array.from(highlightedElements).map(
(el) => el.textContent,
);
expect(highlightTexts).toContain('front');
// Get all option items to check the order
const optionItems = document.querySelectorAll('.option-item');
const optionTexts = [...optionItems]
const optionTexts = Array.from(optionItems)
.map((item) => {
const labelElement = item.querySelector('.option-label-text');
return labelElement?.textContent?.trim();
@@ -1220,7 +1220,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
it('AFH-02: Distinction between selection Enter and save Enter', async () => {
test('AFH-02: Distinction between selection Enter and save Enter', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -1267,7 +1267,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 11. ADVANCED CLEAR ACTIONS =====
describe('Advanced Clear Actions (ACA)', () => {
it('ACA-01: Clear action waiting behavior', async () => {
test('ACA-01: Clear action waiting behavior', async () => {
const mockOnChangeWithDelay = jest.fn().mockImplementation(
() =>
new Promise<void>((resolve) => {
@@ -1300,7 +1300,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 12. ADVANCED UI STATES =====
describe('Advanced UI States (AUS)', () => {
it('AUS-01: No data with previous value selected', async () => {
test('AUS-01: No data with previous value selected', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={[]}
@@ -1322,7 +1322,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
expect(screen.getByText('previous-value')).toBeInTheDocument();
});
it('AUS-02: Always editable accessibility', async () => {
test('AUS-02: Always editable accessibility', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} loading />,
);
@@ -1338,7 +1338,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
expect(combobox).not.toBeDisabled();
});
it('AUS-03: Sufficient space for search value', async () => {
test('AUS-03: Sufficient space for search value', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);
@@ -1372,7 +1372,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 13. REGEX AND CUSTOM VALUES =====
describe('Regex and Custom Values (RCV)', () => {
it('RCV-01: Regex pattern support', async () => {
test('RCV-01: Regex pattern support', async () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockOptions}
@@ -1418,7 +1418,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
});
});
it('RCV-02: Custom values treated as normal dropdown values', async () => {
test('RCV-02: Custom values treated as normal dropdown values', async () => {
const customOptions = [
...mockOptions,
{ label: 'custom-value', value: 'custom-value', type: 'custom' as const },
@@ -1456,7 +1456,7 @@ describe('CustomMultiSelect - Comprehensive Tests', () => {
// ===== 14. DROPDOWN PERSISTENCE =====
describe('Dropdown Persistence (DP)', () => {
it('DP-01: Dropdown stays open for non-save actions', async () => {
test('DP-01: Dropdown stays open for non-save actions', async () => {
renderWithVirtuoso(
<CustomMultiSelect options={mockOptions} onChange={mockOnChange} />,
);

View File

@@ -50,7 +50,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 1. CUSTOM VALUES SUPPORT =====
describe('Custom Values Support (CS)', () => {
it('CS-02: Partial matches create custom values', async () => {
test('CS-02: Partial matches create custom values', async () => {
render(
<CustomSelect
options={mockOptions}
@@ -110,7 +110,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
it('CS-03: Exact match behavior', async () => {
test('CS-03: Exact match behavior', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -133,14 +133,14 @@ describe('CustomSelect - Comprehensive Tests', () => {
await waitFor(() => {
// Check for highlighted "frontend" text
const highlightedElements = document.querySelectorAll('.highlight-text');
const highlightTexts = [...highlightedElements].map(
const highlightTexts = Array.from(highlightedElements).map(
(el) => el.textContent,
);
expect(highlightTexts).toContain('Frontend');
// Frontend option should be visible in dropdown - use a simpler approach
const optionContents = document.querySelectorAll('.option-content');
const hasFrontendOption = [...optionContents].some((content) =>
const hasFrontendOption = Array.from(optionContents).some((content) =>
content.textContent?.includes('Frontend'),
);
expect(hasFrontendOption).toBe(true);
@@ -161,7 +161,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 2. SEARCH AND FILTERING =====
describe('Search and Filtering (SF)', () => {
it('SF-01: Selected values pushed to top', async () => {
test('SF-01: Selected values pushed to top', async () => {
render(
<CustomSelect
options={mockOptions}
@@ -178,14 +178,14 @@ describe('CustomSelect - Comprehensive Tests', () => {
expect(dropdown).toBeInTheDocument();
const options = dropdown?.querySelectorAll('.option-content') || [];
const optionTexts = [...options].map((el) => el.textContent);
const optionTexts = Array.from(options).map((el) => el.textContent);
// Database should be at the top
expect(optionTexts[0]).toContain('Database');
});
});
it('SF-02: Real-time search filtering', async () => {
test('SF-02: Real-time search filtering', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -210,14 +210,14 @@ describe('CustomSelect - Comprehensive Tests', () => {
await waitFor(() => {
// Check for highlighted text within the Frontend option
const highlightedElements = document.querySelectorAll('.highlight-text');
const highlightTexts = [...highlightedElements].map(
const highlightTexts = Array.from(highlightedElements).map(
(el) => el.textContent,
);
expect(highlightTexts).toContain('Front');
// Should show Frontend option (highlighted) - use a simpler approach
const optionContents = document.querySelectorAll('.option-content');
const hasFrontendOption = [...optionContents].some((content) =>
const hasFrontendOption = Array.from(optionContents).some((content) =>
content.textContent?.includes('Frontend'),
);
expect(hasFrontendOption).toBe(true);
@@ -228,7 +228,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
it('SF-03: Search highlighting', async () => {
test('SF-03: Search highlighting', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -250,14 +250,14 @@ describe('CustomSelect - Comprehensive Tests', () => {
// Should highlight matching text in options
await waitFor(() => {
const highlightedElements = document.querySelectorAll('.highlight-text');
const highlightTexts = [...highlightedElements].map(
const highlightTexts = Array.from(highlightedElements).map(
(el) => el.textContent,
);
expect(highlightTexts).toContain('end');
});
});
it('SF-04: Search with partial matches', async () => {
test('SF-04: Search with partial matches', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -298,7 +298,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 3. KEYBOARD NAVIGATION =====
describe('Keyboard Navigation (KN)', () => {
it('KN-01: Arrow key navigation in dropdown', async () => {
test('KN-01: Arrow key navigation in dropdown', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -329,7 +329,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
it('KN-02: Tab navigation to dropdown', async () => {
test('KN-02: Tab navigation to dropdown', async () => {
render(
<div>
<input data-testid="prev-input" />
@@ -355,7 +355,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
it('KN-03: Enter selection in dropdown', async () => {
test('KN-03: Enter selection in dropdown', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -376,7 +376,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
it('KN-04: Space key selection', async () => {
test('KN-04: Space key selection', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -396,7 +396,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
it('KN-05: Tab navigation within dropdown', async () => {
test('KN-05: Tab navigation within dropdown', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -417,7 +417,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 4. UI/UX BEHAVIORS =====
describe('UI/UX Behaviors (UI)', () => {
it('UI-01: Loading state does not block interaction', async () => {
test('UI-01: Loading state does not block interaction', async () => {
render(
<CustomSelect options={mockOptions} onChange={mockOnChange} loading />,
);
@@ -429,7 +429,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
expect(combobox).toHaveFocus();
});
it('UI-02: Component remains editable in all states', () => {
test('UI-02: Component remains editable in all states', () => {
render(
<CustomSelect
options={mockOptions}
@@ -444,7 +444,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
expect(combobox).not.toBeDisabled();
});
it('UI-03: Loading state display in footer', async () => {
test('UI-03: Loading state display in footer', async () => {
render(
<CustomSelect options={mockOptions} onChange={mockOnChange} loading />,
);
@@ -458,7 +458,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
it('UI-04: Error state display in footer', async () => {
test('UI-04: Error state display in footer', async () => {
render(
<CustomSelect
options={mockOptions}
@@ -477,7 +477,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
it('UI-05: No data state display', async () => {
test('UI-05: No data state display', async () => {
render(
<CustomSelect
options={[]}
@@ -497,7 +497,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 6. SAVE AND SELECTION TRIGGERS =====
describe('Save and Selection Triggers (ST)', () => {
it('ST-01: Mouse selection works', async () => {
test('ST-01: Mouse selection works', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -520,7 +520,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 7. GROUPED OPTIONS SUPPORT =====
describe('Grouped Options Support', () => {
it('handles grouped options correctly', async () => {
test('handles grouped options correctly', async () => {
render(
<CustomSelect options={mockGroupedOptions} onChange={mockOnChange} />,
);
@@ -541,7 +541,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
it('grouped option selection works', async () => {
test('grouped option selection works', async () => {
render(
<CustomSelect options={mockGroupedOptions} onChange={mockOnChange} />,
);
@@ -566,7 +566,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 8. ACCESSIBILITY =====
describe('Accessibility', () => {
it('has proper ARIA attributes', async () => {
test('has proper ARIA attributes', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -580,7 +580,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
it('supports screen reader navigation', async () => {
test('supports screen reader navigation', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -596,7 +596,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
it('has proper focus management', async () => {
test('has proper focus management', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -617,7 +617,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 10. EDGE CASES =====
describe('Edge Cases', () => {
it('handles special characters in options', async () => {
test('handles special characters in options', async () => {
const specialOptions = [
{ label: 'Option with spaces', value: 'option-with-spaces' },
{ label: 'Option-with-dashes', value: 'option-with-dashes' },
@@ -638,7 +638,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
it('handles extremely long option labels', async () => {
test('handles extremely long option labels', async () => {
const longLabelOptions = [
{
label:
@@ -663,7 +663,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 11. ADVANCED KEYBOARD NAVIGATION =====
describe('Advanced Keyboard Navigation (AKN)', () => {
it('AKN-01: Mouse out closes dropdown', async () => {
test('AKN-01: Mouse out closes dropdown', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -684,7 +684,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
it('AKN-02: TAB navigation from input to dropdown', async () => {
test('AKN-02: TAB navigation from input to dropdown', async () => {
render(
<div>
<input data-testid="prev-input" />
@@ -722,7 +722,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 12. ADVANCED FILTERING AND HIGHLIGHTING =====
describe('Advanced Filtering and Highlighting (AFH)', () => {
it('AFH-01: Highlighted values pushed to top', async () => {
test('AFH-01: Highlighted values pushed to top', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -745,14 +745,14 @@ describe('CustomSelect - Comprehensive Tests', () => {
await waitFor(() => {
// Check for highlighted text
const highlightedElements = document.querySelectorAll('.highlight-text');
const highlightTexts = [...highlightedElements].map(
const highlightTexts = Array.from(highlightedElements).map(
(el) => el.textContent,
);
expect(highlightTexts).toContain('front');
// Get all option items to check the order
const optionItems = document.querySelectorAll('.option-item');
const optionTexts = [...optionItems]
const optionTexts = Array.from(optionItems)
.map((item) => {
const contentElement = item.querySelector('.option-content');
return contentElement?.textContent?.trim();
@@ -776,7 +776,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
it('AFH-02: Distinction between selection Enter and save Enter', async () => {
test('AFH-02: Distinction between selection Enter and save Enter', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -830,7 +830,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 13. ADVANCED CLEAR ACTIONS =====
describe('Advanced Clear Actions (ACA)', () => {
it('ACA-01: Clear action waiting behavior', async () => {
test('ACA-01: Clear action waiting behavior', async () => {
const mockOnChangeWithDelay = jest.fn().mockImplementation(
() =>
new Promise((resolve) => {
@@ -860,7 +860,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
expect(mockOnChangeWithDelay).toHaveBeenCalled();
});
it('ACA-02: Single select clear behavior like text input', async () => {
test('ACA-02: Single select clear behavior like text input', async () => {
render(
<CustomSelect
options={mockOptions}
@@ -883,7 +883,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 14. ADVANCED UI STATES =====
describe('Advanced UI States (AUS)', () => {
it('AUS-01: No data with previous value selected', async () => {
test('AUS-01: No data with previous value selected', async () => {
render(
<CustomSelect
options={[]}
@@ -905,7 +905,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
expect(screen.getAllByText('previous-value')).toHaveLength(2);
});
it('AUS-02: Always editable accessibility', async () => {
test('AUS-02: Always editable accessibility', async () => {
render(
<CustomSelect options={mockOptions} onChange={mockOnChange} loading />,
);
@@ -921,7 +921,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
expect(combobox).not.toBeDisabled();
});
it('AUS-03: Sufficient space for search value', async () => {
test('AUS-03: Sufficient space for search value', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -950,7 +950,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
it('AUS-04: No spinners blocking user interaction', async () => {
test('AUS-04: No spinners blocking user interaction', async () => {
render(
<CustomSelect options={mockOptions} onChange={mockOnChange} loading />,
);
@@ -976,7 +976,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 15. REGEX AND CUSTOM VALUES =====
describe('Regex and Custom Values (RCV)', () => {
it('RCV-01: Regex pattern support', async () => {
test('RCV-01: Regex pattern support', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');
@@ -1019,7 +1019,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
});
});
it('RCV-02: Custom values treated as normal dropdown values', async () => {
test('RCV-02: Custom values treated as normal dropdown values', async () => {
const customOptions = [
...mockOptions,
{ label: 'custom-value', value: 'custom-value', type: 'custom' as const },
@@ -1051,7 +1051,7 @@ describe('CustomSelect - Comprehensive Tests', () => {
// ===== 16. DROPDOWN PERSISTENCE =====
describe('Dropdown Persistence (DP)', () => {
it('DP-01: Dropdown closes only on save actions', async () => {
test('DP-01: Dropdown closes only on save actions', async () => {
render(<CustomSelect options={mockOptions} onChange={mockOnChange} />);
const combobox = screen.getByRole('combobox');

View File

@@ -86,7 +86,7 @@ describe('VariableItem Integration Tests', () => {
// ===== 1. INTEGRATION WITH CUSTOMSELECT =====
describe('CustomSelect Integration (VI)', () => {
it('VI-01: Single select variable integration', async () => {
test('VI-01: Single select variable integration', async () => {
const variable = createMockVariable({
multiSelect: false,
type: 'CUSTOM',
@@ -130,7 +130,7 @@ describe('VariableItem Integration Tests', () => {
// ===== 2. INTEGRATION WITH CUSTOMMULTISELECT =====
describe('CustomMultiSelect Integration (VI)', () => {
it('VI-02: Multi select variable integration', async () => {
test('VI-02: Multi select variable integration', async () => {
const variable = createMockVariable({
multiSelect: true,
type: 'CUSTOM',
@@ -174,7 +174,7 @@ describe('VariableItem Integration Tests', () => {
// ===== 3. TEXTBOX VARIABLE TYPE =====
describe('Textbox Variable Integration', () => {
it('VI-03: Textbox variable handling', async () => {
test('VI-03: Textbox variable handling', async () => {
const variable = createMockVariable({
type: 'TEXTBOX',
selectedValue: 'initial-value',
@@ -219,7 +219,7 @@ describe('VariableItem Integration Tests', () => {
// ===== 4. VALUE PERSISTENCE AND STATE MANAGEMENT =====
describe('Value Persistence and State Management', () => {
it('VI-04: All selected state handling', () => {
test('VI-04: All selected state handling', () => {
const variable = createMockVariable({
multiSelect: true,
type: 'CUSTOM',
@@ -243,7 +243,7 @@ describe('VariableItem Integration Tests', () => {
expect(screen.getByText('ALL')).toBeInTheDocument();
});
it('VI-05: Dropdown behavior with temporary selections', async () => {
test('VI-05: Dropdown behavior with temporary selections', async () => {
const variable = createMockVariable({
multiSelect: true,
type: 'CUSTOM',
@@ -277,7 +277,7 @@ describe('VariableItem Integration Tests', () => {
// ===== 6. ACCESSIBILITY AND USER EXPERIENCE =====
describe('Accessibility and User Experience', () => {
it('VI-06: Variable description tooltip', async () => {
test('VI-06: Variable description tooltip', async () => {
const variable = createMockVariable({
description: 'This variable controls the service selection',
type: 'CUSTOM',
@@ -310,7 +310,7 @@ describe('VariableItem Integration Tests', () => {
});
});
it('VI-07: Variable name display', () => {
test('VI-07: Variable name display', () => {
const variable = createMockVariable({
name: 'service_name',
type: 'CUSTOM',
@@ -331,7 +331,7 @@ describe('VariableItem Integration Tests', () => {
expect(screen.getByText('$service_name')).toBeInTheDocument();
});
it('VI-08: Max tag count behavior', async () => {
test('VI-08: Max tag count behavior', async () => {
const variable = createMockVariable({
multiSelect: true,
type: 'CUSTOM',
@@ -365,7 +365,7 @@ describe('VariableItem Integration Tests', () => {
// ===== 8. SEARCH INTERACTION TESTS =====
describe('Search Interaction Tests', () => {
it('VI-14: Search persistence across dropdown open/close', async () => {
test('VI-14: Search persistence across dropdown open/close', async () => {
const variable = createMockVariable({
type: 'CUSTOM',
customValue: 'option1,option2,option3',
@@ -417,7 +417,7 @@ describe('VariableItem Integration Tests', () => {
// ===== 9. ADVANCED KEYBOARD NAVIGATION =====
describe('Advanced Keyboard Navigation (VI)', () => {
it('VI-15: Shift + Arrow + Del chip deletion in multiselect', async () => {
test('VI-15: Shift + Arrow + Del chip deletion in multiselect', async () => {
const variable = createMockVariable({
type: 'CUSTOM',
customValue: 'option1,option2,option3',
@@ -461,7 +461,7 @@ describe('VariableItem Integration Tests', () => {
// ===== 11. ADVANCED UI STATES =====
describe('Advanced UI States (VI)', () => {
it('VI-19: No data with previous value selected in variable', async () => {
test('VI-19: No data with previous value selected in variable', async () => {
const variable = createMockVariable({
type: 'CUSTOM',
customValue: '',
@@ -499,7 +499,7 @@ describe('VariableItem Integration Tests', () => {
expect(combobox).toBeInTheDocument();
});
it('VI-20: Always editable accessibility in variable', async () => {
test('VI-20: Always editable accessibility in variable', async () => {
const variable = createMockVariable({
type: 'CUSTOM',
customValue: 'option1,option2',
@@ -530,7 +530,7 @@ describe('VariableItem Integration Tests', () => {
// ===== 13. DROPDOWN PERSISTENCE =====
describe('Dropdown Persistence (VI)', () => {
it('VI-24: Dropdown stays open for non-save actions in variable', async () => {
test('VI-24: Dropdown stays open for non-save actions in variable', async () => {
const variable = createMockVariable({
type: 'CUSTOM',
customValue: 'option1,option2,option3',

View File

@@ -44,7 +44,7 @@ describe('OverflowInputToolTip', () => {
jest.restoreAllMocks();
});
it('shows tooltip when content overflows and input is clamped at maxAutoWidth', async () => {
test('shows tooltip when content overflows and input is clamped at maxAutoWidth', async () => {
mockOverflow(150, 250); // clientWidth >= maxAutoWidth (150), scrollWidth > clientWidth
render(<OverflowInputToolTip value="Very long overflowing text" />);
@@ -64,7 +64,7 @@ describe('OverflowInputToolTip', () => {
).toBeInTheDocument();
});
it('does NOT show tooltip when content does not overflow', async () => {
test('does NOT show tooltip when content does not overflow', async () => {
mockOverflow(150, 100); // content fits (scrollWidth <= clientWidth)
render(<OverflowInputToolTip value="Short text" />);
@@ -76,7 +76,7 @@ describe('OverflowInputToolTip', () => {
});
});
it('does NOT show tooltip when content overflows but input is NOT at maxAutoWidth', async () => {
test('does NOT show tooltip when content overflows but input is NOT at maxAutoWidth', async () => {
mockOverflow(100, 250); // clientWidth < maxAutoWidth (150), scrollWidth > clientWidth
render(<OverflowInputToolTip value="Long but input not clamped" />);
@@ -88,7 +88,7 @@ describe('OverflowInputToolTip', () => {
});
});
it('uncontrolled input allows typing', async () => {
test('uncontrolled input allows typing', async () => {
render(<OverflowInputToolTip defaultValue="Init" />);
const input = screen.getByRole('textbox') as HTMLInputElement;
@@ -97,7 +97,7 @@ describe('OverflowInputToolTip', () => {
expect(input).toHaveValue('InitABC');
});
it('disabled input never shows tooltip even if overflowing', async () => {
test('disabled input never shows tooltip even if overflowing', async () => {
mockOverflow(150, 300);
render(<OverflowInputToolTip value="Overflowing!" disabled />);
@@ -109,7 +109,7 @@ describe('OverflowInputToolTip', () => {
});
});
it('renders mirror span and input correctly (structural assertions instead of snapshot)', () => {
test('renders mirror span and input correctly (structural assertions instead of snapshot)', () => {
const { container } = render(<OverflowInputToolTip value="Snapshot" />);
const mirror = container.querySelector('.overflow-input-mirror');
const input = container.querySelector('input') as HTMLInputElement | null;

View File

@@ -25,7 +25,7 @@ function OverlayScrollbar({
autoHide: 'scroll',
theme: isDarkMode ? 'os-theme-light' : 'os-theme-dark',
},
...customOptions,
...(customOptions || {}),
} as PartialOptions),
[customOptions, isDarkMode],
);

View File

@@ -159,7 +159,7 @@ function HavingFilter({
if (tokens.length === 0) {
return false;
}
const lastToken = tokens.at(-1);
const lastToken = tokens[tokens.length - 1];
// Check if the last token is exactly an operator or ends with an operator and space
return havingOperators.some((op) => {
const opWithSpace = `${op.value} `;
@@ -253,7 +253,7 @@ function HavingFilter({
if (
!text.endsWith(' ') &&
tokens.length >= 2 &&
havingOperators.some((op) => op.value === tokens.at(-2))
havingOperators.some((op) => op.value === tokens[tokens.length - 2])
) {
return null;
}
@@ -261,8 +261,8 @@ function HavingFilter({
// Suggest key/operator pairs and ( for grouping
if (
tokens.length === 0 ||
conjunctions.some((c) => tokens.at(-1) === c.value.trim()) ||
tokens.at(-1) === '('
conjunctions.some((c) => tokens[tokens.length - 1] === c.value.trim()) ||
tokens[tokens.length - 1] === '('
) {
return {
from: context.pos,
@@ -275,7 +275,7 @@ function HavingFilter({
// Show suggestions when typing
if (tokens.length > 0) {
const lastToken = tokens.at(-1);
const lastToken = tokens[tokens.length - 1];
const filteredOptions = options.filter((opt) =>
opt.label.toLowerCase().includes(lastToken.toLowerCase()),
);
@@ -293,8 +293,8 @@ function HavingFilter({
// Suggest conjunctions after a value and a space
if (
tokens.length > 0 &&
(isNumber(tokens.at(-1)) ||
tokens.at(-1) === ')') &&
(isNumber(tokens[tokens.length - 1]) ||
tokens[tokens.length - 1] === ')') &&
text.endsWith(' ')
) {
return {

View File

@@ -535,7 +535,7 @@ function QueryAddOns({
>
<Radio.Button
className={
selectedViews.some((view) => view.key === addOn.key)
selectedViews.find((view) => view.key === addOn.key)
? 'selected-view tab'
: 'tab'
}

View File

@@ -23,7 +23,7 @@ function QueryAggregationOptions({
panelType?: string;
onAggregationIntervalChange: (value: number) => void;
onChange?: (value: string) => void;
queryData: IBuilderQuery ;
queryData: IBuilderQuery | IBuilderTraceOperator;
}): JSX.Element {
const showAggregationInterval = useMemo(() => {
if (panelType === PANEL_TYPES.VALUE) {

View File

@@ -286,7 +286,7 @@ function QuerySearch({
}
});
}
setKeySuggestions([...merged.values()]);
setKeySuggestions(Array.from(merged.values()));
// Force reopen the completion if editor is available and focused
if (editorRef.current) {
@@ -339,7 +339,7 @@ function QuerySearch({
// If value contains single quotes, escape them and wrap in single quotes
if (value.includes("'")) {
// Replace single quotes with escaped single quotes
const escapedValue = value.replaceAll(/'/g, "\\'");
const escapedValue = value.replace(/'/g, "\\'");
return `'${escapedValue}'`;
}
@@ -899,12 +899,12 @@ function QuerySearch({
// If we have previous pairs, we can prioritize keys that haven't been used yet
if (queryContext.queryPairs && queryContext.queryPairs.length > 0) {
const usedKeys = new Set(queryContext.queryPairs.map((pair) => pair.key));
const usedKeys = queryContext.queryPairs.map((pair) => pair.key);
// Add boost to unused keys to prioritize them
options = options.map((option) => ({
...option,
boost: usedKeys.has(option.label) ? -10 : 10,
boost: usedKeys.includes(option.label) ? -10 : 10,
}));
}

View File

@@ -29,7 +29,7 @@ describe('traceOperatorContextUtils', () => {
null,
);
expect(context).toStrictEqual({
expect(context).toEqual({
tokenType: TraceOperatorGrammarLexer.IDENTIFIER,
text: 'test',
start: 0,
@@ -62,7 +62,7 @@ describe('traceOperatorContextUtils', () => {
false,
);
expect(context).toStrictEqual({
expect(context).toEqual({
tokenType: TraceOperatorGrammarLexer.IDENTIFIER,
text: 'test',
start: 0,
@@ -193,7 +193,7 @@ describe('traceOperatorContextUtils', () => {
it('should return default context for empty query', () => {
const result = getTraceOperatorContextAtCursor('', 0);
expect(result).toStrictEqual({
expect(result).toEqual({
tokenType: -1,
text: '',
start: 0,
@@ -211,7 +211,7 @@ describe('traceOperatorContextUtils', () => {
it('should return default context for null query', () => {
const result = getTraceOperatorContextAtCursor(null as any, 0);
expect(result).toStrictEqual({
expect(result).toEqual({
tokenType: -1,
text: '',
start: 0,
@@ -229,7 +229,7 @@ describe('traceOperatorContextUtils', () => {
it('should return default context for undefined query', () => {
const result = getTraceOperatorContextAtCursor(undefined as any, 0);
expect(result).toStrictEqual({
expect(result).toEqual({
tokenType: -1,
text: '',
start: 0,

View File

@@ -8,21 +8,21 @@ const makeTraceOperator = (expression: string): IBuilderTraceOperator =>
describe('getInvolvedQueriesInTraceOperator', () => {
it('returns empty array for empty input', () => {
const result = getInvolvedQueriesInTraceOperator([]);
expect(result).toStrictEqual([]);
expect(result).toEqual([]);
});
it('extracts identifiers from expression', () => {
const result = getInvolvedQueriesInTraceOperator([
makeTraceOperator('A => B'),
]);
expect(result).toStrictEqual(['A', 'B']);
expect(result).toEqual(['A', 'B']);
});
it('extracts identifiers from complex expression', () => {
const result = getInvolvedQueriesInTraceOperator([
makeTraceOperator('A => (NOT B || C)'),
]);
expect(result).toStrictEqual(['A', 'B', 'C']);
expect(result).toEqual(['A', 'B', 'C']);
});
it('filters out querynames from complex expression', () => {
@@ -31,7 +31,7 @@ describe('getInvolvedQueriesInTraceOperator', () => {
'(A1 && (NOT B2 || (C3 -> (D4 && E5)))) => ((F6 || G7) && (NOT (H8 -> I9)))',
),
]);
expect(result).toStrictEqual([
expect(result).toEqual([
'A1',
'B2',
'C3',

View File

@@ -222,7 +222,9 @@ describe('QuerySearch (Integration with Real CodeMirror)', () => {
timeout: 2000,
});
const lastArgs = mockedGetKeysOnMount.mock.calls.at(-1)?.[0] as { signal: unknown; searchText: string };
const lastArgs = mockedGetKeysOnMount.mock.calls[
mockedGetKeysOnMount.mock.calls.length - 1
]?.[0] as { signal: unknown; searchText: string };
expect(lastArgs).toMatchObject({ signal: DataSource.LOGS, searchText: '' });
});

View File

@@ -85,7 +85,7 @@ describe('previousQuery.utils', () => {
saveAsPreviousQuery(key, sampleQuery);
const fromStore = getPreviousQueryFromKey(key);
expect(fromStore).toStrictEqual(sampleQuery);
expect(fromStore).toEqual(sampleQuery);
});
it('saveAsPreviousQuery merges multiple entries and removeKeyFromPreviousQuery deletes one', () => {

View File

@@ -22,18 +22,18 @@ describe('convertFiltersToExpression', () => {
it('should handle empty, null, and undefined inputs', () => {
// Test null and undefined
expect(convertFiltersToExpression(null as any)).toStrictEqual({ expression: '' });
expect(convertFiltersToExpression(undefined as any)).toStrictEqual({
expect(convertFiltersToExpression(null as any)).toEqual({ expression: '' });
expect(convertFiltersToExpression(undefined as any)).toEqual({
expression: '',
});
// Test empty filters
expect(convertFiltersToExpression({ items: [], op: 'AND' })).toStrictEqual({
expect(convertFiltersToExpression({ items: [], op: 'AND' })).toEqual({
expression: '',
});
expect(
convertFiltersToExpression({ items: undefined, op: 'AND' } as any),
).toStrictEqual({ expression: '' });
).toEqual({ expression: '' });
});
it('should convert basic comparison operators with proper value formatting', () => {
@@ -92,7 +92,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toStrictEqual({
expect(result).toEqual({
expression:
"service = 'api-gateway' AND status != 'error' AND duration > 100 AND count <= 50 AND is_active = true AND enabled = false AND count = 0 AND regex REGEXP '.*'",
});
@@ -124,7 +124,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toStrictEqual({
expect(result).toEqual({
expression:
"message = 'user\\'s data' AND description = '' AND path = '/api/v1/users'",
});
@@ -162,7 +162,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toStrictEqual({
expect(result).toEqual({
expression:
"service in ['api-gateway', 'user-service', 'auth-service'] AND status in ['success'] AND tags in [] AND name in ['John\\'s', 'Mary\\'s', 'Bob']",
});
@@ -224,7 +224,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toStrictEqual({
expect(result).toEqual({
expression:
"service NOT IN ['api-gateway', 'user-service'] AND message NOT LIKE 'error' AND path NOT REGEXP '/api/.*' AND service NOT IN ['api-gateway'] AND user_id NOT EXISTS AND description NOT CONTAINS 'error' AND NOT has(tags, 'production') AND NOT hasAny(labels, ['env:prod', 'service:api'])",
});
@@ -268,7 +268,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toStrictEqual({
expect(result).toEqual({
expression:
"user_id exists AND user_id exists AND has(tags, 'production') AND hasAny(tags, ['production', 'staging']) AND hasAll(tags, ['production', 'monitoring'])",
});
@@ -312,7 +312,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toStrictEqual({
expect(result).toEqual({
expression:
"service = 'api-gateway' AND status = 'success' AND service in ['api-gateway']",
});
@@ -362,7 +362,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toStrictEqual({
expect(result).toEqual({
expression:
"service in ['api-gateway', 'user-service'] AND user_id exists AND has(tags, 'production') AND duration > 100 AND status NOT IN ['error', 'timeout'] AND method = 'POST'",
});
@@ -412,7 +412,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toStrictEqual({
expect(result).toEqual({
expression:
"count = 0 AND score > 100 AND limit >= 50 AND threshold < 1000 AND max_value <= 999 AND values in ['1', '2', '3', '4', '5']",
});
@@ -456,7 +456,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toStrictEqual({
expect(result).toEqual({
expression:
"is_active = true AND is_deleted = false AND email = 'user@example.com' AND description = 'Contains \"quotes\" and \\'apostrophes\\'' AND path = '/api/v1/users/123?filter=true'",
});
@@ -506,7 +506,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toStrictEqual({
expect(result).toEqual({
expression:
"has(tags, 'production') AND hasAny(labels, ['env:prod', 'service:api']) AND hasAll(metadata, ['version:1.0', 'team:backend']) AND services in ['api-gateway', 'user-service', 'auth-service', 'payment-service'] AND excluded_services NOT IN ['legacy-service', 'deprecated-service'] AND status_codes in ['200', '201', '400', '500']",
});
@@ -544,7 +544,7 @@ describe('convertFiltersToExpression', () => {
};
const result = convertFiltersToExpression(filters);
expect(result).toStrictEqual({
expect(result).toEqual({
expression:
"user_id NOT EXISTS AND description NOT CONTAINS 'error' AND NOT has(tags, 'production') AND NOT hasAny(labels, ['env:prod', 'service:api'])",
});
@@ -565,9 +565,10 @@ describe('convertFiltersToExpression', () => {
const result = convertFiltersToExpressionWithExistingQuery(
filters,
undefined,
);
expect(result.filters).toStrictEqual(filters);
expect(result.filters).toEqual(filters);
expect(result.filter.expression).toBe("service.name = 'test-service'");
});
@@ -579,9 +580,10 @@ describe('convertFiltersToExpression', () => {
const result = convertFiltersToExpressionWithExistingQuery(
filters,
undefined,
);
expect(result.filters).toStrictEqual(filters);
expect(result.filters).toEqual(filters);
expect(result.filter.expression).toBe('');
});
@@ -609,7 +611,7 @@ describe('convertFiltersToExpression', () => {
expect(result.filter).toBeDefined();
expect(result.filter.expression).toBe("service.name = 'updated-service'");
// Ensure parser can parse the existing query
expect(extractQueryPairs(existingQuery)).toStrictEqual(
expect(extractQueryPairs(existingQuery)).toEqual(
expect.arrayContaining([
expect.objectContaining({
key: 'service.name',
@@ -803,7 +805,7 @@ describe('convertAggregationToExpression', () => {
temporality: 'delta',
});
expect(result).toStrictEqual([
expect(result).toEqual([
{
metricName: 'test_metric',
timeAggregation: 'avg',
@@ -823,7 +825,7 @@ describe('convertAggregationToExpression', () => {
spaceAggregation: 'noop',
});
expect(result).toStrictEqual([
expect(result).toEqual([
{
metricName: 'test_metric',
timeAggregation: 'count',
@@ -839,7 +841,7 @@ describe('convertAggregationToExpression', () => {
dataSource: DataSource.METRICS,
});
expect(result).toStrictEqual([
expect(result).toEqual([
{
metricName: '',
timeAggregation: 'sum',
@@ -856,7 +858,7 @@ describe('convertAggregationToExpression', () => {
alias: 'trace_alias',
});
expect(result).toStrictEqual([
expect(result).toEqual([
{
expression: 'count(test_metric)',
alias: 'trace_alias',
@@ -872,7 +874,7 @@ describe('convertAggregationToExpression', () => {
alias: 'log_alias',
});
expect(result).toStrictEqual([
expect(result).toEqual([
{
expression: 'avg(test_metric)',
alias: 'log_alias',
@@ -887,7 +889,7 @@ describe('convertAggregationToExpression', () => {
dataSource: DataSource.TRACES,
});
expect(result).toStrictEqual([
expect(result).toEqual([
{
expression: 'count()',
},
@@ -901,7 +903,7 @@ describe('convertAggregationToExpression', () => {
dataSource: DataSource.LOGS,
});
expect(result).toStrictEqual([
expect(result).toEqual([
{
expression: 'sum(test_metric)',
},
@@ -915,7 +917,7 @@ describe('convertAggregationToExpression', () => {
dataSource: DataSource.METRICS,
});
expect(result).toStrictEqual([
expect(result).toEqual([
{
metricName: 'test_metric',
timeAggregation: 'max',
@@ -931,7 +933,7 @@ describe('convertAggregationToExpression', () => {
dataSource: DataSource.METRICS,
});
expect(result).toStrictEqual([
expect(result).toEqual([
{
metricName: 'test_metric',
timeAggregation: 'sum',
@@ -949,7 +951,7 @@ describe('convertAggregationToExpression', () => {
dataSource: DataSource.TRACES,
});
expect(result).toStrictEqual([
expect(result).toEqual([
{
expression: 'count()',
},
@@ -963,7 +965,7 @@ describe('convertAggregationToExpression', () => {
dataSource: DataSource.LOGS,
});
expect(result).toStrictEqual([
expect(result).toEqual([
{
expression: 'count()',
},

View File

@@ -58,7 +58,7 @@ const formatSingleValue = (v: string | number | boolean): string => {
return v;
}
// Quote and escape single quotes in strings
return `'${v.replaceAll(/'/g, "\\'")}'`;
return `'${v.replace(/'/g, "\\'")}'`;
}
// Convert numbers and booleans to strings without quotes
return String(v);

View File

@@ -471,6 +471,6 @@ describe('CheckboxFilter - User Flows', () => {
expect(filterForServiceName.key.key).toBe(SERVICE_NAME_KEY);
expect(filterForServiceName.op).toBe('in');
expect(filterForServiceName.value).toStrictEqual(['mq-kafka', 'otel-demo']);
expect(filterForServiceName.value).toEqual(['mq-kafka', 'otel-demo']);
});
});

View File

@@ -30,7 +30,7 @@ import { isKeyMatch } from './utils';
import './Checkbox.styles.scss';
const SELECTED_OPERATORS = new Set([OPERATORS['='], 'in']);
const SELECTED_OPERATORS = [OPERATORS['='], 'in'];
const NON_SELECTED_OPERATORS = [OPERATORS['!='], 'not in'];
const SOURCES_WITH_EMPTY_STATE_ENABLED = [QuickFiltersSource.LOGS_EXPLORER];
@@ -194,7 +194,7 @@ export default function CheckboxFilter(props: ICheckboxProps): JSX.Element {
);
if (filterSync) {
if (SELECTED_OPERATORS.has(filterSync.op)) {
if (SELECTED_OPERATORS.includes(filterSync.op)) {
if (isArray(filterSync.value)) {
filterSync.value.forEach((val) => {
filterState[String(val)] = true;
@@ -532,12 +532,14 @@ export default function CheckboxFilter(props: ICheckboxProps): JSX.Element {
...currentQuery,
builder: {
...currentQuery.builder,
queryData: currentQuery.builder.queryData.map((q, idx) => {
queryData: [
...currentQuery.builder.queryData.map((q, idx) => {
if (idx === activeQueryIndex) {
return query;
}
return q;
}),
],
},
};
@@ -551,7 +553,7 @@ export default function CheckboxFilter(props: ICheckboxProps): JSX.Element {
const isEmptyStateWithDocsEnabled =
SOURCES_WITH_EMPTY_STATE_ENABLED.includes(source) &&
!searchText &&
attributeValues.length === 0;
!attributeValues.length;
return (
<div className="checkbox-filter">
@@ -575,7 +577,7 @@ export default function CheckboxFilter(props: ICheckboxProps): JSX.Element {
<Typography.Text className="title">{filter.title}</Typography.Text>
</section>
<section className="right-action">
{isOpen && attributeValues.length > 0 && (
{isOpen && !!attributeValues.length && (
<Typography.Text
className="clear-all"
onClick={(e): void => {
@@ -591,7 +593,7 @@ export default function CheckboxFilter(props: ICheckboxProps): JSX.Element {
</section>
{isOpen &&
(isLoading || isLoadingKeyValueSuggestions) &&
attributeValues.length === 0 && (
!attributeValues.length && (
<section className="loading">
<Skeleton paragraph={{ rows: 4 }} />
</section>

View File

@@ -139,7 +139,7 @@ function Duration({
attribute as AllTraceFilterKeys,
)
) {
if (!values || values.length === 0) {
if (!values || !values.length) {
return [];
}
let minValue = '';

View File

@@ -92,7 +92,7 @@ export default function QuickFilters(props: IQuickFiltersProps): JSX.Element {
}
return currentQuery.builder.queryData.map((query, index) => ({
label: query.queryName || String.fromCodePoint(65 + index),
label: query.queryName || String.fromCharCode(65 + index),
value: index,
}));
}, [currentQuery?.builder?.queryData]);

View File

@@ -323,7 +323,7 @@ describe('Quick Filters with custom filters', () => {
const settingsButton = icon.closest('button') ?? icon;
await user.click(settingsButton);
await expect(screen.findByText('Edit quick filters')).resolves.toBeInTheDocument();
expect(await screen.findByText('Edit quick filters')).toBeInTheDocument();
const addedSection = screen.getByText(ADDED_FILTERS_LABEL).parentElement!;
expect(addedSection).toContainElement(
@@ -454,7 +454,7 @@ describe('Quick Filters with custom filters', () => {
});
const requestBody = putHandler.mock.calls[0][0];
expect(requestBody.filters).toStrictEqual(
expect(requestBody.filters).toEqual(
expect.arrayContaining([
expect.not.objectContaining({ key: FILTER_OS_DESCRIPTION }),
]),
@@ -535,12 +535,12 @@ describe('Quick Filters refetch behavior', () => {
);
const { unmount } = render(<TestQuickFilters signal={SIGNAL} />);
await expect(screen.findByText(FILTER_SERVICE_NAME)).resolves.toBeInTheDocument();
expect(await screen.findByText(FILTER_SERVICE_NAME)).toBeInTheDocument();
unmount();
render(<TestQuickFilters signal={SIGNAL} />);
await expect(screen.findByText(FILTER_SERVICE_NAME)).resolves.toBeInTheDocument();
expect(await screen.findByText(FILTER_SERVICE_NAME)).toBeInTheDocument();
expect(getCalls).toBe(2);
});
@@ -578,7 +578,7 @@ describe('Quick Filters refetch behavior', () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
render(<TestQuickFilters signal={SIGNAL} />);
await expect(screen.findByText(FILTER_SERVICE_NAME)).resolves.toBeInTheDocument();
expect(await screen.findByText(FILTER_SERVICE_NAME)).toBeInTheDocument();
const icon = await screen.findByTestId(SETTINGS_ICON_TEST_ID);
const settingsButton = icon.closest('button') ?? icon;
@@ -628,7 +628,7 @@ describe('Quick Filters refetch behavior', () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
render(<TestQuickFilters signal={SIGNAL} />);
await expect(screen.findByText(FILTER_SERVICE_NAME)).resolves.toBeInTheDocument();
expect(await screen.findByText(FILTER_SERVICE_NAME)).toBeInTheDocument();
const icon = await screen.findByTestId(SETTINGS_ICON_TEST_ID);
const settingsButton = icon.closest('button') ?? icon;
@@ -657,6 +657,6 @@ describe('Quick Filters refetch behavior', () => {
render(<TestQuickFilters signal={SIGNAL} config={[]} />);
await expect(screen.findByText('No filters found')).resolves.toBeInTheDocument();
expect(await screen.findByText('No filters found')).toBeInTheDocument();
});
});

View File

@@ -19,8 +19,8 @@ const getFilterName = (str: string): string => {
// replace . and _ with space
// capitalize the first letter of each word
return str
.replaceAll(/\./g, ' ')
.replaceAll(/_/g, ' ')
.replace(/\./g, ' ')
.replace(/_/g, ' ')
.split(' ')
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');

View File

@@ -24,7 +24,7 @@ function RefreshPaymentStatus({
try {
await refreshPaymentStatus();
[await activeLicenseRefetch()];
await Promise.all([activeLicenseRefetch()]);
} catch (e) {
console.error(e);
}

View File

@@ -49,9 +49,9 @@ function DynamicColumnTable({
setColumnsData((prevColumns) =>
prevColumns
? [
...prevColumns.slice(0, - 1),
...prevColumns.slice(0, prevColumns.length - 1),
...visibleColumns,
prevColumns.at(-1),
prevColumns[prevColumns.length - 1],
]
: undefined,
);

View File

@@ -68,9 +68,9 @@ export const getNewColumnData: GetNewColumnDataFunction = ({
if (checked && dynamicColumns) {
return prevColumns
? [
...prevColumns.slice(0, - 1),
...prevColumns.slice(0, prevColumns.length - 1),
dynamicColumns[index],
prevColumns.at(-1),
prevColumns[prevColumns.length - 1],
]
: undefined;
}

View File

@@ -28,7 +28,7 @@ const testRoutes: RouteTabProps['routes'] = [
];
describe('RouteTab component', () => {
it('renders correctly', () => {
test('renders correctly', () => {
const history = createMemoryHistory();
render(
<Router history={history}>
@@ -39,7 +39,7 @@ describe('RouteTab component', () => {
expect(screen.getByRole('tab', { name: 'Tab2' })).toBeInTheDocument();
});
it('renders correct number of tabs', () => {
test('renders correct number of tabs', () => {
const history = createMemoryHistory();
render(
<Router history={history}>
@@ -47,10 +47,10 @@ describe('RouteTab component', () => {
</Router>,
);
const tabs = screen.getAllByRole('tab');
expect(tabs).toHaveLength(testRoutes.length);
expect(tabs.length).toBe(testRoutes.length);
});
it('sets provided activeKey as active tab', () => {
test('sets provided activeKey as active tab', () => {
const history = createMemoryHistory();
render(
<Router history={history}>
@@ -62,7 +62,7 @@ describe('RouteTab component', () => {
).toBeInTheDocument();
});
it('navigates to correct route on tab click', () => {
test('navigates to correct route on tab click', () => {
const history = createMemoryHistory();
render(
<Router history={history}>
@@ -74,7 +74,7 @@ describe('RouteTab component', () => {
expect(history.location.pathname).toBe('/tab2');
});
it('calls onChangeHandler on tab change', () => {
test('calls onChangeHandler on tab change', () => {
const onChangeHandler = jest.fn();
const history = createMemoryHistory();
render(

View File

@@ -70,7 +70,9 @@ describe('EditKeyModal (URL-controlled)', () => {
it('renders key data from prop when edit-key param is set', async () => {
renderModal();
await expect(screen.findByDisplayValue('Original Key Name')).resolves.toBeInTheDocument();
expect(
await screen.findByDisplayValue('Original Key Name'),
).toBeInTheDocument();
expect(screen.getByRole('button', { name: /Save Changes/i })).toBeDisabled();
});
@@ -108,8 +110,8 @@ describe('EditKeyModal (URL-controlled)', () => {
});
const latestUrlUpdate =
onUrlUpdate.mock.calls.at(-1)?.[0];
expect(latestUrlUpdate).toStrictEqual(
onUrlUpdate.mock.calls[onUrlUpdate.mock.calls.length - 1]?.[0];
expect(latestUrlUpdate).toEqual(
expect.objectContaining({
queryString: expect.any(String),
}),
@@ -132,7 +134,9 @@ describe('EditKeyModal (URL-controlled)', () => {
await user.click(screen.getByRole('button', { name: /Revoke Key/i }));
// Same dialog, now showing revoke confirmation
await expect(screen.findByRole('dialog', { name: /Revoke Original Key Name/i })).resolves.toBeInTheDocument();
expect(
await screen.findByRole('dialog', { name: /Revoke Original Key Name/i }),
).toBeInTheDocument();
expect(
screen.getByText(/Revoking this key will permanently invalidate it/i),
).toBeInTheDocument();

View File

@@ -104,7 +104,7 @@ describe('ServiceAccountDrawer', () => {
it('renders Overview tab by default: editable name input, locked email, Save disabled when not dirty', async () => {
renderDrawer();
await expect(screen.findByDisplayValue('CI Bot')).resolves.toBeInTheDocument();
expect(await screen.findByDisplayValue('CI Bot')).toBeInTheDocument();
expect(screen.getByText('ci-bot@signoz.io')).toBeInTheDocument();
expect(screen.getByRole('button', { name: /Save Changes/i })).toBeDisabled();
});
@@ -207,7 +207,7 @@ describe('ServiceAccountDrawer', () => {
expect(dialog).toBeInTheDocument();
const confirmBtns = screen.getAllByRole('button', { name: /^Delete$/i });
await user.click(confirmBtns.at(-1));
await user.click(confirmBtns[confirmBtns.length - 1]);
await waitFor(() => {
expect(deleteSpy).toHaveBeenCalled();
@@ -272,9 +272,11 @@ describe('ServiceAccountDrawer', () => {
renderDrawer();
await expect(screen.findByText(
expect(
await screen.findByText(
/An unexpected error occurred while fetching service account details/i,
)).resolves.toBeInTheDocument();
),
).toBeInTheDocument();
});
});
@@ -347,9 +349,11 @@ describe('ServiceAccountDrawer save-error UX', () => {
await waitFor(() => expect(saveBtn).not.toBeDisabled());
await user.click(saveBtn);
await expect(screen.findByText(/Name update.*name update failed/i, undefined, {
expect(
await screen.findByText(/Name update.*name update failed/i, undefined, {
timeout: 5000,
})).resolves.toBeInTheDocument();
}),
).toBeInTheDocument();
});
it('role add failure shows SaveErrorItem with the role name context', async () => {
@@ -381,13 +385,15 @@ describe('ServiceAccountDrawer save-error UX', () => {
await waitFor(() => expect(saveBtn).not.toBeDisabled());
await user.click(saveBtn);
await expect(screen.findByText(
expect(
await screen.findByText(
/Role 'signoz-viewer'.*role assign failed/i,
undefined,
{
timeout: 5000,
},
)).resolves.toBeInTheDocument();
),
).toBeInTheDocument();
});
it('role add retries on 429 then succeeds without showing an error', async () => {

View File

@@ -83,7 +83,7 @@ describe('useShiftHoldOverlay', () => {
it('does not activate in typing context (input)', () => {
const input = document.createElement('input');
document.body.append(input);
document.body.appendChild(input);
const { result } = renderHook(() => useShiftHoldOverlay({}));

View File

@@ -29,7 +29,7 @@ function TimelineV2(props: ITimelineV2Props): JSX.Element {
}
const minIntervals = getMinimumIntervalsBasedOnWidth(width);
const intervalisedSpread = (spread / minIntervals) * 1;
const intervalisedSpread = (spread / minIntervals) * 1.0;
setIntervals(getIntervals(intervalisedSpread, spread));
}, [startTimestamp, endTimestamp, width]);

View File

@@ -68,7 +68,7 @@ export function getIntervals(
const integerPartString = intervalSpread.toString().split('.')[0];
const integerPartLength = integerPartString.length;
const intervalSpreadNormalized =
intervalSpread < 1
intervalSpread < 1.0
? intervalSpread
: Math.floor(Number(integerPartString) / 10 ** (integerPartLength - 1)) *
10 ** (integerPartLength - 1);

View File

@@ -72,7 +72,7 @@ const Uplot = forwardRef<ToggleGraphProps | undefined, UplotProps>(
}
// Clean up tooltip overlay that might be detached
const overlay = document.querySelector('#overlay');
const overlay = document.getElementById('overlay');
if (overlay) {
// Remove all child elements from overlay
while (overlay.firstChild) {

View File

@@ -61,7 +61,9 @@ function YAxisUnitSelector({
}
// Check aliases (from the mapping) using array iteration
const aliases = [...UniversalYAxisUnitMappings[currentOption.value as UniversalYAxisUnit] ?? []];
const aliases = Array.from(
UniversalYAxisUnitMappings[currentOption.value as UniversalYAxisUnit] ?? [],
);
return aliases.some((alias) => alias.toLowerCase().includes(search));
};

View File

@@ -8,7 +8,7 @@ import { formatUniversalUnit } from '../formatter';
describe('formatUniversalUnit', () => {
describe('Time', () => {
it.each([
test.each([
// Days
[31, UniversalYAxisUnit.DAYS, '4.43 weeks'],
[7, UniversalYAxisUnit.DAYS, '1 week'],
@@ -48,7 +48,7 @@ describe('formatUniversalUnit', () => {
});
describe('Data', () => {
it.each([
test.each([
// Bytes
[864, UniversalYAxisUnit.BYTES, '864 B'],
[1000, UniversalYAxisUnit.BYTES, '1 kB'],
@@ -91,7 +91,7 @@ describe('formatUniversalUnit', () => {
});
describe('Data rate', () => {
it.each([
test.each([
// Bytes/second
[864, UniversalYAxisUnit.BYTES_SECOND, '864 B/s'],
[1000, UniversalYAxisUnit.BYTES_SECOND, '1 kB/s'],
@@ -134,7 +134,7 @@ describe('formatUniversalUnit', () => {
});
describe('Bit', () => {
it.each([
test.each([
// Bits
[1, UniversalYAxisUnit.BITS, '1 b'],
[250, UniversalYAxisUnit.BITS, '250 b'],
@@ -186,7 +186,7 @@ describe('formatUniversalUnit', () => {
});
describe('Bit rate', () => {
it.each([
test.each([
// Bits/second
[512, UniversalYAxisUnit.BITS_SECOND, '512 b/s'],
[1000, UniversalYAxisUnit.BITS_SECOND, '1 kb/s'],
@@ -236,7 +236,7 @@ describe('formatUniversalUnit', () => {
});
describe('Count', () => {
it.each([
test.each([
[100, UniversalYAxisUnit.COUNT, '100'],
[875, UniversalYAxisUnit.COUNT, '875'],
[1000, UniversalYAxisUnit.COUNT, '1 K'],
@@ -256,7 +256,7 @@ describe('formatUniversalUnit', () => {
expect(formatUniversalUnit(value, unit)).toBe(expected);
});
it.each([
test.each([
[100, UniversalYAxisUnit.COUNT_SECOND, '100 c/s'],
[875, UniversalYAxisUnit.COUNT_SECOND, '875 c/s'],
[1000, UniversalYAxisUnit.COUNT_SECOND, '1K c/s'],
@@ -267,7 +267,7 @@ describe('formatUniversalUnit', () => {
expect(formatUniversalUnit(value, unit)).toBe(expected);
});
it.each([
test.each([
[100, UniversalYAxisUnit.COUNT_MINUTE, '100 c/m'],
[875, UniversalYAxisUnit.COUNT_MINUTE, '875 c/m'],
[1000, UniversalYAxisUnit.COUNT_MINUTE, '1K c/m'],
@@ -280,7 +280,7 @@ describe('formatUniversalUnit', () => {
});
describe('Operations units', () => {
it.each([
test.each([
[780, UniversalYAxisUnit.OPS_SECOND, '780 ops/s'],
[1000, UniversalYAxisUnit.OPS_SECOND, '1K ops/s'],
[520, UniversalYAxisUnit.OPS_MINUTE, '520 ops/m'],
@@ -297,7 +297,7 @@ describe('formatUniversalUnit', () => {
});
describe('Request units', () => {
it.each([
test.each([
[615, UniversalYAxisUnit.REQUESTS_SECOND, '615 req/s'],
[1000, UniversalYAxisUnit.REQUESTS_SECOND, '1K req/s'],
[480, UniversalYAxisUnit.REQUESTS_MINUTE, '480 req/m'],
@@ -311,7 +311,7 @@ describe('formatUniversalUnit', () => {
});
describe('Read/Write units', () => {
it.each([
test.each([
[505, UniversalYAxisUnit.READS_SECOND, '505 rd/s'],
[1000, UniversalYAxisUnit.READS_SECOND, '1K rd/s'],
[610, UniversalYAxisUnit.WRITES_SECOND, '610 wr/s'],
@@ -335,7 +335,7 @@ describe('formatUniversalUnit', () => {
});
describe('IO Operations units', () => {
it.each([
test.each([
[777, UniversalYAxisUnit.IOOPS_SECOND, '777 io/s'],
[1000, UniversalYAxisUnit.IOOPS_SECOND, '1K io/s'],
[2500, UniversalYAxisUnit.IOOPS_SECOND, '2.5K io/s'],
@@ -363,7 +363,7 @@ describe('formatUniversalUnit', () => {
});
describe('Time (additional)', () => {
it.each([
test.each([
[900, UniversalYAxisUnit.DURATION_MS, '900 milliseconds'],
[1000, UniversalYAxisUnit.DURATION_MS, '1 second'],
[1, UniversalYAxisUnit.DURATION_MS, '1 millisecond'],
@@ -388,7 +388,7 @@ describe('formatUniversalUnit', () => {
});
describe('Data (IEC/Binary)', () => {
it.each([
test.each([
// Bytes
[900, UniversalYAxisUnit.BYTES_IEC, '900 B'],
[1024, UniversalYAxisUnit.BYTES_IEC, '1 KiB'],
@@ -430,7 +430,7 @@ describe('formatUniversalUnit', () => {
});
describe('Data Rate (IEC/Binary)', () => {
it.each([
test.each([
// Kibibytes/second
[900, UniversalYAxisUnit.KIBIBYTES_SECOND, '900 KiB/s'],
[1024, UniversalYAxisUnit.KIBIBYTES_SECOND, '1 MiB/s'],
@@ -473,7 +473,7 @@ describe('formatUniversalUnit', () => {
});
describe('Bits (IEC)', () => {
it.each([
test.each([
[900, UniversalYAxisUnit.BITS_IEC, '900 b'],
[1024, UniversalYAxisUnit.BITS_IEC, '1 Kib'],
[1080, UniversalYAxisUnit.BITS_IEC, '1.05 Kib'],
@@ -483,7 +483,7 @@ describe('formatUniversalUnit', () => {
});
describe('Hash Rate', () => {
it.each([
test.each([
// Hashes/second
[412, UniversalYAxisUnit.HASH_RATE_HASHES_PER_SECOND, '412 H/s'],
[1000, UniversalYAxisUnit.HASH_RATE_HASHES_PER_SECOND, '1 kH/s'],
@@ -518,7 +518,7 @@ describe('formatUniversalUnit', () => {
});
describe('Miscellaneous', () => {
it.each([
test.each([
[742, UniversalYAxisUnit.MISC_STRING, '742'],
[688, UniversalYAxisUnit.MISC_SHORT, '688'],
[555, UniversalYAxisUnit.MISC_HUMIDITY, '555 %H'],
@@ -534,7 +534,7 @@ describe('formatUniversalUnit', () => {
});
describe('Acceleration', () => {
it.each([
test.each([
[
875,
UniversalYAxisUnit.ACCELERATION_METERS_PER_SECOND_SQUARED,
@@ -553,7 +553,7 @@ describe('formatUniversalUnit', () => {
});
describe('Angular', () => {
it.each([
test.each([
[415, UniversalYAxisUnit.ANGULAR_DEGREE, '415 °'],
[732, UniversalYAxisUnit.ANGULAR_RADIAN, '732 rad'],
[128, UniversalYAxisUnit.ANGULAR_GRADIAN, '128 grad'],
@@ -565,7 +565,7 @@ describe('formatUniversalUnit', () => {
});
describe('Area', () => {
it.each([
test.each([
[210, UniversalYAxisUnit.AREA_SQUARE_METERS, '210 m²'],
[152, UniversalYAxisUnit.AREA_SQUARE_FEET, '152 ft²'],
[64, UniversalYAxisUnit.AREA_SQUARE_MILES, '64 mi²'],
@@ -575,7 +575,7 @@ describe('formatUniversalUnit', () => {
});
describe('FLOPs', () => {
it.each([
test.each([
// FLOPS
[150, UniversalYAxisUnit.FLOPS_FLOPS, '150 FLOPS'],
[1000, UniversalYAxisUnit.FLOPS_FLOPS, '1 kFLOPS'],
@@ -613,7 +613,7 @@ describe('formatUniversalUnit', () => {
});
describe('Concentration', () => {
it.each([
test.each([
[415, UniversalYAxisUnit.CONCENTRATION_PPM, '415 ppm'],
[1000, UniversalYAxisUnit.CONCENTRATION_PPM, '1000 ppm'],
[732, UniversalYAxisUnit.CONCENTRATION_PPB, '732 ppb'],
@@ -650,7 +650,7 @@ describe('formatUniversalUnit', () => {
});
describe('Currency', () => {
it.each([
test.each([
[812, UniversalYAxisUnit.CURRENCY_USD, '$812'],
[645, UniversalYAxisUnit.CURRENCY_GBP, '£645'],
[731, UniversalYAxisUnit.CURRENCY_EUR, '€731'],
@@ -688,7 +688,7 @@ describe('formatUniversalUnit', () => {
});
describe('Power/Electrical', () => {
it.each([
test.each([
[715, UniversalYAxisUnit.POWER_WATT, '715 W'],
[1000, UniversalYAxisUnit.POWER_WATT, '1 kW'],
[1080, UniversalYAxisUnit.POWER_WATT, '1.08 kW'],
@@ -744,7 +744,7 @@ describe('formatUniversalUnit', () => {
});
describe('Flow', () => {
it.each([
test.each([
[512, UniversalYAxisUnit.FLOW_GALLONS_PER_MINUTE, '512 gpm'],
[1000, UniversalYAxisUnit.FLOW_GALLONS_PER_MINUTE, '1000 gpm'],
[678, UniversalYAxisUnit.FLOW_CUBIC_METERS_PER_SECOND, '678 cms'],
@@ -766,7 +766,7 @@ describe('formatUniversalUnit', () => {
});
describe('Force', () => {
it.each([
test.each([
[845, UniversalYAxisUnit.FORCE_NEWTON_METERS, '845 Nm'],
[1000, UniversalYAxisUnit.FORCE_NEWTON_METERS, '1 kNm'],
[1080, UniversalYAxisUnit.FORCE_NEWTON_METERS, '1.08 kNm'],
@@ -782,7 +782,7 @@ describe('formatUniversalUnit', () => {
});
describe('Mass', () => {
it.each([
test.each([
[120, UniversalYAxisUnit.MASS_MILLIGRAM, '120 mg'],
[120000, UniversalYAxisUnit.MASS_MILLIGRAM, '120 g'],
[987, UniversalYAxisUnit.MASS_GRAM, '987 g'],
@@ -796,7 +796,7 @@ describe('formatUniversalUnit', () => {
});
describe('Length', () => {
it.each([
test.each([
[88, UniversalYAxisUnit.LENGTH_MILLIMETER, '88 mm'],
[100, UniversalYAxisUnit.LENGTH_MILLIMETER, '100 mm'],
[1000, UniversalYAxisUnit.LENGTH_MILLIMETER, '1 m'],
@@ -812,7 +812,7 @@ describe('formatUniversalUnit', () => {
});
describe('Pressure', () => {
it.each([
test.each([
[45, UniversalYAxisUnit.PRESSURE_MILLIBAR, '45 mbar'],
[1013, UniversalYAxisUnit.PRESSURE_MILLIBAR, '1.01 bar'],
[27, UniversalYAxisUnit.PRESSURE_BAR, '27 bar'],
@@ -828,7 +828,7 @@ describe('formatUniversalUnit', () => {
});
describe('Radiation', () => {
it.each([
test.each([
[452, UniversalYAxisUnit.RADIATION_BECQUEREL, '452 Bq'],
[37, UniversalYAxisUnit.RADIATION_CURIE, '37 Ci'],
[128, UniversalYAxisUnit.RADIATION_GRAY, '128 Gy'],
@@ -849,7 +849,7 @@ describe('formatUniversalUnit', () => {
});
describe('Rotation Speed', () => {
it.each([
test.each([
[345, UniversalYAxisUnit.ROTATION_SPEED_REVOLUTIONS_PER_MINUTE, '345 rpm'],
[789, UniversalYAxisUnit.ROTATION_SPEED_HERTZ, '789 Hz'],
[789000, UniversalYAxisUnit.ROTATION_SPEED_HERTZ, '789 kHz'],
@@ -861,7 +861,7 @@ describe('formatUniversalUnit', () => {
});
describe('Temperature', () => {
it.each([
test.each([
[37, UniversalYAxisUnit.TEMPERATURE_CELSIUS, '37 °C'],
[451, UniversalYAxisUnit.TEMPERATURE_FAHRENHEIT, '451 °F'],
[310, UniversalYAxisUnit.TEMPERATURE_KELVIN, '310 K'],
@@ -871,7 +871,7 @@ describe('formatUniversalUnit', () => {
});
describe('Velocity', () => {
it.each([
test.each([
[900, UniversalYAxisUnit.VELOCITY_METERS_PER_SECOND, '900 m/s'],
[456, UniversalYAxisUnit.VELOCITY_KILOMETERS_PER_HOUR, '456 km/h'],
[789, UniversalYAxisUnit.VELOCITY_MILES_PER_HOUR, '789 mph'],
@@ -882,7 +882,7 @@ describe('formatUniversalUnit', () => {
});
describe('Volume', () => {
it.each([
test.each([
[1200, UniversalYAxisUnit.VOLUME_MILLILITER, '1.2 L'],
[9000000, UniversalYAxisUnit.VOLUME_MILLILITER, '9 kL'],
[9, UniversalYAxisUnit.VOLUME_LITER, '9 L'],

View File

@@ -16,8 +16,8 @@ describe('YAxisUnitSelector utils', () => {
it('returns null or self for unknown units', () => {
expect(mapMetricUnitToUniversalUnit('unknown_unit')).toBe('unknown_unit');
expect(mapMetricUnitToUniversalUnit('')).toBeNull();
expect(mapMetricUnitToUniversalUnit()).toBeNull();
expect(mapMetricUnitToUniversalUnit('')).toBe(null);
expect(mapMetricUnitToUniversalUnit(undefined)).toBe(null);
});
});
@@ -31,7 +31,7 @@ describe('YAxisUnitSelector utils', () => {
it('returns original unit for unknown units', () => {
expect(getUniversalNameFromMetricUnit('unknown_unit')).toBe('unknown_unit');
expect(getUniversalNameFromMetricUnit('')).toBe('-');
expect(getUniversalNameFromMetricUnit()).toBe('-');
expect(getUniversalNameFromMetricUnit(undefined)).toBe('-');
});
it('handles case variations', () => {
@@ -62,7 +62,7 @@ describe('YAxisUnitSelector utils', () => {
},
];
const mergedCategories = mergeCategories(categories1, categories2);
expect(mergedCategories).toStrictEqual([
expect(mergedCategories).toEqual([
{
name: YAxisCategoryNames.Data,
units: [

View File

@@ -56,7 +56,7 @@ export function formatUniversalUnit(
const formatted = formatter(scaled.value, decimals);
if (formatted.text && formatted.text.includes('.')) {
formatted.text = formatDecimalWithLeadingZeros(
Number.parseFloat(formatted.text),
parseFloat(formatted.text),
precision,
);
}
@@ -70,7 +70,7 @@ export function formatUniversalUnit(
const formatted = formatter(value, decimals);
if (formatted.text && formatted.text.includes('.')) {
formatted.text = formatDecimalWithLeadingZeros(
Number.parseFloat(formatted.text),
parseFloat(formatted.text),
precision,
);
}
@@ -82,7 +82,7 @@ export function formatUniversalUnit(
const formatted = formatter(value, decimals);
if (formatted.text && formatted.text.includes('.')) {
formatted.text = formatDecimalWithLeadingZeros(
Number.parseFloat(formatted.text),
parseFloat(formatted.text),
precision,
);
}

View File

@@ -68,7 +68,7 @@ export function mergeCategories(
}
});
return [...mapOfCategories.values()];
return Array.from(mapOfCategories.values());
}
export function getYAxisCategories(source: YAxisSource): YAxisCategory[] {

View File

@@ -41,7 +41,7 @@ jest.mock('lib/history', () => {
location.search = search;
stack.push({ pathname, search });
return;
return undefined;
});
const replace = jest.fn((path: string) => {
@@ -57,7 +57,7 @@ jest.mock('lib/history', () => {
} else {
stack.push({ pathname, search });
}
return;
return undefined;
});
const listen = jest.fn();
@@ -65,7 +65,7 @@ jest.mock('lib/history', () => {
if (n < 0 && stack.length > 1) {
stack.pop();
}
const top = stack.at(-1) || { pathname: '/', search: '' };
const top = stack[stack.length - 1] || { pathname: '/', search: '' };
location.pathname = top.pathname;
location.search = top.search;
});
@@ -149,7 +149,7 @@ describe('CmdKPalette', () => {
jest.clearAllMocks();
});
it('renders navigation and settings groups and items', () => {
test('renders navigation and settings groups and items', () => {
render(<CmdKPalette userRole="ADMIN" />);
expect(screen.getByText('Navigation')).toBeInTheDocument();
@@ -160,7 +160,7 @@ describe('CmdKPalette', () => {
expect(screen.getByText('Switch to Dark Mode')).toBeInTheDocument();
});
it('clicking a navigation item calls history.push with correct route', async () => {
test('clicking a navigation item calls history.push with correct route', async () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
render(<CmdKPalette userRole="ADMIN" />);
@@ -170,14 +170,14 @@ describe('CmdKPalette', () => {
expect(history.push).toHaveBeenCalledWith(ROUTES.HOME);
});
it('role-based filtering (basic smoke)', () => {
test('role-based filtering (basic smoke)', () => {
render(<CmdKPalette userRole="VIEWER" />);
// VIEWER still sees basic navigation items
expect(screen.getByText(HOME_LABEL)).toBeInTheDocument();
});
it('keyboard shortcut opens palette via setOpen', () => {
test('keyboard shortcut opens palette via setOpen', () => {
render(<CmdKPalette userRole="ADMIN" />);
const event = new KeyboardEvent('keydown', { key: 'k', ctrlKey: true });
@@ -186,7 +186,7 @@ describe('CmdKPalette', () => {
expect(mockSetOpen).toHaveBeenCalledWith(true);
});
it('items render with icons when provided', () => {
test('items render with icons when provided', () => {
render(<CmdKPalette userRole="ADMIN" />);
const iconHolders = document.querySelectorAll('.cmd-item-icon');
@@ -194,7 +194,7 @@ describe('CmdKPalette', () => {
expect(screen.getByText(HOME_LABEL)).toBeInTheDocument();
});
it('closing the palette via handleInvoke sets open to false', async () => {
test('closing the palette via handleInvoke sets open to false', async () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
render(<CmdKPalette userRole="ADMIN" />);

View File

@@ -103,7 +103,7 @@ export function CmdKPalette({
}
});
return [...map.entries()];
return Array.from(map.entries());
})();
const handleInvoke = (action: CmdAction): void => {

View File

@@ -68,7 +68,7 @@ export const DATE_TIME_FORMATS = {
export const convert24hTo12h = (format: string): string =>
format
.replaceAll(/\bHH:mm:ss\.SSS\b/g, 'hh:mm:ss.SSS A')
.replaceAll(/\bHH:mm:ss\b/g, 'hh:mm:ss A')
.replaceAll(/\bHH:mm\b/g, 'hh:mm A')
.replaceAll(/\bh:mm:ss\b/g, 'h:mm:ss A');
.replace(/\bHH:mm:ss\.SSS\b/g, 'hh:mm:ss.SSS A')
.replace(/\bHH:mm:ss\b/g, 'hh:mm:ss A')
.replace(/\bHH:mm\b/g, 'hh:mm A')
.replace(/\bh:mm:ss\b/g, 'h:mm:ss A');

View File

@@ -74,7 +74,7 @@ export const formulasNames: string[] = Array.from(
(_, i) => `F${i + 1}`,
);
const alpha: number[] = Array.from(Array(MAX_QUERIES), (_, i) => i + 65);
export const alphabet: string[] = alpha.map((str) => String.fromCodePoint(str));
export const alphabet: string[] = alpha.map((str) => String.fromCharCode(str));
export enum QueryBuilderKeys {
GET_AGGREGATE_ATTRIBUTE = 'GET_AGGREGATE_ATTRIBUTE',

View File

@@ -2,7 +2,7 @@ export const extractDayFromTimestamp = (timestamp: string | null): string => {
if (!timestamp) {
return '';
}
const date = new Date(Number.parseInt(timestamp, 10));
const date = new Date(parseInt(timestamp, 10));
return date.getDate().toString();
};
@@ -12,5 +12,5 @@ export const convertTimestampToLocaleDateString = (
if (!timestamp) {
return '';
}
return new Date(Number.parseInt(timestamp, 10)).toLocaleString();
return new Date(parseInt(timestamp, 10)).toLocaleString();
};

View File

@@ -5,7 +5,7 @@ function TopContributorsContent({
topContributorsData,
totalCurrentTriggers,
}: TopContributorsCardProps): JSX.Element {
const isEmpty = topContributorsData.length === 0;
const isEmpty = !topContributorsData.length;
if (isEmpty) {
return (

View File

@@ -38,12 +38,12 @@ function HorizontalTimelineGraph({
const timestamps = [
...data.map((item) => item.start / 1000),
data.at(-1).end / 1000, // end value of last entry
data[data.length - 1].end / 1000, // end value of last entry
];
const states = [
...data.map((item) => ALERT_STATUS[item.state]),
ALERT_STATUS[data.at(-1).state], // Same state as the last entry
ALERT_STATUS[data[data.length - 1].state], // Same state as the last entry
];
return [timestamps, states];

View File

@@ -45,7 +45,7 @@ function LabelFilter({
const tagFiltersLength = tagFilters.items.length;
if (
(!tagFiltersLength && (!filters || filters.items.length === 0)) ||
(!tagFiltersLength && (!filters || !filters.items.length)) ||
tagFiltersLength === filters?.items.length
) {
return;

View File

@@ -34,13 +34,13 @@ describe('Alert Channels Settings List page', () => {
jest.useRealTimers();
});
describe('Should display the Alert Channels page properly', () => {
it('Should check if "The alerts will be sent to all the configured channels." is visible', () => {
it('Should check if "The alerts will be sent to all the configured channels." is visible ', () => {
expect(screen.getByText('sending_channels_note')).toBeInTheDocument();
});
it('Should check if "New Alert Channel" Button is visble', () => {
it('Should check if "New Alert Channel" Button is visble ', () => {
expect(screen.getByText('button_new_channel')).toBeInTheDocument();
});
it('Should check if the help icon is visible and displays "tooltip_notification_channels', async () => {
it('Should check if the help icon is visible and displays "tooltip_notification_channels ', async () => {
const helpIcon = screen.getByLabelText('question-circle');
fireEvent.mouseOver(helpIcon);

View File

@@ -38,7 +38,7 @@ describe('Alert Channels Settings List page (Normal User)', () => {
jest.useRealTimers();
});
describe('Should display the Alert Channels page properly', () => {
it('Should check if "The alerts will be sent to all the configured channels." is visible', async () => {
it('Should check if "The alerts will be sent to all the configured channels." is visible ', async () => {
await waitFor(() =>
expect(screen.getByText('sending_channels_note')).toBeInTheDocument(),
);
@@ -51,7 +51,7 @@ describe('Alert Channels Settings List page (Normal User)', () => {
await waitFor(() => expect(newAlertButton).toBeInTheDocument());
expect(newAlertButton).toBeDisabled();
});
it('Should check if the help icon is visible and displays "tooltip_notification_channels', async () => {
it('Should check if the help icon is visible and displays "tooltip_notification_channels ', async () => {
const helpIcon = screen.getByLabelText('question-circle');
fireEvent.mouseOver(helpIcon);

View File

@@ -44,7 +44,7 @@ describe('Create Alert Channel', () => {
afterEach(() => {
jest.clearAllMocks();
});
describe('Should check if the new alert channel is properly displayed with the cascading fields of slack channel', () => {
describe('Should check if the new alert channel is properly displayed with the cascading fields of slack channel ', () => {
beforeEach(() => {
render(<CreateAlertChannels preType={ChannelType.Slack} />);
});
@@ -54,13 +54,13 @@ describe('Create Alert Channel', () => {
it('Should check if the title is "New Notification Channels"', () => {
expect(screen.getByText('page_title_create')).toBeInTheDocument();
});
it('Should check if the name label and textbox are displayed properly', () => {
it('Should check if the name label and textbox are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_channel_name',
testId: 'channel-name-textbox',
});
});
it('Should check if Send resolved alerts label and checkbox are displayed properly', () => {
it('Should check if Send resolved alerts label and checkbox are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_send_resolved',
testId: 'field-send-resolved-checkbox',
@@ -76,13 +76,13 @@ describe('Create Alert Channel', () => {
it('Should check if the selected item in the type dropdown has text "Slack"', () => {
expect(screen.getByText('Slack')).toBeInTheDocument();
});
it('Should check if Webhook URL label and input are displayed properly', () => {
it('Should check if Webhook URL label and input are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_webhook_url',
testId: 'webhook-url-textbox',
});
});
it('Should check if Recepient label, input, and help text are displayed properly', () => {
it('Should check if Recepient label, input, and help text are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_recipient',
testId: 'slack-channel-textbox',
@@ -90,7 +90,7 @@ describe('Create Alert Channel', () => {
});
});
it('Should check if Title label and text area are displayed properly', () => {
it('Should check if Title label and text area are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_title',
testId: 'title-textarea',
@@ -101,7 +101,7 @@ describe('Create Alert Channel', () => {
expect(titleTextArea).toHaveTextContent(slackTitleDefaultValue);
});
it('Should check if Description label and text area are displayed properly', () => {
it('Should check if Description label and text area are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_description',
testId: 'description-textarea',
@@ -177,13 +177,13 @@ describe('Create Alert Channel', () => {
it('Should check if the selected item in the type dropdown has text "Webhook"', () => {
expect(screen.getByText('Webhook')).toBeInTheDocument();
});
it('Should check if Webhook URL label and input are displayed properly', () => {
it('Should check if Webhook URL label and input are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_webhook_url',
testId: 'webhook-url-textbox',
});
});
it('Should check if Webhook User Name label, input, and help text are displayed properly', () => {
it('Should check if Webhook User Name label, input, and help text are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_webhook_username',
testId: 'webhook-username-textbox',
@@ -321,7 +321,7 @@ describe('Create Alert Channel', () => {
});
});
it('Should check if Message contains the default template', () => {
it('Should check if Message contains the default template ', () => {
const messageTextArea = screen.getByTestId('opsgenie-message-textarea');
expect(messageTextArea).toHaveValue(opsGenieMessageDefaultValue);
@@ -387,14 +387,14 @@ describe('Create Alert Channel', () => {
expect(screen.getByText('Microsoft Teams')).toBeInTheDocument();
});
it('Should check if Webhook URL label and input are displayed properly', () => {
it('Should check if Webhook URL label and input are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_webhook_url',
testId: 'webhook-url-textbox',
});
});
it('Should check if Title label and text area are displayed properly', () => {
it('Should check if Title label and text area are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_title',
testId: 'title-textarea',
@@ -406,7 +406,7 @@ describe('Create Alert Channel', () => {
expect(titleTextArea).toHaveTextContent(slackTitleDefaultValue);
});
it('Should check if Description label and text area are displayed properly', () => {
it('Should check if Description label and text area are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_description',
testId: 'description-textarea',

View File

@@ -23,20 +23,20 @@ describe('Create Alert Channel (Normal User)', () => {
afterEach(() => {
jest.clearAllMocks();
});
describe('Should check if the new alert channel is properly displayed with the cascading fields of slack channel', () => {
describe('Should check if the new alert channel is properly displayed with the cascading fields of slack channel ', () => {
beforeEach(() => {
render(<CreateAlertChannels preType={ChannelType.Slack} />);
});
it('Should check if the title is "New Notification Channels"', () => {
expect(screen.getByText('page_title_create')).toBeInTheDocument();
});
it('Should check if the name label and textbox are displayed properly', () => {
it('Should check if the name label and textbox are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_channel_name',
testId: 'channel-name-textbox',
});
});
it('Should check if Send resolved alerts label and checkbox are displayed properly', () => {
it('Should check if Send resolved alerts label and checkbox are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_send_resolved',
testId: 'field-send-resolved-checkbox',
@@ -52,13 +52,13 @@ describe('Create Alert Channel (Normal User)', () => {
it('Should check if the selected item in the type dropdown has text "Slack"', () => {
expect(screen.getByText('Slack')).toBeInTheDocument();
});
it('Should check if Webhook URL label and input are displayed properly', () => {
it('Should check if Webhook URL label and input are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_webhook_url',
testId: 'webhook-url-textbox',
});
});
it('Should check if Recepient label, input, and help text are displayed properly', () => {
it('Should check if Recepient label, input, and help text are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_recipient',
testId: 'slack-channel-textbox',
@@ -66,7 +66,7 @@ describe('Create Alert Channel (Normal User)', () => {
});
});
it('Should check if Title label and text area are displayed properly', () => {
it('Should check if Title label and text area are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_title',
testId: 'title-textarea',
@@ -77,7 +77,7 @@ describe('Create Alert Channel (Normal User)', () => {
expect(titleTextArea).toHaveTextContent(slackTitleDefaultValue);
});
it('Should check if Description label and text area are displayed properly', () => {
it('Should check if Description label and text area are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_description',
testId: 'description-textarea',
@@ -103,13 +103,13 @@ describe('Create Alert Channel (Normal User)', () => {
it('Should check if the selected item in the type dropdown has text "Webhook"', () => {
expect(screen.getByText('Webhook')).toBeInTheDocument();
});
it('Should check if Webhook URL label and input are displayed properly', () => {
it('Should check if Webhook URL label and input are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_webhook_url',
testId: 'webhook-url-textbox',
});
});
it('Should check if Webhook User Name label, input, and help text are displayed properly', () => {
it('Should check if Webhook User Name label, input, and help text are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_webhook_username',
testId: 'webhook-username-textbox',
@@ -247,7 +247,7 @@ describe('Create Alert Channel (Normal User)', () => {
});
});
it('Should check if Message contains the default template', () => {
it('Should check if Message contains the default template ', () => {
const messageTextArea = screen.getByTestId('opsgenie-message-textarea');
expect(messageTextArea).toHaveValue(opsGenieMessageDefaultValue);

View File

@@ -24,7 +24,7 @@ jest.mock('components/MarkdownRenderer/MarkdownRenderer', () => ({
MarkdownRenderer: jest.fn(() => <div>Mocked MarkdownRenderer</div>),
}));
describe('Should check if the edit alert channel is properly displayed', () => {
describe('Should check if the edit alert channel is properly displayed ', () => {
beforeEach(() => {
render(<EditAlertChannels initialValue={editAlertChannelInitialValue} />);
});
@@ -35,14 +35,14 @@ describe('Should check if the edit alert channel is properly displayed', () => {
expect(screen.getByText('page_title_edit')).toBeInTheDocument();
});
it('Should check if the name label and textbox are displayed properly', () => {
it('Should check if the name label and textbox are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_channel_name',
testId: 'channel-name-textbox',
value: 'Dummy-Channel',
});
});
it('Should check if Send resolved alerts label and checkbox are displayed properly and the checkbox is checked', () => {
it('Should check if Send resolved alerts label and checkbox are displayed properly and the checkbox is checked ', () => {
testLabelInputAndHelpValue({
labelText: 'field_send_resolved',
testId: 'field-send-resolved-checkbox',
@@ -61,7 +61,7 @@ describe('Should check if the edit alert channel is properly displayed', () => {
expect(screen.getByText('Slack')).toBeInTheDocument();
});
it('Should check if Webhook URL label and input are displayed properly', () => {
it('Should check if Webhook URL label and input are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_webhook_url',
testId: 'webhook-url-textbox',
@@ -70,7 +70,7 @@ describe('Should check if the edit alert channel is properly displayed', () => {
});
});
it('Should check if Recepient label, input, and help text are displayed properly', () => {
it('Should check if Recepient label, input, and help text are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_recipient',
testId: 'slack-channel-textbox',
@@ -79,7 +79,7 @@ describe('Should check if the edit alert channel is properly displayed', () => {
});
});
it('Should check if Title label and text area are displayed properly', () => {
it('Should check if Title label and text area are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_title',
testId: 'title-textarea',
@@ -92,7 +92,7 @@ describe('Should check if the edit alert channel is properly displayed', () => {
expect(titleTextArea).toHaveTextContent(slackTitleDefaultValue);
});
it('Should check if Description label and text area are displayed properly', () => {
it('Should check if Description label and text area are displayed properly ', () => {
testLabelInputAndHelpValue({
labelText: 'field_slack_description',
testId: 'description-textarea',

View File

@@ -12,7 +12,7 @@ import {
} from './utils';
describe('Error utils', () => {
it('Valid OrderBy Params', () => {
test('Valid OrderBy Params', () => {
expect(isOrderParams('serviceName')).toBe(true);
expect(isOrderParams('exceptionCount')).toBe(true);
expect(isOrderParams('lastSeen')).toBe(true);
@@ -20,24 +20,24 @@ describe('Error utils', () => {
expect(isOrderParams('exceptionType')).toBe(true);
});
it('Invalid OrderBy Params', () => {
test('Invalid OrderBy Params', () => {
expect(isOrderParams('invalid')).toBe(false);
expect(isOrderParams(null)).toBe(false);
expect(isOrderParams('')).toBe(false);
});
it('Valid Order', () => {
test('Valid Order', () => {
expect(isOrder('ascending')).toBe(true);
expect(isOrder('descending')).toBe(true);
});
it('Invalid Order', () => {
test('Invalid Order', () => {
expect(isOrder('invalid')).toBe(false);
expect(isOrder(null)).toBe(false);
expect(isOrder('')).toBe(false);
});
it('Default Order', () => {
test('Default Order', () => {
const OrderBy: OrderBy[] = [
'exceptionCount',
'exceptionType',
@@ -57,7 +57,7 @@ describe('Error utils', () => {
});
});
it('Limit', () => {
test('Limit', () => {
expect(getLimit(null)).toBe(10);
expect(getLimit('')).toBe(10);
expect(getLimit('0')).toBe(0);
@@ -68,7 +68,7 @@ describe('Error utils', () => {
expect(getLimit('101')).toBe(101);
});
it('Update Page Size', () => {
test('Update Page Size', () => {
expect(getUpdatePageSize(null)).toBe(10);
expect(getUpdatePageSize('')).toBe(10);
expect(getUpdatePageSize('0')).toBe(0);
@@ -79,7 +79,7 @@ describe('Error utils', () => {
expect(getUpdatePageSize('101')).toBe(101);
});
it('Order Params', () => {
test('Order Params', () => {
expect(getOrderParams(null)).toBe('serviceName');
expect(getOrderParams('')).toBe('serviceName');
expect(getOrderParams('serviceName')).toBe('serviceName');
@@ -89,7 +89,7 @@ describe('Error utils', () => {
expect(getOrderParams('exceptionType')).toBe('exceptionType');
});
it('OffSet', () => {
test('OffSet', () => {
expect(getOffSet(null)).toBe(0);
expect(getOffSet('')).toBe(0);
expect(getOffSet('0')).toBe(0);
@@ -100,7 +100,7 @@ describe('Error utils', () => {
expect(getOffSet('101')).toBe(101);
});
it('Order', () => {
test('Order', () => {
expect(getOrder(null)).toBe('ascending');
expect(getOrder('')).toBe('ascending');
expect(getOrder('ascending')).toBe('ascending');

View File

@@ -39,14 +39,14 @@ export const getOrder = (order: string | null): Order => {
export const getLimit = (limit: string | null): number => {
if (limit) {
return Number.parseInt(limit, 10);
return parseInt(limit, 10);
}
return 10;
};
export const getOffSet = (offset: string | null): number => {
if (offset && typeof offset === 'string') {
return Number.parseInt(offset, 10);
return parseInt(offset, 10);
}
return 0;
};
@@ -88,7 +88,7 @@ export const getNanoSeconds = (date: string): string =>
export const getUpdatePageSize = (pageSize: string | null): number => {
if (pageSize) {
return Number.parseInt(pageSize, 10);
return parseInt(pageSize, 10);
}
return 10;
};

View File

@@ -30,18 +30,18 @@ function UplotChart({
useEffect(() => {
if (plotInstance.current) {
// @ts-expect-error
// @ts-ignore
plotInstance.current.destroy();
}
if (data && data.length > 0) {
// @ts-expect-error
// @ts-ignore
plotInstance.current = new uPlot(options, data, chartRef.current);
}
return (): void => {
if (plotInstance.current) {
// @ts-expect-error
// @ts-ignore
plotInstance.current.destroy();
}
};
@@ -140,7 +140,7 @@ function AnomalyAlertEvaluationView({
},
};
const initialData = allSeries.length > 0
const initialData = allSeries.length
? [
seriesData[allSeries[0]].data[0], // Shared X-axis
...allSeries.map((key) => seriesData[key].data[1]), // Map through Y-axis data for all series
@@ -275,7 +275,7 @@ function AnomalyAlertEvaluationView({
};
const handleSearchValueChange = useDebouncedFn((event): void => {
// @ts-expect-error
// @ts-ignore
const value = event?.target?.value || '';
handleSearch(value);

View File

@@ -13,8 +13,8 @@ const tooltipPlugin = (
let isMouseOverPlot = false;
function formatValue(value: string | number | Date): string | number | Date {
if (typeof value === 'string' && !Number.isNaN(Number.parseFloat(value))) {
return Number.parseFloat(value).toFixed(3);
if (typeof value === 'string' && !Number.isNaN(parseFloat(value))) {
return parseFloat(value).toFixed(3);
}
if (typeof value === 'number') {
return value.toFixed(3);
@@ -121,7 +121,7 @@ const tooltipPlugin = (
tooltip = document.createElement('div');
tooltip.className = 'uplot-tooltip';
tooltip.style.display = 'none';
u.over.append(tooltip);
u.over.appendChild(tooltip);
// Add event listeners
u.over.addEventListener('mouseenter', () => {

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