mirror of
https://github.com/SigNoz/signoz.git
synced 2026-02-23 16:59:30 +00:00
Compare commits
9 Commits
fix/remove
...
fix/issue-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c0684dbf79 | ||
|
|
5133346f77 | ||
|
|
d48495aecc | ||
|
|
465e07de83 | ||
|
|
67184b4064 | ||
|
|
53d7753167 | ||
|
|
c04f664e2f | ||
|
|
e406b0bb61 | ||
|
|
c143e0b130 |
@@ -326,6 +326,9 @@ components:
|
||||
type: string
|
||||
url:
|
||||
type: string
|
||||
required:
|
||||
- code
|
||||
- message
|
||||
type: object
|
||||
ErrorsResponseerroradditional:
|
||||
properties:
|
||||
@@ -1661,6 +1664,9 @@ components:
|
||||
$ref: '#/components/schemas/ErrorsJSON'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- error
|
||||
type: object
|
||||
RoletypesGettableResources:
|
||||
properties:
|
||||
@@ -2150,6 +2156,9 @@ paths:
|
||||
type: array
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"500":
|
||||
@@ -2233,6 +2242,9 @@ paths:
|
||||
$ref: '#/components/schemas/AuthtypesGettableToken'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: See Other
|
||||
"400":
|
||||
@@ -2271,6 +2283,9 @@ paths:
|
||||
$ref: '#/components/schemas/AuthtypesGettableToken'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: See Other
|
||||
"400":
|
||||
@@ -2334,6 +2349,9 @@ paths:
|
||||
$ref: '#/components/schemas/AuthtypesGettableToken'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: See Other
|
||||
"400":
|
||||
@@ -2428,6 +2446,9 @@ paths:
|
||||
$ref: '#/components/schemas/DashboardtypesGettablePublicDasbhboard'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -2482,6 +2503,9 @@ paths:
|
||||
$ref: '#/components/schemas/TypesIdentifiable'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: Created
|
||||
"401":
|
||||
@@ -2575,6 +2599,9 @@ paths:
|
||||
type: array
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -2622,6 +2649,9 @@ paths:
|
||||
$ref: '#/components/schemas/AuthtypesGettableAuthDomain'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"400":
|
||||
@@ -2818,6 +2848,9 @@ paths:
|
||||
$ref: '#/components/schemas/TelemetrytypesGettableFieldKeys'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -2908,6 +2941,9 @@ paths:
|
||||
$ref: '#/components/schemas/TelemetrytypesGettableFieldValues'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -2957,6 +2993,9 @@ paths:
|
||||
$ref: '#/components/schemas/TypesResetPasswordToken'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"400":
|
||||
@@ -3012,6 +3051,9 @@ paths:
|
||||
$ref: '#/components/schemas/TypesGettableGlobalConfig'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -3057,6 +3099,9 @@ paths:
|
||||
type: array
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -3104,6 +3149,9 @@ paths:
|
||||
$ref: '#/components/schemas/TypesInvite'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: Created
|
||||
"400":
|
||||
@@ -3217,6 +3265,9 @@ paths:
|
||||
$ref: '#/components/schemas/TypesInvite'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"400":
|
||||
@@ -3260,6 +3311,9 @@ paths:
|
||||
$ref: '#/components/schemas/TypesUser'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: Created
|
||||
"400":
|
||||
@@ -3354,6 +3408,9 @@ paths:
|
||||
type: array
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"400":
|
||||
@@ -3452,6 +3509,9 @@ paths:
|
||||
type: array
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -3501,6 +3561,9 @@ paths:
|
||||
$ref: '#/components/schemas/PreferencetypesPreference'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"400":
|
||||
@@ -3614,6 +3677,9 @@ paths:
|
||||
type: array
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -3661,6 +3727,9 @@ paths:
|
||||
$ref: '#/components/schemas/TypesGettableAPIKey'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: Created
|
||||
"400":
|
||||
@@ -3828,6 +3897,9 @@ paths:
|
||||
$ref: '#/components/schemas/DashboardtypesGettablePublicDashboardData'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -3881,6 +3953,9 @@ paths:
|
||||
$ref: '#/components/schemas/Querybuildertypesv5QueryRangeResponse'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -3958,6 +4033,9 @@ paths:
|
||||
type: array
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -4005,6 +4083,9 @@ paths:
|
||||
$ref: '#/components/schemas/TypesIdentifiable'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: Created
|
||||
"400":
|
||||
@@ -4139,6 +4220,9 @@ paths:
|
||||
$ref: '#/components/schemas/RoletypesRole'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -4262,6 +4346,9 @@ paths:
|
||||
type: array
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -4401,6 +4488,9 @@ paths:
|
||||
$ref: '#/components/schemas/RoletypesGettableResources'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -4446,6 +4536,9 @@ paths:
|
||||
type: array
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -4540,6 +4633,9 @@ paths:
|
||||
$ref: '#/components/schemas/TypesUser'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -4599,6 +4695,9 @@ paths:
|
||||
$ref: '#/components/schemas/TypesUser'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"400":
|
||||
@@ -4654,6 +4753,9 @@ paths:
|
||||
$ref: '#/components/schemas/TypesUser'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -4696,6 +4798,9 @@ paths:
|
||||
type: array
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -4745,6 +4850,9 @@ paths:
|
||||
$ref: '#/components/schemas/PreferencetypesPreference'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -4887,6 +4995,9 @@ paths:
|
||||
type: array
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -4939,6 +5050,9 @@ paths:
|
||||
$ref: '#/components/schemas/GatewaytypesGettableIngestionKeys'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -4986,6 +5100,9 @@ paths:
|
||||
$ref: '#/components/schemas/GatewaytypesGettableCreatedIngestionKey'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -5124,6 +5241,9 @@ paths:
|
||||
$ref: '#/components/schemas/GatewaytypesGettableCreatedIngestionKeyLimit'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: Created
|
||||
"401":
|
||||
@@ -5265,6 +5385,9 @@ paths:
|
||||
$ref: '#/components/schemas/GatewaytypesGettableIngestionKeys'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -5328,6 +5451,9 @@ paths:
|
||||
$ref: '#/components/schemas/MetricsexplorertypesListMetricsResponse'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"400":
|
||||
@@ -5383,6 +5509,9 @@ paths:
|
||||
$ref: '#/components/schemas/MetricsexplorertypesMetricAlertsResponse'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"400":
|
||||
@@ -5449,6 +5578,9 @@ paths:
|
||||
$ref: '#/components/schemas/MetricsexplorertypesMetricAttributesResponse'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"400":
|
||||
@@ -5504,6 +5636,9 @@ paths:
|
||||
$ref: '#/components/schemas/MetricsexplorertypesMetricDashboardsResponse'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"400":
|
||||
@@ -5560,6 +5695,9 @@ paths:
|
||||
$ref: '#/components/schemas/MetricsexplorertypesMetricHighlightsResponse'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"400":
|
||||
@@ -5616,6 +5754,9 @@ paths:
|
||||
$ref: '#/components/schemas/MetricsexplorertypesMetricMetadata'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"400":
|
||||
@@ -5732,6 +5873,9 @@ paths:
|
||||
$ref: '#/components/schemas/MetricsexplorertypesStatsResponse'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"400":
|
||||
@@ -5787,6 +5931,9 @@ paths:
|
||||
$ref: '#/components/schemas/MetricsexplorertypesTreemapResponse'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"400":
|
||||
@@ -5836,6 +5983,9 @@ paths:
|
||||
$ref: '#/components/schemas/TypesOrganization'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
@@ -5966,6 +6116,9 @@ paths:
|
||||
$ref: '#/components/schemas/AuthtypesSessionContext'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"400":
|
||||
@@ -6003,6 +6156,9 @@ paths:
|
||||
$ref: '#/components/schemas/AuthtypesGettableToken'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"400":
|
||||
@@ -6046,6 +6202,9 @@ paths:
|
||||
$ref: '#/components/schemas/AuthtypesGettableToken'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"400":
|
||||
@@ -6078,6 +6237,9 @@ paths:
|
||||
$ref: '#/components/schemas/ZeustypesGettableHost'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"400":
|
||||
@@ -6592,6 +6754,9 @@ paths:
|
||||
$ref: '#/components/schemas/Querybuildertypesv5QueryRangeResponse'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"400":
|
||||
@@ -6646,6 +6811,9 @@ paths:
|
||||
$ref: '#/components/schemas/Querybuildertypesv5QueryRangeRequest'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"400":
|
||||
|
||||
@@ -436,7 +436,7 @@ export interface ErrorsJSONDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
code?: string;
|
||||
code: string;
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
@@ -444,7 +444,7 @@ export interface ErrorsJSONDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
message?: string;
|
||||
message: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
@@ -1985,11 +1985,11 @@ export enum Querybuildertypesv5VariableTypeDTO {
|
||||
text = 'text',
|
||||
}
|
||||
export interface RenderErrorResponseDTO {
|
||||
error?: ErrorsJSONDTO;
|
||||
error: ErrorsJSONDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2599,30 +2599,30 @@ export type AuthzCheck200 = {
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
data?: AuthtypesGettableTransactionDTO[];
|
||||
data: AuthtypesGettableTransactionDTO[];
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type ChangePasswordPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type CreateSessionByGoogleCallback303 = {
|
||||
data?: AuthtypesGettableTokenDTO;
|
||||
data: AuthtypesGettableTokenDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type CreateSessionByOIDCCallback303 = {
|
||||
data?: AuthtypesGettableTokenDTO;
|
||||
data: AuthtypesGettableTokenDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type CreateSessionBySAMLCallbackParams = {
|
||||
@@ -2650,11 +2650,11 @@ export type CreateSessionBySAMLCallbackBody = {
|
||||
};
|
||||
|
||||
export type CreateSessionBySAMLCallback303 = {
|
||||
data?: AuthtypesGettableTokenDTO;
|
||||
data: AuthtypesGettableTokenDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type DeletePublicDashboardPathParameters = {
|
||||
@@ -2664,22 +2664,22 @@ export type GetPublicDashboardPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type GetPublicDashboard200 = {
|
||||
data?: DashboardtypesGettablePublicDasbhboardDTO;
|
||||
data: DashboardtypesGettablePublicDasbhboardDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type CreatePublicDashboardPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type CreatePublicDashboard201 = {
|
||||
data?: TypesIdentifiableDTO;
|
||||
data: TypesIdentifiableDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type UpdatePublicDashboardPathParameters = {
|
||||
@@ -2689,19 +2689,19 @@ export type ListAuthDomains200 = {
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
data?: AuthtypesGettableAuthDomainDTO[];
|
||||
data: AuthtypesGettableAuthDomainDTO[];
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type CreateAuthDomain200 = {
|
||||
data?: AuthtypesGettableAuthDomainDTO;
|
||||
data: AuthtypesGettableAuthDomainDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type DeleteAuthDomainPathParameters = {
|
||||
@@ -2757,11 +2757,11 @@ export type GetFieldsKeysParams = {
|
||||
};
|
||||
|
||||
export type GetFieldsKeys200 = {
|
||||
data?: TelemetrytypesGettableFieldKeysDTO;
|
||||
data: TelemetrytypesGettableFieldKeysDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetFieldsValuesParams = {
|
||||
@@ -2821,49 +2821,49 @@ export type GetFieldsValuesParams = {
|
||||
};
|
||||
|
||||
export type GetFieldsValues200 = {
|
||||
data?: TelemetrytypesGettableFieldValuesDTO;
|
||||
data: TelemetrytypesGettableFieldValuesDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetResetPasswordTokenPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type GetResetPasswordToken200 = {
|
||||
data?: TypesResetPasswordTokenDTO;
|
||||
data: TypesResetPasswordTokenDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetGlobalConfig200 = {
|
||||
data?: TypesGettableGlobalConfigDTO;
|
||||
data: TypesGettableGlobalConfigDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type ListInvite200 = {
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
data?: TypesInviteDTO[];
|
||||
data: TypesInviteDTO[];
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type CreateInvite201 = {
|
||||
data?: TypesInviteDTO;
|
||||
data: TypesInviteDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type DeleteInvitePathParameters = {
|
||||
@@ -2873,19 +2873,19 @@ export type GetInvitePathParameters = {
|
||||
token: string;
|
||||
};
|
||||
export type GetInvite200 = {
|
||||
data?: TypesInviteDTO;
|
||||
data: TypesInviteDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type AcceptInvite201 = {
|
||||
data?: TypesUserDTO;
|
||||
data: TypesUserDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type ListPromotedAndIndexedPaths200 = {
|
||||
@@ -2893,33 +2893,33 @@ export type ListPromotedAndIndexedPaths200 = {
|
||||
* @type array
|
||||
* @nullable true
|
||||
*/
|
||||
data?: PromotetypesPromotePathDTO[] | null;
|
||||
data: PromotetypesPromotePathDTO[] | null;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type ListOrgPreferences200 = {
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
data?: PreferencetypesPreferenceDTO[];
|
||||
data: PreferencetypesPreferenceDTO[];
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetOrgPreferencePathParameters = {
|
||||
name: string;
|
||||
};
|
||||
export type GetOrgPreference200 = {
|
||||
data?: PreferencetypesPreferenceDTO;
|
||||
data: PreferencetypesPreferenceDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type UpdateOrgPreferencePathParameters = {
|
||||
@@ -2929,19 +2929,19 @@ export type ListAPIKeys200 = {
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
data?: TypesGettableAPIKeyDTO[];
|
||||
data: TypesGettableAPIKeyDTO[];
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type CreateAPIKey201 = {
|
||||
data?: TypesGettableAPIKeyDTO;
|
||||
data: TypesGettableAPIKeyDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type RevokeAPIKeyPathParameters = {
|
||||
@@ -2954,11 +2954,11 @@ export type GetPublicDashboardDataPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type GetPublicDashboardData200 = {
|
||||
data?: DashboardtypesGettablePublicDashboardDataDTO;
|
||||
data: DashboardtypesGettablePublicDashboardDataDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetPublicDashboardWidgetQueryRangePathParameters = {
|
||||
@@ -2966,30 +2966,30 @@ export type GetPublicDashboardWidgetQueryRangePathParameters = {
|
||||
idx: string;
|
||||
};
|
||||
export type GetPublicDashboardWidgetQueryRange200 = {
|
||||
data?: Querybuildertypesv5QueryRangeResponseDTO;
|
||||
data: Querybuildertypesv5QueryRangeResponseDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type ListRoles200 = {
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
data?: RoletypesRoleDTO[];
|
||||
data: RoletypesRoleDTO[];
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type CreateRole201 = {
|
||||
data?: TypesIdentifiableDTO;
|
||||
data: TypesIdentifiableDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type DeleteRolePathParameters = {
|
||||
@@ -2999,11 +2999,11 @@ export type GetRolePathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type GetRole200 = {
|
||||
data?: RoletypesRoleDTO;
|
||||
data: RoletypesRoleDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type PatchRolePathParameters = {
|
||||
@@ -3017,11 +3017,11 @@ export type GetObjects200 = {
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
data?: AuthtypesObjectDTO[];
|
||||
data: AuthtypesObjectDTO[];
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type PatchObjectsPathParameters = {
|
||||
@@ -3029,22 +3029,22 @@ export type PatchObjectsPathParameters = {
|
||||
relation: string;
|
||||
};
|
||||
export type GetResources200 = {
|
||||
data?: RoletypesGettableResourcesDTO;
|
||||
data: RoletypesGettableResourcesDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type ListUsers200 = {
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
data?: TypesUserDTO[];
|
||||
data: TypesUserDTO[];
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type DeleteUserPathParameters = {
|
||||
@@ -3054,52 +3054,52 @@ export type GetUserPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type GetUser200 = {
|
||||
data?: TypesUserDTO;
|
||||
data: TypesUserDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type UpdateUserPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
export type UpdateUser200 = {
|
||||
data?: TypesUserDTO;
|
||||
data: TypesUserDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetMyUser200 = {
|
||||
data?: TypesUserDTO;
|
||||
data: TypesUserDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type ListUserPreferences200 = {
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
data?: PreferencetypesPreferenceDTO[];
|
||||
data: PreferencetypesPreferenceDTO[];
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetUserPreferencePathParameters = {
|
||||
name: string;
|
||||
};
|
||||
export type GetUserPreference200 = {
|
||||
data?: PreferencetypesPreferenceDTO;
|
||||
data: PreferencetypesPreferenceDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type UpdateUserPreferencePathParameters = {
|
||||
@@ -3109,11 +3109,11 @@ export type GetFeatures200 = {
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
data?: FeaturetypesGettableFeatureDTO[];
|
||||
data: FeaturetypesGettableFeatureDTO[];
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetIngestionKeysParams = {
|
||||
@@ -3130,19 +3130,19 @@ export type GetIngestionKeysParams = {
|
||||
};
|
||||
|
||||
export type GetIngestionKeys200 = {
|
||||
data?: GatewaytypesGettableIngestionKeysDTO;
|
||||
data: GatewaytypesGettableIngestionKeysDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type CreateIngestionKey200 = {
|
||||
data?: GatewaytypesGettableCreatedIngestionKeyDTO;
|
||||
data: GatewaytypesGettableCreatedIngestionKeyDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type DeleteIngestionKeyPathParameters = {
|
||||
@@ -3155,11 +3155,11 @@ export type CreateIngestionKeyLimitPathParameters = {
|
||||
keyId: string;
|
||||
};
|
||||
export type CreateIngestionKeyLimit201 = {
|
||||
data?: GatewaytypesGettableCreatedIngestionKeyLimitDTO;
|
||||
data: GatewaytypesGettableCreatedIngestionKeyLimitDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type DeleteIngestionKeyLimitPathParameters = {
|
||||
@@ -3187,11 +3187,11 @@ export type SearchIngestionKeysParams = {
|
||||
};
|
||||
|
||||
export type SearchIngestionKeys200 = {
|
||||
data?: GatewaytypesGettableIngestionKeysDTO;
|
||||
data: GatewaytypesGettableIngestionKeysDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type ListMetricsParams = {
|
||||
@@ -3220,22 +3220,22 @@ export type ListMetricsParams = {
|
||||
};
|
||||
|
||||
export type ListMetrics200 = {
|
||||
data?: MetricsexplorertypesListMetricsResponseDTO;
|
||||
data: MetricsexplorertypesListMetricsResponseDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetMetricAlertsPathParameters = {
|
||||
metricName: string;
|
||||
};
|
||||
export type GetMetricAlerts200 = {
|
||||
data?: MetricsexplorertypesMetricAlertsResponseDTO;
|
||||
data: MetricsexplorertypesMetricAlertsResponseDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetMetricAttributesPathParameters = {
|
||||
@@ -3257,117 +3257,117 @@ export type GetMetricAttributesParams = {
|
||||
};
|
||||
|
||||
export type GetMetricAttributes200 = {
|
||||
data?: MetricsexplorertypesMetricAttributesResponseDTO;
|
||||
data: MetricsexplorertypesMetricAttributesResponseDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetMetricDashboardsPathParameters = {
|
||||
metricName: string;
|
||||
};
|
||||
export type GetMetricDashboards200 = {
|
||||
data?: MetricsexplorertypesMetricDashboardsResponseDTO;
|
||||
data: MetricsexplorertypesMetricDashboardsResponseDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetMetricHighlightsPathParameters = {
|
||||
metricName: string;
|
||||
};
|
||||
export type GetMetricHighlights200 = {
|
||||
data?: MetricsexplorertypesMetricHighlightsResponseDTO;
|
||||
data: MetricsexplorertypesMetricHighlightsResponseDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetMetricMetadataPathParameters = {
|
||||
metricName: string;
|
||||
};
|
||||
export type GetMetricMetadata200 = {
|
||||
data?: MetricsexplorertypesMetricMetadataDTO;
|
||||
data: MetricsexplorertypesMetricMetadataDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type UpdateMetricMetadataPathParameters = {
|
||||
metricName: string;
|
||||
};
|
||||
export type GetMetricsStats200 = {
|
||||
data?: MetricsexplorertypesStatsResponseDTO;
|
||||
data: MetricsexplorertypesStatsResponseDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetMetricsTreemap200 = {
|
||||
data?: MetricsexplorertypesTreemapResponseDTO;
|
||||
data: MetricsexplorertypesTreemapResponseDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetMyOrganization200 = {
|
||||
data?: TypesOrganizationDTO;
|
||||
data: TypesOrganizationDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetSessionContext200 = {
|
||||
data?: AuthtypesSessionContextDTO;
|
||||
data: AuthtypesSessionContextDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type CreateSessionByEmailPassword200 = {
|
||||
data?: AuthtypesGettableTokenDTO;
|
||||
data: AuthtypesGettableTokenDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type RotateSession200 = {
|
||||
data?: AuthtypesGettableTokenDTO;
|
||||
data: AuthtypesGettableTokenDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type GetHosts200 = {
|
||||
data?: ZeustypesGettableHostDTO;
|
||||
data: ZeustypesGettableHostDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type QueryRangeV5200 = {
|
||||
data?: Querybuildertypesv5QueryRangeResponseDTO;
|
||||
data: Querybuildertypesv5QueryRangeResponseDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type ReplaceVariables200 = {
|
||||
data?: Querybuildertypesv5QueryRangeRequestDTO;
|
||||
data: Querybuildertypesv5QueryRangeRequestDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status?: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
@@ -40,6 +40,7 @@ function ValueGraph({
|
||||
value,
|
||||
rawValue,
|
||||
thresholds,
|
||||
yAxisUnit,
|
||||
}: ValueGraphProps): JSX.Element {
|
||||
const { t } = useTranslation(['valueGraph']);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
@@ -87,7 +88,7 @@ function ValueGraph({
|
||||
const {
|
||||
threshold,
|
||||
isConflictingThresholds,
|
||||
} = getBackgroundColorAndThresholdCheck(thresholds, rawValue);
|
||||
} = getBackgroundColorAndThresholdCheck(thresholds, rawValue, yAxisUnit);
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -155,6 +156,7 @@ interface ValueGraphProps {
|
||||
value: string;
|
||||
rawValue: number;
|
||||
thresholds: ThresholdProps[];
|
||||
yAxisUnit?: string;
|
||||
}
|
||||
|
||||
export default ValueGraph;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { getYAxisFormattedValue } from 'components/Graph/yAxisConfig';
|
||||
import { evaluateThresholdWithConvertedValue } from 'container/GridTableComponent/utils';
|
||||
import { ThresholdProps } from 'container/NewWidget/RightContainer/Threshold/types';
|
||||
|
||||
function compareThreshold(
|
||||
function doesValueSatisfyThreshold(
|
||||
rawValue: number,
|
||||
threshold: ThresholdProps,
|
||||
yAxisUnit?: string,
|
||||
): boolean {
|
||||
if (
|
||||
threshold.thresholdOperator === undefined ||
|
||||
@@ -11,31 +12,14 @@ function compareThreshold(
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
switch (threshold.thresholdOperator) {
|
||||
case '>':
|
||||
return rawValue > threshold.thresholdValue;
|
||||
case '>=':
|
||||
return rawValue >= threshold.thresholdValue;
|
||||
case '<':
|
||||
return rawValue < threshold.thresholdValue;
|
||||
case '<=':
|
||||
return rawValue <= threshold.thresholdValue;
|
||||
case '=':
|
||||
return rawValue === threshold.thresholdValue;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function extractNumbersFromString(inputString: string): number[] {
|
||||
const regex = /[+-]?\d+(\.\d+)?/g;
|
||||
const matches = inputString.match(regex);
|
||||
|
||||
if (matches) {
|
||||
return matches.map(Number);
|
||||
}
|
||||
|
||||
return [];
|
||||
return evaluateThresholdWithConvertedValue(
|
||||
rawValue,
|
||||
threshold.thresholdValue,
|
||||
threshold.thresholdOperator,
|
||||
threshold.thresholdUnit,
|
||||
yAxisUnit,
|
||||
);
|
||||
}
|
||||
|
||||
function getHighestPrecedenceThreshold(
|
||||
@@ -63,17 +47,13 @@ function getHighestPrecedenceThreshold(
|
||||
export function getBackgroundColorAndThresholdCheck(
|
||||
thresholds: ThresholdProps[],
|
||||
rawValue: number,
|
||||
yAxisUnit?: string,
|
||||
): {
|
||||
threshold: ThresholdProps;
|
||||
isConflictingThresholds: boolean;
|
||||
} {
|
||||
const matchingThresholds = thresholds.filter((threshold) =>
|
||||
compareThreshold(
|
||||
extractNumbersFromString(
|
||||
getYAxisFormattedValue(rawValue.toString(), threshold.thresholdUnit || ''),
|
||||
)[0],
|
||||
threshold,
|
||||
),
|
||||
doesValueSatisfyThreshold(rawValue, threshold, yAxisUnit),
|
||||
);
|
||||
|
||||
if (matchingThresholds.length === 0) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { UniversalYAxisUnit } from '../types';
|
||||
import { YAxisCategoryNames } from '../constants';
|
||||
import { UniversalYAxisUnit, YAxisCategory } from '../types';
|
||||
import {
|
||||
getUniversalNameFromMetricUnit,
|
||||
mapMetricUnitToUniversalUnit,
|
||||
@@ -41,29 +42,29 @@ describe('YAxisUnitSelector utils', () => {
|
||||
|
||||
describe('mergeCategories', () => {
|
||||
it('merges categories correctly', () => {
|
||||
const categories1 = [
|
||||
const categories1: YAxisCategory[] = [
|
||||
{
|
||||
name: 'Data',
|
||||
name: YAxisCategoryNames.Data,
|
||||
units: [
|
||||
{ name: 'bytes', id: UniversalYAxisUnit.BYTES },
|
||||
{ name: 'kilobytes', id: UniversalYAxisUnit.KILOBYTES },
|
||||
],
|
||||
},
|
||||
];
|
||||
const categories2 = [
|
||||
const categories2: YAxisCategory[] = [
|
||||
{
|
||||
name: 'Data',
|
||||
name: YAxisCategoryNames.Data,
|
||||
units: [{ name: 'bits', id: UniversalYAxisUnit.BITS }],
|
||||
},
|
||||
{
|
||||
name: 'Time',
|
||||
name: YAxisCategoryNames.Time,
|
||||
units: [{ name: 'seconds', id: UniversalYAxisUnit.SECONDS }],
|
||||
},
|
||||
];
|
||||
const mergedCategories = mergeCategories(categories1, categories2);
|
||||
expect(mergedCategories).toEqual([
|
||||
{
|
||||
name: 'Data',
|
||||
name: YAxisCategoryNames.Data,
|
||||
units: [
|
||||
{ name: 'bytes', id: UniversalYAxisUnit.BYTES },
|
||||
{ name: 'kilobytes', id: UniversalYAxisUnit.KILOBYTES },
|
||||
@@ -71,7 +72,7 @@ describe('YAxisUnitSelector utils', () => {
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Time',
|
||||
name: YAxisCategoryNames.Time,
|
||||
units: [{ name: 'seconds', id: UniversalYAxisUnit.SECONDS }],
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -1,5 +1,36 @@
|
||||
import { UnitFamilyConfig, UniversalYAxisUnit, YAxisUnit } from './types';
|
||||
|
||||
export enum YAxisCategoryNames {
|
||||
Time = 'Time',
|
||||
Data = 'Data',
|
||||
DataRate = 'Data Rate',
|
||||
Count = 'Count',
|
||||
Operations = 'Operations',
|
||||
Percentage = 'Percentage',
|
||||
Boolean = 'Boolean',
|
||||
None = 'None',
|
||||
HashRate = 'Hash Rate',
|
||||
Miscellaneous = 'Miscellaneous',
|
||||
Acceleration = 'Acceleration',
|
||||
Angular = 'Angular',
|
||||
Area = 'Area',
|
||||
Flops = 'FLOPs',
|
||||
Concentration = 'Concentration',
|
||||
Currency = 'Currency',
|
||||
Datetime = 'Datetime',
|
||||
PowerElectrical = 'Power/Electrical',
|
||||
Flow = 'Flow',
|
||||
Force = 'Force',
|
||||
Mass = 'Mass',
|
||||
Length = 'Length',
|
||||
Pressure = 'Pressure',
|
||||
Radiation = 'Radiation',
|
||||
RotationSpeed = 'Rotation Speed',
|
||||
Temperature = 'Temperature',
|
||||
Velocity = 'Velocity',
|
||||
Volume = 'Volume',
|
||||
}
|
||||
|
||||
// Mapping of universal y-axis units to their AWS, UCUM, and OpenMetrics equivalents (if available)
|
||||
export const UniversalYAxisUnitMappings: Partial<
|
||||
Record<UniversalYAxisUnit, Set<YAxisUnit> | null>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Y_AXIS_UNIT_NAMES } from './constants';
|
||||
import { YAxisCategoryNames } from './constants';
|
||||
import { UniversalYAxisUnit, YAxisCategory } from './types';
|
||||
|
||||
// Base categories for the universal y-axis units
|
||||
export const BASE_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
{
|
||||
name: 'Time',
|
||||
name: YAxisCategoryNames.Time,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.SECONDS],
|
||||
@@ -37,7 +38,7 @@ export const BASE_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Data',
|
||||
name: YAxisCategoryNames.Data,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.BYTES],
|
||||
@@ -154,7 +155,7 @@ export const BASE_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Data Rate',
|
||||
name: YAxisCategoryNames.DataRate,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.BYTES_SECOND],
|
||||
@@ -295,7 +296,7 @@ export const BASE_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Count',
|
||||
name: YAxisCategoryNames.Count,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.COUNT],
|
||||
@@ -312,7 +313,7 @@ export const BASE_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Operations',
|
||||
name: YAxisCategoryNames.Operations,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.OPS_SECOND],
|
||||
@@ -353,7 +354,7 @@ export const BASE_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Percentage',
|
||||
name: YAxisCategoryNames.Percentage,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.PERCENT],
|
||||
@@ -366,7 +367,7 @@ export const BASE_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Boolean',
|
||||
name: YAxisCategoryNames.Boolean,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.TRUE_FALSE],
|
||||
@@ -382,7 +383,7 @@ export const BASE_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
|
||||
export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
{
|
||||
name: 'Time',
|
||||
name: YAxisCategoryNames.Time,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.DURATION_MS],
|
||||
@@ -419,7 +420,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Data Rate',
|
||||
name: YAxisCategoryNames.DataRate,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.DATA_RATE_PACKETS_PER_SECOND],
|
||||
@@ -428,7 +429,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Boolean',
|
||||
name: YAxisCategoryNames.Boolean,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.ON_OFF],
|
||||
@@ -437,7 +438,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'None',
|
||||
name: YAxisCategoryNames.None,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.NONE],
|
||||
@@ -446,7 +447,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Hash Rate',
|
||||
name: YAxisCategoryNames.HashRate,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.HASH_RATE_HASHES_PER_SECOND],
|
||||
@@ -479,7 +480,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Miscellaneous',
|
||||
name: YAxisCategoryNames.Miscellaneous,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.MISC_STRING],
|
||||
@@ -520,7 +521,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Acceleration',
|
||||
name: YAxisCategoryNames.Acceleration,
|
||||
units: [
|
||||
{
|
||||
name:
|
||||
@@ -541,7 +542,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Angular',
|
||||
name: YAxisCategoryNames.Angular,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.ANGULAR_DEGREE],
|
||||
@@ -566,7 +567,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Area',
|
||||
name: YAxisCategoryNames.Area,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.AREA_SQUARE_METERS],
|
||||
@@ -583,7 +584,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'FLOPs',
|
||||
name: YAxisCategoryNames.Flops,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.FLOPS_FLOPS],
|
||||
@@ -620,7 +621,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Concentration',
|
||||
name: YAxisCategoryNames.Concentration,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.CONCENTRATION_PPM],
|
||||
@@ -677,7 +678,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Currency',
|
||||
name: YAxisCategoryNames.Currency,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.CURRENCY_USD],
|
||||
@@ -774,7 +775,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Datetime',
|
||||
name: YAxisCategoryNames.Datetime,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.DATETIME_ISO],
|
||||
@@ -811,7 +812,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Power/Electrical',
|
||||
name: YAxisCategoryNames.PowerElectrical,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.POWER_WATT],
|
||||
@@ -968,7 +969,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Flow',
|
||||
name: YAxisCategoryNames.Flow,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.FLOW_GALLONS_PER_MINUTE],
|
||||
@@ -1005,7 +1006,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Force',
|
||||
name: YAxisCategoryNames.Force,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.FORCE_NEWTON_METERS],
|
||||
@@ -1026,7 +1027,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Mass',
|
||||
name: YAxisCategoryNames.Mass,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.MASS_MILLIGRAM],
|
||||
@@ -1051,7 +1052,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Length',
|
||||
name: YAxisCategoryNames.Length,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.LENGTH_MILLIMETER],
|
||||
@@ -1080,7 +1081,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Pressure',
|
||||
name: YAxisCategoryNames.Pressure,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.PRESSURE_MILLIBAR],
|
||||
@@ -1117,7 +1118,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Radiation',
|
||||
name: YAxisCategoryNames.Radiation,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.RADIATION_BECQUEREL],
|
||||
@@ -1174,7 +1175,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Rotation Speed',
|
||||
name: YAxisCategoryNames.RotationSpeed,
|
||||
units: [
|
||||
{
|
||||
name:
|
||||
@@ -1200,7 +1201,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Temperature',
|
||||
name: YAxisCategoryNames.Temperature,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.TEMPERATURE_CELSIUS],
|
||||
@@ -1217,7 +1218,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Velocity',
|
||||
name: YAxisCategoryNames.Velocity,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.VELOCITY_METERS_PER_SECOND],
|
||||
@@ -1238,7 +1239,7 @@ export const ADDITIONAL_Y_AXIS_CATEGORIES: YAxisCategory[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Volume',
|
||||
name: YAxisCategoryNames.Volume,
|
||||
units: [
|
||||
{
|
||||
name: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.VOLUME_MILLILITER],
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { YAxisCategoryNames } from './constants';
|
||||
|
||||
export interface YAxisUnitSelectorProps {
|
||||
value: string | undefined;
|
||||
onChange: (value: UniversalYAxisUnit) => void;
|
||||
@@ -669,7 +671,7 @@ export interface UnitFamilyConfig {
|
||||
}
|
||||
|
||||
export interface YAxisCategory {
|
||||
name: string;
|
||||
name: YAxisCategoryNames;
|
||||
units: {
|
||||
name: string;
|
||||
id: UniversalYAxisUnit;
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
.chart-manager-series-label {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
color: inherit;
|
||||
text-align: left;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
&:disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.chart-manager-container {
|
||||
width: 100%;
|
||||
max-height: calc(40% - 40px);
|
||||
|
||||
@@ -1,24 +1,28 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { Button, Input } from 'antd';
|
||||
import { PrecisionOption, PrecisionOptionsEnum } from 'components/Graph/types';
|
||||
import { ResizeTable } from 'components/ResizeTable';
|
||||
import { getGraphManagerTableColumns } from 'container/GridCardLayout/GridCard/FullView/TableRender/GraphManagerColumns';
|
||||
import { ExtendedChartDataset } from 'container/GridCardLayout/GridCard/FullView/types';
|
||||
import { getDefaultTableDataSet } from 'container/GridCardLayout/GridCard/FullView/utils';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import { UPlotConfigBuilder } from 'lib/uPlotV2/config/UPlotConfigBuilder';
|
||||
import { usePlotContext } from 'lib/uPlotV2/context/PlotContext';
|
||||
import useLegendsSync from 'lib/uPlotV2/hooks/useLegendsSync';
|
||||
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
||||
|
||||
import { getChartManagerColumns } from './getChartMangerColumns';
|
||||
import { ExtendedChartDataset, getDefaultTableDataSet } from './utils';
|
||||
|
||||
import './ChartManager.styles.scss';
|
||||
|
||||
interface ChartManagerProps {
|
||||
config: UPlotConfigBuilder;
|
||||
alignedData: uPlot.AlignedData;
|
||||
yAxisUnit?: string;
|
||||
decimalPrecision?: PrecisionOption;
|
||||
onCancel?: () => void;
|
||||
}
|
||||
|
||||
const X_AXIS_INDEX = 0;
|
||||
|
||||
/**
|
||||
* ChartManager provides a tabular view to manage the visibility of
|
||||
* individual series on a uPlot chart.
|
||||
@@ -28,16 +32,12 @@ interface ChartManagerProps {
|
||||
* - filter series by label
|
||||
* - toggle individual series on/off
|
||||
* - persist the visibility configuration to local storage.
|
||||
*
|
||||
* @param config - `UPlotConfigBuilder` instance used to derive chart options.
|
||||
* @param alignedData - uPlot aligned data used to build the initial table dataset.
|
||||
* @param yAxisUnit - Optional unit label for Y-axis values shown in the table.
|
||||
* @param onCancel - Optional callback invoked when the user cancels the dialog.
|
||||
*/
|
||||
export default function ChartManager({
|
||||
config,
|
||||
alignedData,
|
||||
yAxisUnit,
|
||||
decimalPrecision = PrecisionOptionsEnum.TWO,
|
||||
onCancel,
|
||||
}: ChartManagerProps): JSX.Element {
|
||||
const { notifications } = useNotifications();
|
||||
@@ -53,8 +53,13 @@ export default function ChartManager({
|
||||
const { isDashboardLocked } = useDashboard();
|
||||
|
||||
const [tableDataSet, setTableDataSet] = useState<ExtendedChartDataset[]>(() =>
|
||||
getDefaultTableDataSet(config.getConfig() as uPlot.Options, alignedData),
|
||||
getDefaultTableDataSet(
|
||||
config.getConfig() as uPlot.Options,
|
||||
alignedData,
|
||||
decimalPrecision,
|
||||
),
|
||||
);
|
||||
const [filterValue, setFilterValue] = useState('');
|
||||
|
||||
const graphVisibilityState = useMemo(
|
||||
() =>
|
||||
@@ -67,46 +72,62 @@ export default function ChartManager({
|
||||
|
||||
useEffect(() => {
|
||||
setTableDataSet(
|
||||
getDefaultTableDataSet(config.getConfig() as uPlot.Options, alignedData),
|
||||
);
|
||||
}, [alignedData, config]);
|
||||
|
||||
const filterHandler = useCallback(
|
||||
(event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
const value = event.target.value.toString().toLowerCase();
|
||||
const updatedDataSet = tableDataSet.map((item) => {
|
||||
if (item.label?.toLocaleLowerCase().includes(value)) {
|
||||
return { ...item, show: true };
|
||||
}
|
||||
return { ...item, show: false };
|
||||
});
|
||||
setTableDataSet(updatedDataSet);
|
||||
},
|
||||
[tableDataSet],
|
||||
);
|
||||
|
||||
const dataSource = useMemo(
|
||||
() =>
|
||||
tableDataSet.filter(
|
||||
(item, index) => index !== 0 && item.show, // skipping the first item as it is the x-axis
|
||||
getDefaultTableDataSet(
|
||||
config.getConfig() as uPlot.Options,
|
||||
alignedData,
|
||||
decimalPrecision,
|
||||
),
|
||||
[tableDataSet],
|
||||
);
|
||||
setFilterValue('');
|
||||
}, [alignedData, config, decimalPrecision]);
|
||||
|
||||
const handleFilterChange = useCallback(
|
||||
(e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
setFilterValue(e.target.value.toLowerCase());
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const handleToggleSeriesOnOff = useCallback(
|
||||
(index: number): void => {
|
||||
onToggleSeriesOnOff(index);
|
||||
},
|
||||
[onToggleSeriesOnOff],
|
||||
);
|
||||
|
||||
const dataSource = useMemo(() => {
|
||||
const filter = filterValue.trim();
|
||||
return tableDataSet.filter((item, index) => {
|
||||
if (index === X_AXIS_INDEX) {
|
||||
return false;
|
||||
}
|
||||
if (!filter) {
|
||||
return true;
|
||||
}
|
||||
return item.label?.toLowerCase().includes(filter) ?? false;
|
||||
});
|
||||
}, [tableDataSet, filterValue]);
|
||||
|
||||
const columns = useMemo(
|
||||
() =>
|
||||
getGraphManagerTableColumns({
|
||||
getChartManagerColumns({
|
||||
tableDataSet,
|
||||
checkBoxOnChangeHandler: (_e, index) => {
|
||||
onToggleSeriesOnOff(index);
|
||||
},
|
||||
graphVisibilityState,
|
||||
labelClickedHandler: onToggleSeriesVisibility,
|
||||
onToggleSeriesOnOff: handleToggleSeriesOnOff,
|
||||
onToggleSeriesVisibility,
|
||||
yAxisUnit,
|
||||
isGraphDisabled: isDashboardLocked,
|
||||
decimalPrecision,
|
||||
}),
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[tableDataSet, graphVisibilityState, yAxisUnit, isDashboardLocked],
|
||||
[
|
||||
tableDataSet,
|
||||
graphVisibilityState,
|
||||
handleToggleSeriesOnOff,
|
||||
onToggleSeriesVisibility,
|
||||
yAxisUnit,
|
||||
isDashboardLocked,
|
||||
decimalPrecision,
|
||||
],
|
||||
);
|
||||
|
||||
const handleSave = useCallback((): void => {
|
||||
@@ -114,15 +135,18 @@ export default function ChartManager({
|
||||
notifications.success({
|
||||
message: 'The updated graphs & legends are saved',
|
||||
});
|
||||
if (onCancel) {
|
||||
onCancel();
|
||||
}
|
||||
onCancel?.();
|
||||
}, [syncSeriesVisibilityToLocalStorage, notifications, onCancel]);
|
||||
|
||||
return (
|
||||
<div className="chart-manager-container">
|
||||
<div className="chart-manager-header">
|
||||
<Input onChange={filterHandler} placeholder="Filter Series" />
|
||||
<Input
|
||||
placeholder="Filter Series"
|
||||
value={filterValue}
|
||||
onChange={handleFilterChange}
|
||||
data-testid="filter-input"
|
||||
/>
|
||||
<div className="chart-manager-actions-container">
|
||||
<Button type="default" onClick={onCancel}>
|
||||
Cancel
|
||||
@@ -136,10 +160,10 @@ export default function ChartManager({
|
||||
<ResizeTable
|
||||
columns={columns}
|
||||
dataSource={dataSource}
|
||||
virtual
|
||||
rowKey="index"
|
||||
scroll={{ y: 200 }}
|
||||
pagination={false}
|
||||
virtual
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { Tooltip } from 'antd';
|
||||
|
||||
import './ChartManager.styles.scss';
|
||||
|
||||
interface SeriesLabelProps {
|
||||
label: string;
|
||||
labelIndex: number;
|
||||
onClick: (idx: number) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export function SeriesLabel({
|
||||
label,
|
||||
labelIndex,
|
||||
onClick,
|
||||
disabled,
|
||||
}: SeriesLabelProps): JSX.Element {
|
||||
return (
|
||||
<Tooltip placement="topLeft" title={label}>
|
||||
<button
|
||||
className="chart-manager-series-label"
|
||||
disabled={disabled}
|
||||
type="button"
|
||||
data-testid={`series-label-button-${labelIndex}`}
|
||||
onClick={(): void => onClick(labelIndex)}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { UPlotConfigBuilder } from 'lib/uPlotV2/config/UPlotConfigBuilder';
|
||||
import { render, screen } from 'tests/test-utils';
|
||||
|
||||
import ChartManager from '../ChartManager';
|
||||
|
||||
const mockSyncSeriesVisibilityToLocalStorage = jest.fn();
|
||||
const mockNotificationsSuccess = jest.fn();
|
||||
|
||||
jest.mock('lib/uPlotV2/context/PlotContext', () => ({
|
||||
usePlotContext: (): {
|
||||
onToggleSeriesOnOff: jest.Mock;
|
||||
onToggleSeriesVisibility: jest.Mock;
|
||||
syncSeriesVisibilityToLocalStorage: jest.Mock;
|
||||
} => ({
|
||||
onToggleSeriesOnOff: jest.fn(),
|
||||
onToggleSeriesVisibility: jest.fn(),
|
||||
syncSeriesVisibilityToLocalStorage: mockSyncSeriesVisibilityToLocalStorage,
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('lib/uPlotV2/hooks/useLegendsSync', () => ({
|
||||
__esModule: true,
|
||||
default: (): {
|
||||
legendItemsMap: { [key: number]: { show: boolean; label: string } };
|
||||
} => ({
|
||||
legendItemsMap: {
|
||||
0: { show: true, label: 'Time' },
|
||||
1: { show: true, label: 'Series 1' },
|
||||
2: { show: true, label: 'Series 2' },
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('providers/Dashboard/Dashboard', () => ({
|
||||
useDashboard: (): { isDashboardLocked: boolean } => ({
|
||||
isDashboardLocked: false,
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('hooks/useNotifications', () => ({
|
||||
useNotifications: (): { notifications: { success: jest.Mock } } => ({
|
||||
notifications: {
|
||||
success: mockNotificationsSuccess,
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('components/ResizeTable', () => {
|
||||
const MockTable = ({
|
||||
dataSource,
|
||||
columns,
|
||||
}: {
|
||||
dataSource: { index: number; label?: string }[];
|
||||
columns: { key: string; title: string }[];
|
||||
}): JSX.Element => (
|
||||
<div data-testid="resize-table">
|
||||
{columns.map((col) => (
|
||||
<span key={col.key}>{col.title}</span>
|
||||
))}
|
||||
{dataSource.map((row) => (
|
||||
<div key={row.index} data-testid={`row-${row.index}`}>
|
||||
{row.label}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
return { ResizeTable: MockTable };
|
||||
});
|
||||
|
||||
const createMockConfig = (): { getConfig: () => uPlot.Options } => ({
|
||||
getConfig: (): uPlot.Options => ({
|
||||
width: 100,
|
||||
height: 100,
|
||||
series: [
|
||||
{ label: 'Time', value: 'time' },
|
||||
{ label: 'Series 1', scale: 'y' },
|
||||
{ label: 'Series 2', scale: 'y' },
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
const createAlignedData = (): uPlot.AlignedData => [
|
||||
[1000, 2000, 3000],
|
||||
[10, 20, 30],
|
||||
[1, 2, 3],
|
||||
];
|
||||
|
||||
describe('ChartManager', () => {
|
||||
const mockOnCancel = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('renders filter input and action buttons', () => {
|
||||
render(
|
||||
<ChartManager
|
||||
config={createMockConfig() as any}
|
||||
alignedData={createAlignedData()}
|
||||
onCancel={mockOnCancel}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByPlaceholderText('Filter Series')).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: /Cancel/ })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: /Save/ })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders ResizeTable with data', () => {
|
||||
render(
|
||||
<ChartManager
|
||||
config={createMockConfig() as UPlotConfigBuilder}
|
||||
alignedData={createAlignedData()}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByTestId('resize-table')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls onCancel when Cancel button is clicked', async () => {
|
||||
render(
|
||||
<ChartManager
|
||||
config={createMockConfig() as UPlotConfigBuilder}
|
||||
alignedData={createAlignedData()}
|
||||
onCancel={mockOnCancel}
|
||||
/>,
|
||||
);
|
||||
|
||||
await userEvent.click(screen.getByRole('button', { name: /Cancel/ }));
|
||||
|
||||
expect(mockOnCancel).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('filters table data when typing in filter input', async () => {
|
||||
render(
|
||||
<ChartManager
|
||||
config={createMockConfig() as UPlotConfigBuilder}
|
||||
alignedData={createAlignedData()}
|
||||
/>,
|
||||
);
|
||||
|
||||
// Before filter: both Series 1 and Series 2 rows are visible
|
||||
expect(screen.getByTestId('row-1')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('row-2')).toBeInTheDocument();
|
||||
|
||||
const filterInput = screen.getByTestId('filter-input');
|
||||
await userEvent.type(filterInput, 'Series 1');
|
||||
|
||||
// After filter: only Series 1 row is visible, Series 2 row is filtered out
|
||||
expect(screen.getByTestId('row-1')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('row-2')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls syncSeriesVisibilityToLocalStorage, notifications.success, and onCancel when Save is clicked', async () => {
|
||||
render(
|
||||
<ChartManager
|
||||
config={createMockConfig() as UPlotConfigBuilder}
|
||||
alignedData={createAlignedData()}
|
||||
onCancel={mockOnCancel}
|
||||
/>,
|
||||
);
|
||||
|
||||
await userEvent.click(screen.getByRole('button', { name: /Save/ }));
|
||||
|
||||
expect(mockSyncSeriesVisibilityToLocalStorage).toHaveBeenCalledTimes(1);
|
||||
expect(mockNotificationsSuccess).toHaveBeenCalledWith({
|
||||
message: 'The updated graphs & legends are saved',
|
||||
});
|
||||
expect(mockOnCancel).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { render, screen } from 'tests/test-utils';
|
||||
|
||||
import { SeriesLabel } from '../SeriesLabel';
|
||||
|
||||
describe('SeriesLabel', () => {
|
||||
it('renders the label text', () => {
|
||||
render(
|
||||
<SeriesLabel label="Test Series Label" labelIndex={1} onClick={jest.fn()} />,
|
||||
);
|
||||
expect(screen.getByTestId('series-label-button-1')).toHaveTextContent(
|
||||
'Test Series Label',
|
||||
);
|
||||
});
|
||||
|
||||
it('calls onClick with labelIndex when clicked', async () => {
|
||||
const onClick = jest.fn();
|
||||
render(<SeriesLabel label="Series A" labelIndex={2} onClick={onClick} />);
|
||||
|
||||
await userEvent.click(screen.getByTestId('series-label-button-2'));
|
||||
|
||||
expect(onClick).toHaveBeenCalledWith(2);
|
||||
expect(onClick).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('renders disabled button when disabled prop is true', () => {
|
||||
render(
|
||||
<SeriesLabel label="Disabled" labelIndex={0} onClick={jest.fn()} disabled />,
|
||||
);
|
||||
const button = screen.getByTestId('series-label-button-0');
|
||||
expect(button).toBeDisabled();
|
||||
});
|
||||
|
||||
it('has chart-manager-series-label class', () => {
|
||||
render(<SeriesLabel label="Label" labelIndex={0} onClick={jest.fn()} />);
|
||||
const button = screen.getByTestId('series-label-button-0');
|
||||
expect(button).toHaveClass('chart-manager-series-label');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,167 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { Y_AXIS_UNIT_NAMES } from 'components/YAxisUnitSelector/constants';
|
||||
import { UniversalYAxisUnit } from 'components/YAxisUnitSelector/types';
|
||||
|
||||
import { getChartManagerColumns } from '../getChartMangerColumns';
|
||||
import { ExtendedChartDataset } from '../utils';
|
||||
|
||||
const createMockDataset = (
|
||||
index: number,
|
||||
overrides: Partial<ExtendedChartDataset> = {},
|
||||
): ExtendedChartDataset =>
|
||||
({
|
||||
index,
|
||||
label: `Series ${index}`,
|
||||
show: true,
|
||||
sum: 100,
|
||||
avg: 50,
|
||||
min: 10,
|
||||
max: 90,
|
||||
stroke: '#ff0000',
|
||||
...overrides,
|
||||
} as ExtendedChartDataset);
|
||||
|
||||
describe('getChartManagerColumns', () => {
|
||||
const tableDataSet: ExtendedChartDataset[] = [
|
||||
createMockDataset(0, { label: 'Time' }),
|
||||
createMockDataset(1),
|
||||
createMockDataset(2),
|
||||
];
|
||||
const graphVisibilityState = [true, true, false];
|
||||
const onToggleSeriesOnOff = jest.fn();
|
||||
const onToggleSeriesVisibility = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('returns columns with expected structure', () => {
|
||||
const columns = getChartManagerColumns({
|
||||
tableDataSet,
|
||||
graphVisibilityState,
|
||||
onToggleSeriesOnOff,
|
||||
onToggleSeriesVisibility,
|
||||
});
|
||||
|
||||
expect(columns).toHaveLength(6);
|
||||
expect(columns[0].key).toBe('index');
|
||||
expect(columns[1].key).toBe('label');
|
||||
expect(columns[2].key).toBe('avg');
|
||||
expect(columns[3].key).toBe('sum');
|
||||
expect(columns[4].key).toBe('max');
|
||||
expect(columns[5].key).toBe('min');
|
||||
});
|
||||
|
||||
it('includes Label column with title', () => {
|
||||
const columns = getChartManagerColumns({
|
||||
tableDataSet,
|
||||
graphVisibilityState,
|
||||
onToggleSeriesOnOff,
|
||||
onToggleSeriesVisibility,
|
||||
});
|
||||
|
||||
const labelCol = columns.find((c) => c.key === 'label');
|
||||
expect(labelCol!.title).toBe('Label');
|
||||
});
|
||||
|
||||
it('formats column titles with yAxisUnit', () => {
|
||||
const columns = getChartManagerColumns({
|
||||
tableDataSet,
|
||||
graphVisibilityState,
|
||||
onToggleSeriesOnOff,
|
||||
onToggleSeriesVisibility,
|
||||
yAxisUnit: 'ms',
|
||||
});
|
||||
|
||||
const avgCol = columns.find((c) => c.key === 'avg');
|
||||
expect(avgCol!.title).toBe(
|
||||
`Avg (in ${Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.MILLISECONDS]})`,
|
||||
);
|
||||
});
|
||||
|
||||
it('numeric column render returns formatted string with yAxisUnit', () => {
|
||||
const columns = getChartManagerColumns({
|
||||
tableDataSet,
|
||||
graphVisibilityState,
|
||||
onToggleSeriesOnOff,
|
||||
onToggleSeriesVisibility,
|
||||
yAxisUnit: 'ms',
|
||||
});
|
||||
|
||||
const avgCol = columns.find((c) => c.key === 'avg');
|
||||
const renderFn = avgCol?.render as
|
||||
| ((val: number, record: ExtendedChartDataset, index: number) => string)
|
||||
| undefined;
|
||||
expect(renderFn).toBeDefined();
|
||||
const output = renderFn!(123.45, tableDataSet[1], 1);
|
||||
expect(output).toBe('123.45 ms');
|
||||
});
|
||||
|
||||
it('numeric column render formats zero when value is undefined', () => {
|
||||
const columns = getChartManagerColumns({
|
||||
tableDataSet,
|
||||
graphVisibilityState,
|
||||
onToggleSeriesOnOff,
|
||||
onToggleSeriesVisibility,
|
||||
yAxisUnit: 'none',
|
||||
});
|
||||
|
||||
const sumCol = columns.find((c) => c.key === 'sum');
|
||||
const renderFn = sumCol?.render as
|
||||
| ((
|
||||
val: number | undefined,
|
||||
record: ExtendedChartDataset,
|
||||
index: number,
|
||||
) => string)
|
||||
| undefined;
|
||||
const output = renderFn!(undefined, tableDataSet[1], 1);
|
||||
expect(output).toBe('0');
|
||||
});
|
||||
|
||||
it('label column render displays label text and is clickable', () => {
|
||||
const columns = getChartManagerColumns({
|
||||
tableDataSet,
|
||||
graphVisibilityState,
|
||||
onToggleSeriesOnOff,
|
||||
onToggleSeriesVisibility,
|
||||
});
|
||||
|
||||
const labelCol = columns.find((c) => c.key === 'label');
|
||||
const renderFn = labelCol!.render as
|
||||
| ((
|
||||
label: string,
|
||||
record: ExtendedChartDataset,
|
||||
index: number,
|
||||
) => JSX.Element)
|
||||
| undefined;
|
||||
expect(renderFn).toBeDefined();
|
||||
const renderResult = renderFn!('Series 1', tableDataSet[1], 1);
|
||||
|
||||
const { getByRole } = render(renderResult);
|
||||
expect(getByRole('button', { name: 'Series 1' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('index column render renders checkbox with correct checked state', () => {
|
||||
const columns = getChartManagerColumns({
|
||||
tableDataSet,
|
||||
graphVisibilityState,
|
||||
onToggleSeriesOnOff,
|
||||
onToggleSeriesVisibility,
|
||||
});
|
||||
|
||||
const indexCol = columns.find((c) => c.key === 'index');
|
||||
const renderFn = indexCol!.render as
|
||||
| ((
|
||||
_val: unknown,
|
||||
record: ExtendedChartDataset,
|
||||
index: number,
|
||||
) => JSX.Element)
|
||||
| undefined;
|
||||
expect(renderFn).toBeDefined();
|
||||
const { container } = render(renderFn!(null, tableDataSet[1], 1));
|
||||
|
||||
const checkbox = container.querySelector('input[type="checkbox"]');
|
||||
expect(checkbox).toBeInTheDocument();
|
||||
expect(checkbox).toBeChecked(); // graphVisibilityState[1] is true
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,113 @@
|
||||
import { PrecisionOptionsEnum } from 'components/Graph/types';
|
||||
|
||||
import {
|
||||
formatTableValueWithUnit,
|
||||
getDefaultTableDataSet,
|
||||
getTableColumnTitle,
|
||||
} from '../utils';
|
||||
|
||||
describe('ChartManager utils', () => {
|
||||
describe('getDefaultTableDataSet', () => {
|
||||
const createOptions = (seriesCount: number): uPlot.Options => ({
|
||||
series: Array.from({ length: seriesCount }, (_, i) =>
|
||||
i === 0
|
||||
? { label: 'Time', value: 'time' }
|
||||
: { label: `Series ${i}`, scale: 'y' },
|
||||
),
|
||||
width: 100,
|
||||
height: 100,
|
||||
});
|
||||
|
||||
it('returns one row per series with computed stats', () => {
|
||||
const options = createOptions(3);
|
||||
const data: uPlot.AlignedData = [
|
||||
[1000, 2000, 3000],
|
||||
[10, 20, 30],
|
||||
[1, 2, 3],
|
||||
];
|
||||
|
||||
const result = getDefaultTableDataSet(options, data);
|
||||
|
||||
expect(result).toHaveLength(3);
|
||||
expect(result[0]).toMatchObject({
|
||||
index: 0,
|
||||
label: 'Time',
|
||||
show: true,
|
||||
});
|
||||
expect(result[1]).toMatchObject({
|
||||
index: 1,
|
||||
label: 'Series 1',
|
||||
show: true,
|
||||
sum: 60,
|
||||
avg: 20,
|
||||
max: 30,
|
||||
min: 10,
|
||||
});
|
||||
expect(result[2]).toMatchObject({
|
||||
index: 2,
|
||||
label: 'Series 2',
|
||||
show: true,
|
||||
sum: 6,
|
||||
avg: 2,
|
||||
max: 3,
|
||||
min: 1,
|
||||
});
|
||||
});
|
||||
|
||||
it('handles empty data arrays', () => {
|
||||
const options = createOptions(2);
|
||||
const data: uPlot.AlignedData = [[], []];
|
||||
|
||||
const result = getDefaultTableDataSet(options, data);
|
||||
|
||||
expect(result[0]).toMatchObject({
|
||||
sum: 0,
|
||||
avg: 0,
|
||||
max: 0,
|
||||
min: 0,
|
||||
});
|
||||
});
|
||||
|
||||
it('respects decimalPrecision parameter', () => {
|
||||
const options = createOptions(2);
|
||||
const data: uPlot.AlignedData = [[1000], [123.454]];
|
||||
|
||||
const resultTwo = getDefaultTableDataSet(
|
||||
options,
|
||||
data,
|
||||
PrecisionOptionsEnum.TWO,
|
||||
);
|
||||
expect(resultTwo[1].avg).toBe(123.45);
|
||||
|
||||
const resultZero = getDefaultTableDataSet(
|
||||
options,
|
||||
data,
|
||||
PrecisionOptionsEnum.ZERO,
|
||||
);
|
||||
expect(resultZero[1].avg).toBe(123);
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatTableValueWithUnit', () => {
|
||||
it('formats value with unit', () => {
|
||||
const result = formatTableValueWithUnit(1234.56, 'ms');
|
||||
expect(result).toBe('1.23 s');
|
||||
});
|
||||
|
||||
it('falls back to none format when yAxisUnit is undefined', () => {
|
||||
const result = formatTableValueWithUnit(123.45);
|
||||
expect(result).toBe('123.45');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTableColumnTitle', () => {
|
||||
it('returns title only when yAxisUnit is undefined', () => {
|
||||
expect(getTableColumnTitle('Avg')).toBe('Avg');
|
||||
});
|
||||
|
||||
it('returns title with unit when yAxisUnit is provided', () => {
|
||||
const result = getTableColumnTitle('Avg', 'ms');
|
||||
expect(result).toBe('Avg (in Milliseconds (ms))');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,94 @@
|
||||
import { ColumnType } from 'antd/es/table';
|
||||
import { PrecisionOption, PrecisionOptionsEnum } from 'components/Graph/types';
|
||||
import CustomCheckBox from 'container/GridCardLayout/GridCard/FullView/TableRender/CustomCheckBox';
|
||||
|
||||
import { SeriesLabel } from './SeriesLabel';
|
||||
import {
|
||||
ExtendedChartDataset,
|
||||
formatTableValueWithUnit,
|
||||
getTableColumnTitle,
|
||||
} from './utils';
|
||||
|
||||
export interface GetChartManagerColumnsParams {
|
||||
tableDataSet: ExtendedChartDataset[];
|
||||
graphVisibilityState: boolean[];
|
||||
onToggleSeriesOnOff: (index: number) => void;
|
||||
onToggleSeriesVisibility: (index: number) => void;
|
||||
yAxisUnit?: string;
|
||||
decimalPrecision?: PrecisionOption;
|
||||
isGraphDisabled?: boolean;
|
||||
}
|
||||
|
||||
export function getChartManagerColumns({
|
||||
tableDataSet,
|
||||
graphVisibilityState,
|
||||
onToggleSeriesOnOff,
|
||||
onToggleSeriesVisibility,
|
||||
yAxisUnit,
|
||||
decimalPrecision = PrecisionOptionsEnum.TWO,
|
||||
isGraphDisabled,
|
||||
}: GetChartManagerColumnsParams): ColumnType<ExtendedChartDataset>[] {
|
||||
return [
|
||||
{
|
||||
title: '',
|
||||
width: 50,
|
||||
dataIndex: 'index',
|
||||
key: 'index',
|
||||
render: (_: unknown, record: ExtendedChartDataset): JSX.Element => (
|
||||
<CustomCheckBox
|
||||
data={tableDataSet}
|
||||
graphVisibilityState={graphVisibilityState}
|
||||
index={record.index}
|
||||
disabled={isGraphDisabled}
|
||||
checkBoxOnChangeHandler={(_e, idx): void => onToggleSeriesOnOff(idx)}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Label',
|
||||
width: 300,
|
||||
dataIndex: 'label',
|
||||
key: 'label',
|
||||
render: (label: string, record: ExtendedChartDataset): JSX.Element => (
|
||||
<SeriesLabel
|
||||
label={label ?? ''}
|
||||
labelIndex={record.index}
|
||||
disabled={isGraphDisabled}
|
||||
onClick={onToggleSeriesVisibility}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: getTableColumnTitle('Avg', yAxisUnit),
|
||||
width: 90,
|
||||
dataIndex: 'avg',
|
||||
key: 'avg',
|
||||
render: (val: number | undefined): string =>
|
||||
formatTableValueWithUnit(val ?? 0, yAxisUnit, decimalPrecision),
|
||||
},
|
||||
{
|
||||
title: getTableColumnTitle('Sum', yAxisUnit),
|
||||
width: 90,
|
||||
dataIndex: 'sum',
|
||||
key: 'sum',
|
||||
render: (val: number | undefined): string =>
|
||||
formatTableValueWithUnit(val ?? 0, yAxisUnit, decimalPrecision),
|
||||
},
|
||||
{
|
||||
title: getTableColumnTitle('Max', yAxisUnit),
|
||||
width: 90,
|
||||
dataIndex: 'max',
|
||||
key: 'max',
|
||||
render: (val: number | undefined): string =>
|
||||
formatTableValueWithUnit(val ?? 0, yAxisUnit, decimalPrecision),
|
||||
},
|
||||
{
|
||||
title: getTableColumnTitle('Min', yAxisUnit),
|
||||
width: 90,
|
||||
dataIndex: 'min',
|
||||
key: 'min',
|
||||
render: (val: number | undefined): string =>
|
||||
formatTableValueWithUnit(val ?? 0, yAxisUnit, decimalPrecision),
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import { PrecisionOption, PrecisionOptionsEnum } from 'components/Graph/types';
|
||||
import { getYAxisFormattedValue } from 'components/Graph/yAxisConfig';
|
||||
import { Y_AXIS_UNIT_NAMES } from 'components/YAxisUnitSelector/constants';
|
||||
import uPlot from 'uplot';
|
||||
|
||||
/** Extended series with computed stats for table display */
|
||||
export type ExtendedChartDataset = uPlot.Series & {
|
||||
show: boolean;
|
||||
sum: number;
|
||||
avg: number;
|
||||
min: number;
|
||||
max: number;
|
||||
index: number;
|
||||
};
|
||||
|
||||
function roundToDecimalPrecision(
|
||||
value: number,
|
||||
decimalPrecision: PrecisionOption = PrecisionOptionsEnum.TWO,
|
||||
): number {
|
||||
if (
|
||||
typeof value !== 'number' ||
|
||||
Number.isNaN(value) ||
|
||||
value === Infinity ||
|
||||
value === -Infinity
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (decimalPrecision === PrecisionOptionsEnum.FULL) {
|
||||
return value;
|
||||
}
|
||||
|
||||
// regex to match the decimal precision for the given decimal precision
|
||||
const regex = new RegExp(`^-?\\d*\\.?0*\\d{0,${decimalPrecision}}`);
|
||||
const matched = value ? value.toFixed(decimalPrecision).match(regex) : null;
|
||||
return matched ? parseFloat(matched[0]) : 0;
|
||||
}
|
||||
|
||||
/** Build table dataset from uPlot options and aligned data */
|
||||
export function getDefaultTableDataSet(
|
||||
options: uPlot.Options,
|
||||
data: uPlot.AlignedData,
|
||||
decimalPrecision: PrecisionOption = PrecisionOptionsEnum.TWO,
|
||||
): ExtendedChartDataset[] {
|
||||
return options.series.map(
|
||||
(series: uPlot.Series, index: number): ExtendedChartDataset => {
|
||||
const arr = (data[index] as number[]) ?? [];
|
||||
const sum = arr.reduce((a, b) => a + b, 0) || 0;
|
||||
const count = arr.length || 1;
|
||||
|
||||
const hasValues = arr.length > 0;
|
||||
return {
|
||||
...series,
|
||||
index,
|
||||
show: true,
|
||||
sum: roundToDecimalPrecision(sum, decimalPrecision),
|
||||
avg: roundToDecimalPrecision(sum / count, decimalPrecision),
|
||||
max: hasValues
|
||||
? roundToDecimalPrecision(Math.max(...arr), decimalPrecision)
|
||||
: 0,
|
||||
min: hasValues
|
||||
? roundToDecimalPrecision(Math.min(...arr), decimalPrecision)
|
||||
: 0,
|
||||
};
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/** Format numeric value for table display using yAxisUnit */
|
||||
export function formatTableValueWithUnit(
|
||||
value: number,
|
||||
yAxisUnit?: string,
|
||||
decimalPrecision: PrecisionOption = PrecisionOptionsEnum.TWO,
|
||||
): string {
|
||||
return `${getYAxisFormattedValue(
|
||||
String(value),
|
||||
yAxisUnit ?? 'none',
|
||||
decimalPrecision,
|
||||
)}`;
|
||||
}
|
||||
|
||||
/** Format column header with optional unit */
|
||||
export function getTableColumnTitle(title: string, yAxisUnit?: string): string {
|
||||
if (!yAxisUnit) {
|
||||
return title;
|
||||
}
|
||||
const universalName =
|
||||
Y_AXIS_UNIT_NAMES[yAxisUnit as keyof typeof Y_AXIS_UNIT_NAMES];
|
||||
if (!universalName) {
|
||||
return `${title} (in ${yAxisUnit})`;
|
||||
}
|
||||
return `${title} (in ${universalName})`;
|
||||
}
|
||||
@@ -96,6 +96,7 @@ function BarPanel(props: PanelWrapperProps): JSX.Element {
|
||||
config={config}
|
||||
alignedData={chartData}
|
||||
yAxisUnit={widget.yAxisUnit}
|
||||
decimalPrecision={widget.decimalPrecision}
|
||||
onCancel={onToggleModelHandler}
|
||||
/>
|
||||
);
|
||||
@@ -105,6 +106,7 @@ function BarPanel(props: PanelWrapperProps): JSX.Element {
|
||||
chartData,
|
||||
widget.yAxisUnit,
|
||||
onToggleModelHandler,
|
||||
widget.decimalPrecision,
|
||||
]);
|
||||
|
||||
const onPlotDestroy = useCallback(() => {
|
||||
|
||||
@@ -95,6 +95,7 @@ function TimeSeriesPanel(props: PanelWrapperProps): JSX.Element {
|
||||
config={config}
|
||||
alignedData={chartData}
|
||||
yAxisUnit={widget.yAxisUnit}
|
||||
decimalPrecision={widget.decimalPrecision}
|
||||
onCancel={onToggleModelHandler}
|
||||
/>
|
||||
);
|
||||
@@ -104,6 +105,7 @@ function TimeSeriesPanel(props: PanelWrapperProps): JSX.Element {
|
||||
chartData,
|
||||
widget.yAxisUnit,
|
||||
onToggleModelHandler,
|
||||
widget.decimalPrecision,
|
||||
]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -48,7 +48,9 @@ function ForgotPassword({
|
||||
}
|
||||
|
||||
try {
|
||||
ErrorResponseHandlerV2(mutationError as AxiosError<ErrorV2Resp>);
|
||||
ErrorResponseHandlerV2(
|
||||
(mutationError as unknown) as AxiosError<ErrorV2Resp>,
|
||||
);
|
||||
} catch (apiError) {
|
||||
return apiError as APIError;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ function evaluateCondition(
|
||||
* @param columnUnit - The current unit of the value.
|
||||
* @returns A boolean indicating whether the value meets the threshold condition.
|
||||
*/
|
||||
function evaluateThresholdWithConvertedValue(
|
||||
export function evaluateThresholdWithConvertedValue(
|
||||
value: number,
|
||||
thresholdValue: number,
|
||||
thresholdOperator?: string,
|
||||
|
||||
@@ -99,6 +99,7 @@ function GridValueComponent({
|
||||
<ValueGraph
|
||||
thresholds={thresholds || []}
|
||||
rawValue={value}
|
||||
yAxisUnit={yAxisUnit}
|
||||
value={
|
||||
yAxisUnit
|
||||
? getYAxisFormattedValue(
|
||||
|
||||
@@ -178,7 +178,9 @@ export default function HostsListTable({
|
||||
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
|
||||
}}
|
||||
tableLayout="fixed"
|
||||
rowKey={(record): string => record.hostName}
|
||||
rowKey={(record): string =>
|
||||
(record as HostRowData & { key: string }).key ?? record.hostName
|
||||
}
|
||||
onChange={handleTableChange}
|
||||
onRow={(record): { onClick: () => void; className: string } => ({
|
||||
onClick: (): void => handleRowClick(record),
|
||||
|
||||
@@ -126,7 +126,8 @@
|
||||
background: var(--bg-ink-500);
|
||||
}
|
||||
|
||||
.ant-table-cell:has(.hostname-column-value) {
|
||||
.ant-table-cell:has(.hostname-column-value),
|
||||
.ant-table-cell:has(.hostname-cell-missing) {
|
||||
background: var(--bg-ink-400);
|
||||
}
|
||||
|
||||
@@ -139,6 +140,23 @@
|
||||
letter-spacing: -0.07px;
|
||||
}
|
||||
|
||||
.hostname-cell-missing {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.hostname-cell-placeholder {
|
||||
color: var(--Vanilla-400, #c0c1c3);
|
||||
}
|
||||
|
||||
.hostname-cell-warning-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin-left: 4px;
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.status-cell {
|
||||
.active-tag {
|
||||
color: var(--bg-forest-500);
|
||||
@@ -357,7 +375,8 @@
|
||||
color: var(--bg-ink-500);
|
||||
}
|
||||
|
||||
.ant-table-cell:has(.hostname-column-value) {
|
||||
.ant-table-cell:has(.hostname-column-value),
|
||||
.ant-table-cell:has(.hostname-cell-missing) {
|
||||
background: var(--bg-vanilla-100);
|
||||
}
|
||||
|
||||
@@ -365,6 +384,10 @@
|
||||
color: var(--bg-ink-300);
|
||||
}
|
||||
|
||||
.hostname-cell-placeholder {
|
||||
color: var(--text-ink-300);
|
||||
}
|
||||
|
||||
.ant-table-tbody > tr:hover > td {
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,24 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { HostData, TimeSeries } from 'api/infraMonitoring/getHostLists';
|
||||
|
||||
import { formatDataForTable, GetHostsQuickFiltersConfig } from '../utils';
|
||||
import {
|
||||
formatDataForTable,
|
||||
GetHostsQuickFiltersConfig,
|
||||
HostnameCell,
|
||||
} from '../utils';
|
||||
|
||||
const PROGRESS_BAR_CLASS = '.progress-bar';
|
||||
|
||||
const emptyTimeSeries: TimeSeries = {
|
||||
labels: {},
|
||||
labelsArray: [],
|
||||
values: [],
|
||||
};
|
||||
|
||||
describe('InfraMonitoringHosts utils', () => {
|
||||
describe('formatDataForTable', () => {
|
||||
it('should format host data correctly', () => {
|
||||
const mockData = [
|
||||
const mockData: HostData[] = [
|
||||
{
|
||||
hostName: 'test-host',
|
||||
active: true,
|
||||
@@ -16,8 +27,12 @@ describe('InfraMonitoringHosts utils', () => {
|
||||
wait: 0.05,
|
||||
load15: 2.5,
|
||||
os: 'linux',
|
||||
cpuTimeSeries: emptyTimeSeries,
|
||||
memoryTimeSeries: emptyTimeSeries,
|
||||
waitTimeSeries: emptyTimeSeries,
|
||||
load15TimeSeries: emptyTimeSeries,
|
||||
},
|
||||
] as any;
|
||||
];
|
||||
|
||||
const result = formatDataForTable(mockData);
|
||||
|
||||
@@ -46,7 +61,7 @@ describe('InfraMonitoringHosts utils', () => {
|
||||
});
|
||||
|
||||
it('should handle inactive hosts', () => {
|
||||
const mockData = [
|
||||
const mockData: HostData[] = [
|
||||
{
|
||||
hostName: 'test-host',
|
||||
active: false,
|
||||
@@ -55,12 +70,12 @@ describe('InfraMonitoringHosts utils', () => {
|
||||
wait: 0.02,
|
||||
load15: 1.2,
|
||||
os: 'linux',
|
||||
cpuTimeSeries: [],
|
||||
memoryTimeSeries: [],
|
||||
waitTimeSeries: [],
|
||||
load15TimeSeries: [],
|
||||
cpuTimeSeries: emptyTimeSeries,
|
||||
memoryTimeSeries: emptyTimeSeries,
|
||||
waitTimeSeries: emptyTimeSeries,
|
||||
load15TimeSeries: emptyTimeSeries,
|
||||
},
|
||||
] as any;
|
||||
];
|
||||
|
||||
const result = formatDataForTable(mockData);
|
||||
|
||||
@@ -68,6 +83,65 @@ describe('InfraMonitoringHosts utils', () => {
|
||||
expect(inactiveTag.container.textContent).toBe('INACTIVE');
|
||||
expect(inactiveTag.container.querySelector('.inactive')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should set hostName to empty string when host has no hostname', () => {
|
||||
const mockData: HostData[] = [
|
||||
{
|
||||
hostName: '',
|
||||
active: true,
|
||||
cpu: 0.5,
|
||||
memory: 0.4,
|
||||
wait: 0.01,
|
||||
load15: 1.0,
|
||||
os: 'linux',
|
||||
cpuTimeSeries: emptyTimeSeries,
|
||||
memoryTimeSeries: emptyTimeSeries,
|
||||
waitTimeSeries: emptyTimeSeries,
|
||||
load15TimeSeries: emptyTimeSeries,
|
||||
},
|
||||
];
|
||||
|
||||
const result = formatDataForTable(mockData);
|
||||
expect(result[0].hostName).toBe('');
|
||||
expect(result[0].key).toBe('-0');
|
||||
});
|
||||
});
|
||||
|
||||
describe('HostnameCell', () => {
|
||||
it('should render hostname when present (case A: no icon)', () => {
|
||||
const { container } = render(<HostnameCell hostName="gke-prod-1" />);
|
||||
expect(container.querySelector('.hostname-column-value')).toBeTruthy();
|
||||
expect(container.textContent).toBe('gke-prod-1');
|
||||
expect(container.querySelector('.hostname-cell-missing')).toBeFalsy();
|
||||
expect(container.querySelector('.hostname-cell-warning-icon')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should render placeholder and icon when hostName is empty (case B)', () => {
|
||||
const { container } = render(<HostnameCell hostName="" />);
|
||||
expect(screen.getByText('-')).toBeTruthy();
|
||||
expect(container.querySelector('.hostname-cell-missing')).toBeTruthy();
|
||||
const iconWrapper = container.querySelector('.hostname-cell-warning-icon');
|
||||
expect(iconWrapper).toBeTruthy();
|
||||
expect(iconWrapper?.getAttribute('aria-label')).toBe(
|
||||
'Missing host.name metadata',
|
||||
);
|
||||
expect(iconWrapper?.getAttribute('tabindex')).toBe('0');
|
||||
// Tooltip with "Learn how to configure →" link is shown on hover/focus
|
||||
});
|
||||
|
||||
it('should render placeholder and icon when hostName is whitespace only (case C)', () => {
|
||||
const { container } = render(<HostnameCell hostName=" " />);
|
||||
expect(screen.getByText('-')).toBeTruthy();
|
||||
expect(container.querySelector('.hostname-cell-missing')).toBeTruthy();
|
||||
expect(container.querySelector('.hostname-cell-warning-icon')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should render placeholder and icon when hostName is undefined (case D)', () => {
|
||||
const { container } = render(<HostnameCell hostName={undefined} />);
|
||||
expect(screen.getByText('-')).toBeTruthy();
|
||||
expect(container.querySelector('.hostname-cell-missing')).toBeTruthy();
|
||||
expect(container.querySelector('.hostname-cell-warning-icon')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetHostsQuickFiltersConfig', () => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Dispatch, SetStateAction } from 'react';
|
||||
import { InfoCircleOutlined } from '@ant-design/icons';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Progress, TabsProps, Tag, Tooltip } from 'antd';
|
||||
import { Progress, TabsProps, Tag, Tooltip, Typography } from 'antd';
|
||||
import { ColumnType } from 'antd/es/table';
|
||||
import {
|
||||
HostData,
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
} from 'components/QuickFilters/types';
|
||||
import TabLabel from 'components/TabLabel';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { TriangleAlert } from 'lucide-react';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
|
||||
@@ -24,6 +25,7 @@ import HostsList from './HostsList';
|
||||
import './InfraMonitoring.styles.scss';
|
||||
|
||||
export interface HostRowData {
|
||||
key?: string;
|
||||
hostName: string;
|
||||
cpu: React.ReactNode;
|
||||
memory: React.ReactNode;
|
||||
@@ -32,6 +34,59 @@ export interface HostRowData {
|
||||
active: React.ReactNode;
|
||||
}
|
||||
|
||||
const HOSTNAME_DOCS_URL =
|
||||
'https://signoz.io/docs/infrastructure-monitoring/hostmetrics/#host-name-is-blankempty';
|
||||
|
||||
export function HostnameCell({
|
||||
hostName,
|
||||
}: {
|
||||
hostName?: string | null;
|
||||
}): React.ReactElement {
|
||||
const isEmpty = !hostName || !hostName.trim();
|
||||
if (!isEmpty) {
|
||||
return <div className="hostname-column-value">{hostName}</div>;
|
||||
}
|
||||
return (
|
||||
<div className="hostname-cell-missing">
|
||||
<Typography.Text type="secondary" className="hostname-cell-placeholder">
|
||||
-
|
||||
</Typography.Text>
|
||||
<Tooltip
|
||||
title={
|
||||
<div>
|
||||
Missing host.name metadata.
|
||||
<br />
|
||||
<a
|
||||
href={HOSTNAME_DOCS_URL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
onClick={(e): void => e.stopPropagation()}
|
||||
>
|
||||
Learn how to configure →
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
trigger={['hover', 'focus']}
|
||||
>
|
||||
<span
|
||||
className="hostname-cell-warning-icon"
|
||||
tabIndex={0}
|
||||
role="img"
|
||||
aria-label="Missing host.name metadata"
|
||||
onClick={(e): void => e.stopPropagation()}
|
||||
onKeyDown={(e): void => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.stopPropagation();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<TriangleAlert size={14} color={Color.BG_CHERRY_500} />
|
||||
</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export interface HostsListTableProps {
|
||||
isLoading: boolean;
|
||||
isError: boolean;
|
||||
@@ -75,8 +130,8 @@ export const getHostsListColumns = (): ColumnType<HostRowData>[] => [
|
||||
dataIndex: 'hostName',
|
||||
key: 'hostName',
|
||||
width: 250,
|
||||
render: (value: string): React.ReactNode => (
|
||||
<div className="hostname-column-value">{value}</div>
|
||||
render: (value: string | undefined): React.ReactNode => (
|
||||
<HostnameCell hostName={value ?? ''} />
|
||||
),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -342,7 +342,7 @@ function MultiIngestionSettings(): JSX.Element {
|
||||
|
||||
useEffect(() => {
|
||||
if (isError) {
|
||||
showErrorNotification(notifications, error as AxiosError);
|
||||
showErrorNotification(notifications, (error as unknown) as AxiosError);
|
||||
}
|
||||
}, [error, isError, notifications]);
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import { YAxisCategoryNames } from 'components/YAxisUnitSelector/constants';
|
||||
import { YAxisSource } from 'components/YAxisUnitSelector/types';
|
||||
import { getYAxisCategories } from 'components/YAxisUnitSelector/utils';
|
||||
import { convertValue } from 'lib/getConvertedValue';
|
||||
import { flattenDeep } from 'lodash-es';
|
||||
|
||||
import {
|
||||
@@ -439,131 +443,6 @@ export const flattenedCategories = flattenDeep(
|
||||
dataTypeCategories.map((category) => category.formats),
|
||||
);
|
||||
|
||||
type ConversionFactors = {
|
||||
[key: string]: {
|
||||
[key: string]: number | null;
|
||||
};
|
||||
};
|
||||
|
||||
// Object containing conversion factors for various categories and formats
|
||||
const conversionFactors: ConversionFactors = {
|
||||
[CategoryNames.Time]: {
|
||||
[TimeFormats.Hertz]: 1,
|
||||
[TimeFormats.Nanoseconds]: 1e-9,
|
||||
[TimeFormats.Microseconds]: 1e-6,
|
||||
[TimeFormats.Milliseconds]: 1e-3,
|
||||
[TimeFormats.Seconds]: 1,
|
||||
[TimeFormats.Minutes]: 60,
|
||||
[TimeFormats.Hours]: 3600,
|
||||
[TimeFormats.Days]: 86400,
|
||||
[TimeFormats.DurationMs]: 1e-3,
|
||||
[TimeFormats.DurationS]: 1,
|
||||
[TimeFormats.DurationHms]: null, // Requires special handling
|
||||
[TimeFormats.DurationDhms]: null, // Requires special handling
|
||||
[TimeFormats.Timeticks]: null, // Requires special handling
|
||||
[TimeFormats.ClockMs]: 1e-3,
|
||||
[TimeFormats.ClockS]: 1,
|
||||
},
|
||||
[CategoryNames.Throughput]: {
|
||||
[ThroughputFormats.CountsPerSec]: 1,
|
||||
[ThroughputFormats.OpsPerSec]: 1,
|
||||
[ThroughputFormats.RequestsPerSec]: 1,
|
||||
[ThroughputFormats.ReadsPerSec]: 1,
|
||||
[ThroughputFormats.WritesPerSec]: 1,
|
||||
[ThroughputFormats.IOOpsPerSec]: 1,
|
||||
[ThroughputFormats.CountsPerMin]: 1 / 60,
|
||||
[ThroughputFormats.OpsPerMin]: 1 / 60,
|
||||
[ThroughputFormats.ReadsPerMin]: 1 / 60,
|
||||
[ThroughputFormats.WritesPerMin]: 1 / 60,
|
||||
},
|
||||
[CategoryNames.Data]: {
|
||||
[DataFormats.BytesIEC]: 1,
|
||||
[DataFormats.BytesSI]: 1,
|
||||
[DataFormats.BitsIEC]: 0.125,
|
||||
[DataFormats.BitsSI]: 0.125,
|
||||
[DataFormats.KibiBytes]: 1024,
|
||||
[DataFormats.KiloBytes]: 1000,
|
||||
[DataFormats.MebiBytes]: 1048576,
|
||||
[DataFormats.MegaBytes]: 1000000,
|
||||
[DataFormats.GibiBytes]: 1073741824,
|
||||
[DataFormats.GigaBytes]: 1000000000,
|
||||
[DataFormats.TebiBytes]: 1099511627776,
|
||||
[DataFormats.TeraBytes]: 1000000000000,
|
||||
[DataFormats.PebiBytes]: 1125899906842624,
|
||||
[DataFormats.PetaBytes]: 1000000000000000,
|
||||
},
|
||||
[CategoryNames.DataRate]: {
|
||||
[DataRateFormats.PacketsPerSec]: null, // Cannot convert directly to other data rates
|
||||
[DataRateFormats.BytesPerSecIEC]: 1,
|
||||
[DataRateFormats.BytesPerSecSI]: 1,
|
||||
[DataRateFormats.BitsPerSecIEC]: 0.125,
|
||||
[DataRateFormats.BitsPerSecSI]: 0.125,
|
||||
[DataRateFormats.KibiBytesPerSec]: 1024,
|
||||
[DataRateFormats.KibiBitsPerSec]: 128,
|
||||
[DataRateFormats.KiloBytesPerSec]: 1000,
|
||||
[DataRateFormats.KiloBitsPerSec]: 125,
|
||||
[DataRateFormats.MebiBytesPerSec]: 1048576,
|
||||
[DataRateFormats.MebiBitsPerSec]: 131072,
|
||||
[DataRateFormats.MegaBytesPerSec]: 1000000,
|
||||
[DataRateFormats.MegaBitsPerSec]: 125000,
|
||||
[DataRateFormats.GibiBytesPerSec]: 1073741824,
|
||||
[DataRateFormats.GibiBitsPerSec]: 134217728,
|
||||
[DataRateFormats.GigaBytesPerSec]: 1000000000,
|
||||
[DataRateFormats.GigaBitsPerSec]: 125000000,
|
||||
[DataRateFormats.TebiBytesPerSec]: 1099511627776,
|
||||
[DataRateFormats.TebiBitsPerSec]: 137438953472,
|
||||
[DataRateFormats.TeraBytesPerSec]: 1000000000000,
|
||||
[DataRateFormats.TeraBitsPerSec]: 125000000000,
|
||||
[DataRateFormats.PebiBytesPerSec]: 1125899906842624,
|
||||
[DataRateFormats.PebiBitsPerSec]: 140737488355328,
|
||||
[DataRateFormats.PetaBytesPerSec]: 1000000000000000,
|
||||
[DataRateFormats.PetaBitsPerSec]: 125000000000000,
|
||||
},
|
||||
[CategoryNames.Miscellaneous]: {
|
||||
[MiscellaneousFormats.None]: null,
|
||||
[MiscellaneousFormats.String]: null,
|
||||
[MiscellaneousFormats.Short]: null,
|
||||
[MiscellaneousFormats.Percent]: 1,
|
||||
[MiscellaneousFormats.PercentUnit]: 100,
|
||||
[MiscellaneousFormats.Humidity]: 1,
|
||||
[MiscellaneousFormats.Decibel]: null,
|
||||
[MiscellaneousFormats.Hexadecimal0x]: null,
|
||||
[MiscellaneousFormats.Hexadecimal]: null,
|
||||
[MiscellaneousFormats.ScientificNotation]: null,
|
||||
[MiscellaneousFormats.LocaleFormat]: null,
|
||||
[MiscellaneousFormats.Pixels]: null,
|
||||
},
|
||||
[CategoryNames.Boolean]: {
|
||||
[BooleanFormats.TRUE_FALSE]: null, // Not convertible
|
||||
[BooleanFormats.YES_NO]: null, // Not convertible
|
||||
[BooleanFormats.ON_OFF]: null, // Not convertible
|
||||
},
|
||||
};
|
||||
|
||||
// Function to get the conversion factor between two units in a specific category
|
||||
function getConversionFactor(
|
||||
fromUnit: string,
|
||||
toUnit: string,
|
||||
category: CategoryNames,
|
||||
): number | null {
|
||||
// Retrieves the conversion factors for the specified category
|
||||
const categoryFactors = conversionFactors[category];
|
||||
if (!categoryFactors) {
|
||||
return null; // Returns null if the category does not exist
|
||||
}
|
||||
const fromFactor = categoryFactors[fromUnit];
|
||||
const toFactor = categoryFactors[toUnit];
|
||||
if (
|
||||
fromFactor === undefined ||
|
||||
toFactor === undefined ||
|
||||
fromFactor === null ||
|
||||
toFactor === null
|
||||
) {
|
||||
return null; // Returns null if either unit does not exist or is not convertible
|
||||
}
|
||||
return fromFactor / toFactor; // Returns the conversion factor ratio
|
||||
}
|
||||
|
||||
// Function to convert a value from one unit to another
|
||||
export function convertUnit(
|
||||
value: number,
|
||||
@@ -573,14 +452,16 @@ export function convertUnit(
|
||||
let fromUnit: string | undefined;
|
||||
let toUnit: string | undefined;
|
||||
|
||||
const categories = getYAxisCategories(YAxisSource.DASHBOARDS);
|
||||
|
||||
// Finds the category that contains the specified units and extracts fromUnit and toUnit using array methods
|
||||
const category = dataTypeCategories.find((category) =>
|
||||
category.formats.some((format) => {
|
||||
if (format.id === fromUnitId) {
|
||||
fromUnit = format.id;
|
||||
const category = categories.find((category) =>
|
||||
category.units.some((unit) => {
|
||||
if (unit.id === fromUnitId) {
|
||||
fromUnit = unit.id;
|
||||
}
|
||||
if (format.id === toUnitId) {
|
||||
toUnit = format.id;
|
||||
if (unit.id === toUnitId) {
|
||||
toUnit = unit.id;
|
||||
}
|
||||
return fromUnit && toUnit; // Break out early if both units are found
|
||||
}),
|
||||
@@ -590,24 +471,16 @@ export function convertUnit(
|
||||
return null;
|
||||
} // Return null if category or units are not found
|
||||
|
||||
// Gets the conversion factor for the specified units
|
||||
const conversionFactor = getConversionFactor(
|
||||
fromUnit,
|
||||
toUnit,
|
||||
category.name as any,
|
||||
);
|
||||
if (conversionFactor === null) {
|
||||
return null;
|
||||
} // Return null if conversion is not possible
|
||||
|
||||
return value * conversionFactor;
|
||||
// Convert the value from the fromUnit to the toUnit
|
||||
return convertValue(value, fromUnit, toUnit);
|
||||
}
|
||||
|
||||
// Function to get the category name for a given unit ID
|
||||
export const getCategoryName = (unitId: string): CategoryNames | null => {
|
||||
export const getCategoryName = (unitId: string): YAxisCategoryNames | null => {
|
||||
// Finds the category that contains the specified unit ID
|
||||
const foundCategory = dataTypeCategories.find((category) =>
|
||||
category.formats.some((format) => format.id === unitId),
|
||||
const categories = getYAxisCategories(YAxisSource.DASHBOARDS);
|
||||
const foundCategory = categories.find((category) =>
|
||||
category.units.some((unit) => unit.id === unitId),
|
||||
);
|
||||
return foundCategory ? (foundCategory.name as CategoryNames) : null;
|
||||
return foundCategory ? foundCategory.name : null;
|
||||
};
|
||||
|
||||
@@ -2,6 +2,9 @@ import { Layout } from 'react-grid-layout';
|
||||
import { DefaultOptionType } from 'antd/es/select';
|
||||
import { omitIdFromQuery } from 'components/ExplorerCard/utils';
|
||||
import { PrecisionOptionsEnum } from 'components/Graph/types';
|
||||
import { YAxisCategoryNames } from 'components/YAxisUnitSelector/constants';
|
||||
import { YAxisSource } from 'components/YAxisUnitSelector/types';
|
||||
import { getYAxisCategories } from 'components/YAxisUnitSelector/utils';
|
||||
import {
|
||||
initialQueryBuilderFormValuesMap,
|
||||
PANEL_TYPES,
|
||||
@@ -21,11 +24,7 @@ import { IBuilderQuery, Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import {
|
||||
dataTypeCategories,
|
||||
getCategoryName,
|
||||
} from './RightContainer/dataFormatCategories';
|
||||
import { CategoryNames } from './RightContainer/types';
|
||||
import { getCategoryName } from './RightContainer/dataFormatCategories';
|
||||
|
||||
export const getIsQueryModified = (
|
||||
currentQuery: Query,
|
||||
@@ -606,14 +605,21 @@ export const PANEL_TYPE_TO_QUERY_TYPES: Record<PANEL_TYPES, EQueryType[]> = {
|
||||
* the label and value for each format.
|
||||
*/
|
||||
export const getCategorySelectOptionByName = (
|
||||
name?: CategoryNames | string,
|
||||
): DefaultOptionType[] =>
|
||||
dataTypeCategories
|
||||
.find((category) => category.name === name)
|
||||
?.formats.map((format) => ({
|
||||
label: format.name,
|
||||
value: format.id,
|
||||
})) || [];
|
||||
name?: YAxisCategoryNames,
|
||||
): DefaultOptionType[] => {
|
||||
const categories = getYAxisCategories(YAxisSource.DASHBOARDS);
|
||||
if (!categories.length) {
|
||||
return [];
|
||||
}
|
||||
return (
|
||||
categories
|
||||
.find((category) => category.name === name)
|
||||
?.units.map((unit) => ({
|
||||
label: unit.name,
|
||||
value: unit.id,
|
||||
})) || []
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates unit options based on the provided column unit.
|
||||
|
||||
@@ -86,9 +86,9 @@ export default function OnboardingIngestionDetails(): JSX.Element {
|
||||
<div className="ingestion-endpoint-section-error-container">
|
||||
<Typography.Text className="ingestion-endpoint-section-error-text error">
|
||||
<TriangleAlert size={14} />{' '}
|
||||
{(error as AxiosError<RenderErrorResponseDTO>)?.response?.data?.error
|
||||
?.message ||
|
||||
(error as AxiosError)?.message ||
|
||||
{((error as unknown) as AxiosError<RenderErrorResponseDTO>)?.response
|
||||
?.data?.error.message ||
|
||||
((error as unknown) as AxiosError)?.message ||
|
||||
'Something went wrong'}
|
||||
</Typography.Text>
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ function AuthDomain(): JSX.Element {
|
||||
let errorResult: APIError | null = null;
|
||||
try {
|
||||
ErrorResponseHandlerV2(
|
||||
errorFetchingAuthDomainListResponse as AxiosError<ErrorV2Resp>,
|
||||
(errorFetchingAuthDomainListResponse as unknown) as AxiosError<ErrorV2Resp>,
|
||||
);
|
||||
} catch (error) {
|
||||
errorResult = error as APIError;
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { CategoryNames } from 'container/NewWidget/RightContainer/types';
|
||||
import { YAxisCategoryNames } from 'components/YAxisUnitSelector/constants';
|
||||
|
||||
export const categoryToSupport = [
|
||||
CategoryNames.Data,
|
||||
CategoryNames.DataRate,
|
||||
CategoryNames.Time,
|
||||
CategoryNames.Throughput,
|
||||
CategoryNames.Miscellaneous,
|
||||
CategoryNames.Boolean,
|
||||
export const categoryToSupport: YAxisCategoryNames[] = [
|
||||
YAxisCategoryNames.None,
|
||||
YAxisCategoryNames.Data,
|
||||
YAxisCategoryNames.DataRate,
|
||||
YAxisCategoryNames.Time,
|
||||
YAxisCategoryNames.Count,
|
||||
YAxisCategoryNames.Operations,
|
||||
YAxisCategoryNames.Percentage,
|
||||
YAxisCategoryNames.Miscellaneous,
|
||||
YAxisCategoryNames.Boolean,
|
||||
];
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
)
|
||||
|
||||
type JSON struct {
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Code string `json:"code" required:"true"`
|
||||
Message string `json:"message" required:"true"`
|
||||
Url string `json:"url,omitempty"`
|
||||
Errors []responseerroradditional `json:"errors,omitempty"`
|
||||
}
|
||||
|
||||
@@ -16,13 +16,13 @@ const (
|
||||
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
|
||||
type SuccessResponse struct {
|
||||
Status string `json:"status"`
|
||||
Data interface{} `json:"data,omitempty"`
|
||||
Status string `json:"status" required:"true"`
|
||||
Data interface{} `json:"data,omitempty" required:"true"`
|
||||
}
|
||||
|
||||
type ErrorResponse struct {
|
||||
Status string `json:"status"`
|
||||
Error *errors.JSON `json:"error"`
|
||||
Status string `json:"status" required:"true"`
|
||||
Error *errors.JSON `json:"error" required:"true"`
|
||||
}
|
||||
|
||||
func Success(rw http.ResponseWriter, httpCode int, data interface{}) {
|
||||
|
||||
Reference in New Issue
Block a user