Compare commits

..

23 Commits

Author SHA1 Message Date
nityanandagohain
dc63dc0b28 fix: integration with opamp spanmapping 2026-04-24 19:25:32 +05:30
nityanandagohain
fbb47f7fb9 Merge remote-tracking branch 'origin/main' into issue_4361 2026-04-24 11:46:32 +05:30
nityanandagohain
7aa69a3265 fix: use mustnewuuid 2026-04-24 00:16:29 +05:30
nityanandagohain
6de9ebfcac fix: address comments 2026-04-23 22:14:06 +05:30
nityanandagohain
85c7ce0680 fix: address comments 2026-04-23 18:46:32 +05:30
nityanandagohain
910cbf55cf Merge remote-tracking branch 'origin/main' into issue_4361 2026-04-23 16:24:32 +05:30
nityanandagohain
c30b3870f2 fix: address comments 2026-04-23 16:17:36 +05:30
nityanandagohain
a4da71eb52 fix: more changes 2026-04-22 14:05:56 +05:30
nityanandagohain
f5ed4c90b0 fix: address more comments 2026-04-22 13:54:27 +05:30
nityanandagohain
c03e97221a fix: address comments 2026-04-21 23:31:54 +05:30
nityanandagohain
cd224616f0 fix: address comments 2026-04-21 23:19:49 +05:30
nityanandagohain
50b42aca8c fix: lint issues 2026-04-20 16:09:50 +05:30
nityanandagohain
dbad6cff96 Merge remote-tracking branch 'origin/issue_4361' into issue_4361 2026-04-20 16:09:35 +05:30
nityanandagohain
73a44cee77 Merge remote-tracking branch 'origin/main' into issue_4361 2026-04-20 16:09:12 +05:30
nityanandagohain
b9b7c10af9 fix: remove lint issues 2026-04-20 16:09:09 +05:30
Nityananda Gohain
3d71707f0b Merge branch 'main' into issue_4361 2026-04-20 11:02:57 +05:30
nityanandagohain
f59f611ea2 fix: remove stutters 2026-04-20 11:00:38 +05:30
nityanandagohain
07131f10a9 fix: minor changes 2026-04-20 10:52:17 +05:30
nityanandagohain
d930e77870 fix: cleanup 2026-04-20 10:40:36 +05:30
nityanandagohain
8a9f6bee98 Merge remote-tracking branch 'origin/main' into issue_4361 2026-04-20 09:14:50 +05:30
nityanandagohain
4b06b4546f Merge remote-tracking branch 'origin/issue_4361' into issue_4361 2026-04-12 22:02:12 +05:30
nityanandagohain
526b08a179 feat: 1.types and handler for ai-o11y attribute mapping 2026-04-12 17:32:30 +05:30
nityanandagohain
c7ab610bd8 feat: 1.types and handler for ai-o11y attribute mapping 2026-04-12 17:31:40 +05:30
719 changed files with 12297 additions and 12245 deletions

View File

@@ -11,8 +11,6 @@ global:
external_url: <unset>
# the url where the SigNoz backend receives telemetry data (traces, metrics, logs) from instrumented applications.
ingestion_url: <unset>
# the url of the SigNoz MCP server. when unset, the MCP settings page is hidden in the frontend.
# mcp_url: <unset>
##################### Version #####################
version:

View File

@@ -2369,13 +2369,6 @@ components:
$ref: '#/components/schemas/GlobaltypesIdentNConfig'
ingestion_url:
type: string
mcp_url:
nullable: true
type: string
required:
- external_url
- ingestion_url
- mcp_url
type: object
GlobaltypesIdentNConfig:
properties:
@@ -4496,6 +4489,184 @@ components:
type: object
Sigv4SigV4Config:
type: object
SpantypesFieldContext:
enum:
- attribute
- resource
type: string
SpantypesGettableSpanMapperGroups:
properties:
items:
items:
$ref: '#/components/schemas/SpantypesSpanMapperGroup'
type: array
required:
- items
type: object
SpantypesPostableSpanMapper:
properties:
config:
$ref: '#/components/schemas/SpantypesSpanMapperConfig'
enabled:
type: boolean
field_context:
$ref: '#/components/schemas/SpantypesFieldContext'
name:
type: string
required:
- name
- field_context
- config
type: object
SpantypesPostableSpanMapperGroup:
properties:
category:
$ref: '#/components/schemas/SpantypesSpanMapperGroupCategory'
condition:
$ref: '#/components/schemas/SpantypesSpanMapperGroupCondition'
enabled:
type: boolean
name:
type: string
required:
- name
- category
- condition
type: object
SpantypesSpanMapper:
properties:
config:
$ref: '#/components/schemas/SpantypesSpanMapperConfig'
createdAt:
format: date-time
type: string
createdBy:
type: string
enabled:
type: boolean
field_context:
$ref: '#/components/schemas/SpantypesFieldContext'
group_id:
type: string
id:
type: string
name:
type: string
updatedAt:
format: date-time
type: string
updatedBy:
type: string
required:
- id
- group_id
- name
- field_context
- config
- enabled
type: object
SpantypesSpanMapperConfig:
properties:
sources:
items:
$ref: '#/components/schemas/SpantypesSpanMapperSource'
nullable: true
type: array
required:
- sources
type: object
SpantypesSpanMapperGroup:
properties:
category:
$ref: '#/components/schemas/SpantypesSpanMapperGroupCategory'
condition:
$ref: '#/components/schemas/SpantypesSpanMapperGroupCondition'
createdAt:
format: date-time
type: string
createdBy:
type: string
enabled:
type: boolean
id:
type: string
name:
type: string
orgId:
type: string
updatedAt:
format: date-time
type: string
updatedBy:
type: string
required:
- id
- orgId
- name
- category
- condition
- enabled
type: object
SpantypesSpanMapperGroupCategory:
type: object
SpantypesSpanMapperGroupCondition:
properties:
attributes:
items:
type: string
nullable: true
type: array
resource:
items:
type: string
nullable: true
type: array
required:
- attributes
- resource
type: object
SpantypesSpanMapperOperation:
enum:
- move
- copy
type: string
SpantypesSpanMapperSource:
properties:
context:
$ref: '#/components/schemas/SpantypesFieldContext'
key:
type: string
operation:
$ref: '#/components/schemas/SpantypesSpanMapperOperation'
priority:
type: integer
required:
- key
- context
- operation
- priority
type: object
SpantypesUpdatableSpanMapper:
properties:
config:
$ref: '#/components/schemas/SpantypesSpanMapperConfig'
enabled:
nullable: true
type: boolean
field_context:
$ref: '#/components/schemas/SpantypesFieldContext'
type: object
SpantypesUpdatableSpanMapperGroup:
properties:
condition:
$ref: '#/components/schemas/SpantypesSpanMapperGroupCondition'
enabled:
nullable: true
type: boolean
name:
nullable: true
type: string
type: object
TelemetrytypesFieldContext:
enum:
- metric
@@ -9238,6 +9409,487 @@ paths:
summary: Updates my service account
tags:
- serviceaccount
/api/v1/span_mapper_groups:
get:
deprecated: false
description: Returns all span attribute mapping groups for the authenticated
org.
operationId: ListSpanMapperGroups
parameters:
- explode: true
in: query
name: category
schema:
$ref: '#/components/schemas/SpantypesSpanMapperGroupCategory'
style: deepObject
- in: query
name: enabled
schema:
nullable: true
type: boolean
responses:
"200":
content:
application/json:
schema:
properties:
data:
$ref: '#/components/schemas/SpantypesGettableSpanMapperGroups'
status:
type: string
required:
- status
- data
type: object
description: OK
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Bad Request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- VIEWER
- tokenizer:
- VIEWER
summary: List span attribute mapping groups
tags:
- spanmapper
post:
deprecated: false
description: Creates a new span attribute mapping group for the org.
operationId: CreateSpanMapperGroup
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/SpantypesPostableSpanMapperGroup'
responses:
"201":
content:
application/json:
schema:
properties:
data:
$ref: '#/components/schemas/SpantypesSpanMapperGroup'
status:
type: string
required:
- status
- data
type: object
description: Created
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Bad Request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"409":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Conflict
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- ADMIN
- tokenizer:
- ADMIN
summary: Create a span attribute mapping group
tags:
- spanmapper
/api/v1/span_mapper_groups/{groupId}:
delete:
deprecated: false
description: Hard-deletes a mapping group and cascades to all its mappers.
operationId: DeleteSpanMapperGroup
parameters:
- in: path
name: groupId
required: true
schema:
type: string
responses:
"204":
description: No Content
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Not Found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- ADMIN
- tokenizer:
- ADMIN
summary: Delete a span attribute mapping group
tags:
- spanmapper
patch:
deprecated: false
description: Partially updates an existing mapping group's name, condition,
or enabled state.
operationId: UpdateSpanMapperGroup
parameters:
- in: path
name: groupId
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/SpantypesUpdatableSpanMapperGroup'
responses:
"204":
description: No Content
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Bad Request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Not Found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- ADMIN
- tokenizer:
- ADMIN
summary: Update a span attribute mapping group
tags:
- spanmapper
/api/v1/span_mapper_groups/{groupId}/span_mappers:
get:
deprecated: false
description: Returns all mappers belonging to a mapping group.
operationId: ListSpanMappers
parameters:
- in: path
name: groupId
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
properties:
data:
$ref: '#/components/schemas/SpantypesGettableSpanMapperGroups'
status:
type: string
required:
- status
- data
type: object
description: OK
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Bad Request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Not Found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- VIEWER
- tokenizer:
- VIEWER
summary: List span mappers for a group
tags:
- spanmapper
post:
deprecated: false
description: Adds a new mapper to the specified mapping group.
operationId: CreateSpanMapper
parameters:
- in: path
name: groupId
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/SpantypesPostableSpanMapper'
responses:
"201":
content:
application/json:
schema:
properties:
data:
$ref: '#/components/schemas/SpantypesSpanMapper'
status:
type: string
required:
- status
- data
type: object
description: Created
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Bad Request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Not Found
"409":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Conflict
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- ADMIN
- tokenizer:
- ADMIN
summary: Create a span mapper
tags:
- spanmapper
/api/v1/span_mapper_groups/{groupId}/span_mappers/{mapperId}:
delete:
deprecated: false
description: Hard-deletes a mapper from a mapping group.
operationId: DeleteSpanMapper
parameters:
- in: path
name: groupId
required: true
schema:
type: string
- in: path
name: mapperId
required: true
schema:
type: string
responses:
"204":
description: No Content
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Not Found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- ADMIN
- tokenizer:
- ADMIN
summary: Delete a span mapper
tags:
- spanmapper
patch:
deprecated: false
description: Partially updates an existing mapper's field context, config, or
enabled state.
operationId: UpdateSpanMapper
parameters:
- in: path
name: groupId
required: true
schema:
type: string
- in: path
name: mapperId
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/SpantypesUpdatableSpanMapper'
responses:
"204":
description: No Content
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Bad Request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Forbidden
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Not Found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/RenderErrorResponse'
description: Internal Server Error
security:
- api_key:
- ADMIN
- tokenizer:
- ADMIN
summary: Update a span mapper
tags:
- spanmapper
/api/v1/testChannel:
post:
deprecated: true

View File

@@ -12,6 +12,7 @@ import (
"github.com/SigNoz/signoz/pkg/cache/memorycache"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/modules/spanmapper/implspanmapper"
"github.com/gorilla/handlers"
@@ -111,9 +112,11 @@ func NewServer(config signoz.Config, signoz *signoz.SigNoz) (*Server, error) {
}
// initiate agent config handler
spanAttrMappingFeature := implspanmapper.NewSpanAttrMappingFeature(signoz.Modules.SpanMapper)
agentConfMgr, err := agentConf.Initiate(&agentConf.ManagerOptions{
Store: signoz.SQLStore,
AgentFeatures: []agentConf.AgentFeature{logParsingPipelineController},
AgentFeatures: []agentConf.AgentFeature{logParsingPipelineController, spanAttrMappingFeature},
})
if err != nil {
return nil, err

View File

@@ -312,6 +312,14 @@
"name": "react-redux",
"message": "[State mgmt] react-redux is deprecated. Migrate to Zustand, nuqs, or react-query."
},
{
"name": "xstate",
"message": "[State mgmt] xstate is deprecated. Migrate to Zustand or react-query."
},
{
"name": "@xstate/react",
"message": "[State mgmt] @xstate/react is deprecated. Migrate to Zustand or react-query."
},
{
"name": "react",
"importNames": [
@@ -606,9 +614,8 @@
"signoz/no-navigator-clipboard": "off",
// Tests can use navigator.clipboard directly,
"signoz/no-raw-absolute-path":"off",
"no-restricted-globals": "off",
"no-restricted-globals": "off"
// Tests need raw localStorage/sessionStorage to seed DOM state for isolation
"signoz/no-zustand-getstate-in-hooks": "off"
}
},
{

View File

@@ -1,4 +1,4 @@
<!doctype html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
@@ -72,12 +72,10 @@
// to that prefix by the React app (see utils/storage.ts getScopedKey).
// Read the <base> tag — already populated by the Go template — to derive
// the same prefix here, before any JS module has loaded.
var basePath =
(document.querySelector('base') || {}).getAttribute('href') || '/';
var basePath = (document.querySelector('base') || {}).getAttribute('href') || '/';
var prefix = basePath === '/' ? '' : basePath;
var theme = localStorage.getItem(prefix + 'THEME');
var autoSwitch =
localStorage.getItem(prefix + 'THEME_AUTO_SWITCH') === 'true';
var autoSwitch = localStorage.getItem(prefix + 'THEME_AUTO_SWITCH') === 'true';
if (autoSwitch) {
theme = window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'

View File

@@ -42,13 +42,13 @@ window.getComputedStyle = function (
} catch {
// Return a minimal CSSStyleDeclaration so callers (testing-library, Radix UI)
// see the element as visible and without animations.
return {
return ({
display: '',
visibility: '',
opacity: '1',
animationName: 'none',
getPropertyValue: () => '',
} as unknown as CSSStyleDeclaration;
} as unknown) as CSSStyleDeclaration;
}
};

View File

@@ -9,7 +9,7 @@
"build": "vite build",
"preview": "vite preview",
"prettify": "oxfmt",
"fmt": "oxfmt --check",
"fmt": "echo 'Disabled due to migration' || oxfmt --check",
"lint": "oxlint ./src && stylelint \"src/**/*.scss\"",
"lint:js": "oxlint ./src",
"lint:generated": "oxlint ./src/api/generated --fix",
@@ -63,6 +63,7 @@
"@visx/shape": "3.5.0",
"@visx/tooltip": "3.3.0",
"@vitejs/plugin-react": "5.1.4",
"@xstate/react": "^3.0.0",
"ansi-to-html": "0.7.2",
"antd": "5.11.0",
"antd-table-saveas-excel": "2.2.1",
@@ -145,6 +146,7 @@
"vite": "npm:rolldown-vite@7.3.1",
"vite-plugin-html": "3.2.2",
"web-vitals": "^0.2.4",
"xstate": "^4.31.0",
"zod": "4.3.6",
"zustand": "5.0.11"
},
@@ -238,7 +240,7 @@
},
"lint-staged": {
"*.(js|jsx|ts|tsx)": [
"oxfmt --check",
"echo 'Disabled due to migration' || oxfmt --check",
"oxlint --fix",
"sh scripts/typecheck-staged.sh"
]

View File

@@ -56,6 +56,7 @@ function isExternalUrl(node) {
return false;
}
// window.open(withBasePath(x)) and window.open(getAbsoluteUrl(x)) are already safe.
function isSafeHelperCall(node) {
return (
@@ -96,27 +97,18 @@ export default {
callee.object.type !== 'Identifier' ||
callee.object.name !== 'window' ||
callee.property.name !== 'open'
) {
return;
}
if (args.length === 0) {
return;
}
if (isExternalUrl(args[0])) {
return;
}
if (isSafeHelperCall(args[0])) {
return;
}
)
{return;}
if (args.length === 0) {return;}
if (isExternalUrl(args[0])) {return;}
if (isSafeHelperCall(args[0])) {return;}
context.report({ node, messageId: 'windowOpen' });
},
// window.location.origin + path
BinaryExpression(node) {
if (node.operator !== '+') {
return;
}
if (node.operator !== '+') {return;}
if (isOriginAccess(node.left) || isOriginAccess(node.right)) {
context.report({ node, messageId: 'originConcat' });
}
@@ -132,40 +124,26 @@ export default {
// window.location.origin used directly (not in concatenation)
// Catches: frontendBaseUrl: window.location.origin
MemberExpression(node) {
if (!isOriginAccess(node)) {
return;
}
if (!isOriginAccess(node)) {return;}
const parent = node.parent;
// Skip if parent is BinaryExpression with + (handled by BinaryExpression visitor)
if (parent.type === 'BinaryExpression' && parent.operator === '+') {
return;
}
if (parent.type === 'BinaryExpression' && parent.operator === '+') {return;}
// Skip if inside TemplateLiteral (handled by TemplateLiteral visitor)
if (parent.type === 'TemplateLiteral') {
return;
}
if (parent.type === 'TemplateLiteral') {return;}
context.report({ node, messageId: 'originDirect' });
},
// window.location.href = path
AssignmentExpression(node) {
if (node.operator !== '=') {
return;
}
if (!isHrefAccess(node.left)) {
return;
}
if (node.operator !== '=') {return;}
if (!isHrefAccess(node.left)) {return;}
// Allow external URLs
if (isExternalUrl(node.right)) {
return;
}
if (isExternalUrl(node.right)) {return;}
// Allow safe helper calls
if (isSafeHelperCall(node.right)) {
return;
}
if (isSafeHelperCall(node.right)) {return;}
context.report({ node, messageId: 'hrefAssign' });
},

View File

@@ -3125,17 +3125,12 @@ export interface GlobaltypesConfigDTO {
/**
* @type string
*/
external_url: string;
external_url?: string;
identN?: GlobaltypesIdentNConfigDTO;
/**
* @type string
*/
ingestion_url: string;
/**
* @type string
* @nullable true
*/
mcp_url: string | null;
ingestion_url?: string;
}
export interface GlobaltypesIdentNConfigDTO {
@@ -5475,6 +5470,187 @@ export interface Sigv4SigV4ConfigDTO {
[key: string]: unknown;
}
export enum SpantypesFieldContextDTO {
attribute = 'attribute',
resource = 'resource',
}
export interface SpantypesGettableSpanMapperGroupsDTO {
/**
* @type array
*/
items: SpantypesSpanMapperGroupDTO[];
}
export interface SpantypesPostableSpanMapperDTO {
config: SpantypesSpanMapperConfigDTO;
/**
* @type boolean
*/
enabled?: boolean;
field_context: SpantypesFieldContextDTO;
/**
* @type string
*/
name: string;
}
export interface SpantypesPostableSpanMapperGroupDTO {
category: SpantypesSpanMapperGroupCategoryDTO;
condition: SpantypesSpanMapperGroupConditionDTO;
/**
* @type boolean
*/
enabled?: boolean;
/**
* @type string
*/
name: string;
}
export interface SpantypesSpanMapperDTO {
config: SpantypesSpanMapperConfigDTO;
/**
* @type string
* @format date-time
*/
createdAt?: Date;
/**
* @type string
*/
createdBy?: string;
/**
* @type boolean
*/
enabled: boolean;
field_context: SpantypesFieldContextDTO;
/**
* @type string
*/
group_id: string;
/**
* @type string
*/
id: string;
/**
* @type string
*/
name: string;
/**
* @type string
* @format date-time
*/
updatedAt?: Date;
/**
* @type string
*/
updatedBy?: string;
}
export interface SpantypesSpanMapperConfigDTO {
/**
* @type array
* @nullable true
*/
sources: SpantypesSpanMapperSourceDTO[] | null;
}
export interface SpantypesSpanMapperGroupDTO {
category: SpantypesSpanMapperGroupCategoryDTO;
condition: SpantypesSpanMapperGroupConditionDTO;
/**
* @type string
* @format date-time
*/
createdAt?: Date;
/**
* @type string
*/
createdBy?: string;
/**
* @type boolean
*/
enabled: boolean;
/**
* @type string
*/
id: string;
/**
* @type string
*/
name: string;
/**
* @type string
*/
orgId: string;
/**
* @type string
* @format date-time
*/
updatedAt?: Date;
/**
* @type string
*/
updatedBy?: string;
}
export interface SpantypesSpanMapperGroupCategoryDTO {
[key: string]: unknown;
}
export interface SpantypesSpanMapperGroupConditionDTO {
/**
* @type array
* @nullable true
*/
attributes: string[] | null;
/**
* @type array
* @nullable true
*/
resource: string[] | null;
}
export enum SpantypesSpanMapperOperationDTO {
move = 'move',
copy = 'copy',
}
export interface SpantypesSpanMapperSourceDTO {
context: SpantypesFieldContextDTO;
/**
* @type string
*/
key: string;
operation: SpantypesSpanMapperOperationDTO;
/**
* @type integer
*/
priority: number;
}
export interface SpantypesUpdatableSpanMapperDTO {
config?: SpantypesSpanMapperConfigDTO;
/**
* @type boolean
* @nullable true
*/
enabled?: boolean | null;
field_context?: SpantypesFieldContextDTO;
}
export interface SpantypesUpdatableSpanMapperGroupDTO {
condition?: SpantypesSpanMapperGroupConditionDTO;
/**
* @type boolean
* @nullable true
*/
enabled?: boolean | null;
/**
* @type string
* @nullable true
*/
name?: string | null;
}
export enum TelemetrytypesFieldContextDTO {
metric = 'metric',
log = 'log',
@@ -6925,6 +7101,71 @@ export type GetMyServiceAccount200 = {
status: string;
};
export type ListSpanMapperGroupsParams = {
/**
* @description undefined
*/
category?: SpantypesSpanMapperGroupCategoryDTO;
/**
* @type boolean
* @nullable true
* @description undefined
*/
enabled?: boolean | null;
};
export type ListSpanMapperGroups200 = {
data: SpantypesGettableSpanMapperGroupsDTO;
/**
* @type string
*/
status: string;
};
export type CreateSpanMapperGroup201 = {
data: SpantypesSpanMapperGroupDTO;
/**
* @type string
*/
status: string;
};
export type DeleteSpanMapperGroupPathParameters = {
groupId: string;
};
export type UpdateSpanMapperGroupPathParameters = {
groupId: string;
};
export type ListSpanMappersPathParameters = {
groupId: string;
};
export type ListSpanMappers200 = {
data: SpantypesGettableSpanMapperGroupsDTO;
/**
* @type string
*/
status: string;
};
export type CreateSpanMapperPathParameters = {
groupId: string;
};
export type CreateSpanMapper201 = {
data: SpantypesSpanMapperDTO;
/**
* @type string
*/
status: string;
};
export type DeleteSpanMapperPathParameters = {
groupId: string;
mapperId: string;
};
export type UpdateSpanMapperPathParameters = {
groupId: string;
mapperId: string;
};
export type ListUsersDeprecated200 = {
/**
* @type array

View File

@@ -0,0 +1,787 @@
/**
* ! Do not edit manually
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'yarn generate:api'
* SigNoz
*/
import { useMutation, useQuery } from 'react-query';
import type {
InvalidateOptions,
MutationFunction,
QueryClient,
QueryFunction,
QueryKey,
UseMutationOptions,
UseMutationResult,
UseQueryOptions,
UseQueryResult,
} from 'react-query';
import type {
CreateSpanMapper201,
CreateSpanMapperGroup201,
CreateSpanMapperPathParameters,
DeleteSpanMapperGroupPathParameters,
DeleteSpanMapperPathParameters,
ListSpanMapperGroups200,
ListSpanMapperGroupsParams,
ListSpanMappers200,
ListSpanMappersPathParameters,
RenderErrorResponseDTO,
SpantypesPostableSpanMapperDTO,
SpantypesPostableSpanMapperGroupDTO,
SpantypesUpdatableSpanMapperDTO,
SpantypesUpdatableSpanMapperGroupDTO,
UpdateSpanMapperGroupPathParameters,
UpdateSpanMapperPathParameters,
} from '../sigNoz.schemas';
import { GeneratedAPIInstance } from '../../../generatedAPIInstance';
import type { ErrorType, BodyType } from '../../../generatedAPIInstance';
/**
* Returns all span attribute mapping groups for the authenticated org.
* @summary List span attribute mapping groups
*/
export const listSpanMapperGroups = (
params?: ListSpanMapperGroupsParams,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<ListSpanMapperGroups200>({
url: `/api/v1/span_mapper_groups`,
method: 'GET',
params,
signal,
});
};
export const getListSpanMapperGroupsQueryKey = (
params?: ListSpanMapperGroupsParams,
) => {
return [`/api/v1/span_mapper_groups`, ...(params ? [params] : [])] as const;
};
export const getListSpanMapperGroupsQueryOptions = <
TData = Awaited<ReturnType<typeof listSpanMapperGroups>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
params?: ListSpanMapperGroupsParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listSpanMapperGroups>>,
TError,
TData
>;
},
) => {
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getListSpanMapperGroupsQueryKey(params);
const queryFn: QueryFunction<
Awaited<ReturnType<typeof listSpanMapperGroups>>
> = ({ signal }) => listSpanMapperGroups(params, signal);
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof listSpanMapperGroups>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type ListSpanMapperGroupsQueryResult = NonNullable<
Awaited<ReturnType<typeof listSpanMapperGroups>>
>;
export type ListSpanMapperGroupsQueryError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary List span attribute mapping groups
*/
export function useListSpanMapperGroups<
TData = Awaited<ReturnType<typeof listSpanMapperGroups>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
params?: ListSpanMapperGroupsParams,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listSpanMapperGroups>>,
TError,
TData
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getListSpanMapperGroupsQueryOptions(params, options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
query.queryKey = queryOptions.queryKey;
return query;
}
/**
* @summary List span attribute mapping groups
*/
export const invalidateListSpanMapperGroups = async (
queryClient: QueryClient,
params?: ListSpanMapperGroupsParams,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getListSpanMapperGroupsQueryKey(params) },
options,
);
return queryClient;
};
/**
* Creates a new span attribute mapping group for the org.
* @summary Create a span attribute mapping group
*/
export const createSpanMapperGroup = (
spantypesPostableSpanMapperGroupDTO: BodyType<SpantypesPostableSpanMapperGroupDTO>,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<CreateSpanMapperGroup201>({
url: `/api/v1/span_mapper_groups`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: spantypesPostableSpanMapperGroupDTO,
signal,
});
};
export const getCreateSpanMapperGroupMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createSpanMapperGroup>>,
TError,
{ data: BodyType<SpantypesPostableSpanMapperGroupDTO> },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof createSpanMapperGroup>>,
TError,
{ data: BodyType<SpantypesPostableSpanMapperGroupDTO> },
TContext
> => {
const mutationKey = ['createSpanMapperGroup'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof createSpanMapperGroup>>,
{ data: BodyType<SpantypesPostableSpanMapperGroupDTO> }
> = (props) => {
const { data } = props ?? {};
return createSpanMapperGroup(data);
};
return { mutationFn, ...mutationOptions };
};
export type CreateSpanMapperGroupMutationResult = NonNullable<
Awaited<ReturnType<typeof createSpanMapperGroup>>
>;
export type CreateSpanMapperGroupMutationBody =
BodyType<SpantypesPostableSpanMapperGroupDTO>;
export type CreateSpanMapperGroupMutationError =
ErrorType<RenderErrorResponseDTO>;
/**
* @summary Create a span attribute mapping group
*/
export const useCreateSpanMapperGroup = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createSpanMapperGroup>>,
TError,
{ data: BodyType<SpantypesPostableSpanMapperGroupDTO> },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof createSpanMapperGroup>>,
TError,
{ data: BodyType<SpantypesPostableSpanMapperGroupDTO> },
TContext
> => {
const mutationOptions = getCreateSpanMapperGroupMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Hard-deletes a mapping group and cascades to all its mappers.
* @summary Delete a span attribute mapping group
*/
export const deleteSpanMapperGroup = ({
groupId,
}: DeleteSpanMapperGroupPathParameters) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/span_mapper_groups/${groupId}`,
method: 'DELETE',
});
};
export const getDeleteSpanMapperGroupMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteSpanMapperGroup>>,
TError,
{ pathParams: DeleteSpanMapperGroupPathParameters },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof deleteSpanMapperGroup>>,
TError,
{ pathParams: DeleteSpanMapperGroupPathParameters },
TContext
> => {
const mutationKey = ['deleteSpanMapperGroup'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof deleteSpanMapperGroup>>,
{ pathParams: DeleteSpanMapperGroupPathParameters }
> = (props) => {
const { pathParams } = props ?? {};
return deleteSpanMapperGroup(pathParams);
};
return { mutationFn, ...mutationOptions };
};
export type DeleteSpanMapperGroupMutationResult = NonNullable<
Awaited<ReturnType<typeof deleteSpanMapperGroup>>
>;
export type DeleteSpanMapperGroupMutationError =
ErrorType<RenderErrorResponseDTO>;
/**
* @summary Delete a span attribute mapping group
*/
export const useDeleteSpanMapperGroup = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteSpanMapperGroup>>,
TError,
{ pathParams: DeleteSpanMapperGroupPathParameters },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof deleteSpanMapperGroup>>,
TError,
{ pathParams: DeleteSpanMapperGroupPathParameters },
TContext
> => {
const mutationOptions = getDeleteSpanMapperGroupMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Partially updates an existing mapping group's name, condition, or enabled state.
* @summary Update a span attribute mapping group
*/
export const updateSpanMapperGroup = (
{ groupId }: UpdateSpanMapperGroupPathParameters,
spantypesUpdatableSpanMapperGroupDTO: BodyType<SpantypesUpdatableSpanMapperGroupDTO>,
) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/span_mapper_groups/${groupId}`,
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
data: spantypesUpdatableSpanMapperGroupDTO,
});
};
export const getUpdateSpanMapperGroupMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateSpanMapperGroup>>,
TError,
{
pathParams: UpdateSpanMapperGroupPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperGroupDTO>;
},
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof updateSpanMapperGroup>>,
TError,
{
pathParams: UpdateSpanMapperGroupPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperGroupDTO>;
},
TContext
> => {
const mutationKey = ['updateSpanMapperGroup'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof updateSpanMapperGroup>>,
{
pathParams: UpdateSpanMapperGroupPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperGroupDTO>;
}
> = (props) => {
const { pathParams, data } = props ?? {};
return updateSpanMapperGroup(pathParams, data);
};
return { mutationFn, ...mutationOptions };
};
export type UpdateSpanMapperGroupMutationResult = NonNullable<
Awaited<ReturnType<typeof updateSpanMapperGroup>>
>;
export type UpdateSpanMapperGroupMutationBody =
BodyType<SpantypesUpdatableSpanMapperGroupDTO>;
export type UpdateSpanMapperGroupMutationError =
ErrorType<RenderErrorResponseDTO>;
/**
* @summary Update a span attribute mapping group
*/
export const useUpdateSpanMapperGroup = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateSpanMapperGroup>>,
TError,
{
pathParams: UpdateSpanMapperGroupPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperGroupDTO>;
},
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof updateSpanMapperGroup>>,
TError,
{
pathParams: UpdateSpanMapperGroupPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperGroupDTO>;
},
TContext
> => {
const mutationOptions = getUpdateSpanMapperGroupMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Returns all mappers belonging to a mapping group.
* @summary List span mappers for a group
*/
export const listSpanMappers = (
{ groupId }: ListSpanMappersPathParameters,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<ListSpanMappers200>({
url: `/api/v1/span_mapper_groups/${groupId}/span_mappers`,
method: 'GET',
signal,
});
};
export const getListSpanMappersQueryKey = ({
groupId,
}: ListSpanMappersPathParameters) => {
return [`/api/v1/span_mapper_groups/${groupId}/span_mappers`] as const;
};
export const getListSpanMappersQueryOptions = <
TData = Awaited<ReturnType<typeof listSpanMappers>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
{ groupId }: ListSpanMappersPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listSpanMappers>>,
TError,
TData
>;
},
) => {
const { query: queryOptions } = options ?? {};
const queryKey =
queryOptions?.queryKey ?? getListSpanMappersQueryKey({ groupId });
const queryFn: QueryFunction<Awaited<ReturnType<typeof listSpanMappers>>> = ({
signal,
}) => listSpanMappers({ groupId }, signal);
return {
queryKey,
queryFn,
enabled: !!groupId,
...queryOptions,
} as UseQueryOptions<
Awaited<ReturnType<typeof listSpanMappers>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type ListSpanMappersQueryResult = NonNullable<
Awaited<ReturnType<typeof listSpanMappers>>
>;
export type ListSpanMappersQueryError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary List span mappers for a group
*/
export function useListSpanMappers<
TData = Awaited<ReturnType<typeof listSpanMappers>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
{ groupId }: ListSpanMappersPathParameters,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listSpanMappers>>,
TError,
TData
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getListSpanMappersQueryOptions({ groupId }, options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
query.queryKey = queryOptions.queryKey;
return query;
}
/**
* @summary List span mappers for a group
*/
export const invalidateListSpanMappers = async (
queryClient: QueryClient,
{ groupId }: ListSpanMappersPathParameters,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getListSpanMappersQueryKey({ groupId }) },
options,
);
return queryClient;
};
/**
* Adds a new mapper to the specified mapping group.
* @summary Create a span mapper
*/
export const createSpanMapper = (
{ groupId }: CreateSpanMapperPathParameters,
spantypesPostableSpanMapperDTO: BodyType<SpantypesPostableSpanMapperDTO>,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<CreateSpanMapper201>({
url: `/api/v1/span_mapper_groups/${groupId}/span_mappers`,
method: 'POST',
headers: { 'Content-Type': 'application/json' },
data: spantypesPostableSpanMapperDTO,
signal,
});
};
export const getCreateSpanMapperMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createSpanMapper>>,
TError,
{
pathParams: CreateSpanMapperPathParameters;
data: BodyType<SpantypesPostableSpanMapperDTO>;
},
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof createSpanMapper>>,
TError,
{
pathParams: CreateSpanMapperPathParameters;
data: BodyType<SpantypesPostableSpanMapperDTO>;
},
TContext
> => {
const mutationKey = ['createSpanMapper'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof createSpanMapper>>,
{
pathParams: CreateSpanMapperPathParameters;
data: BodyType<SpantypesPostableSpanMapperDTO>;
}
> = (props) => {
const { pathParams, data } = props ?? {};
return createSpanMapper(pathParams, data);
};
return { mutationFn, ...mutationOptions };
};
export type CreateSpanMapperMutationResult = NonNullable<
Awaited<ReturnType<typeof createSpanMapper>>
>;
export type CreateSpanMapperMutationBody =
BodyType<SpantypesPostableSpanMapperDTO>;
export type CreateSpanMapperMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Create a span mapper
*/
export const useCreateSpanMapper = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof createSpanMapper>>,
TError,
{
pathParams: CreateSpanMapperPathParameters;
data: BodyType<SpantypesPostableSpanMapperDTO>;
},
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof createSpanMapper>>,
TError,
{
pathParams: CreateSpanMapperPathParameters;
data: BodyType<SpantypesPostableSpanMapperDTO>;
},
TContext
> => {
const mutationOptions = getCreateSpanMapperMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Hard-deletes a mapper from a mapping group.
* @summary Delete a span mapper
*/
export const deleteSpanMapper = ({
groupId,
mapperId,
}: DeleteSpanMapperPathParameters) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/span_mapper_groups/${groupId}/span_mappers/${mapperId}`,
method: 'DELETE',
});
};
export const getDeleteSpanMapperMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteSpanMapper>>,
TError,
{ pathParams: DeleteSpanMapperPathParameters },
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof deleteSpanMapper>>,
TError,
{ pathParams: DeleteSpanMapperPathParameters },
TContext
> => {
const mutationKey = ['deleteSpanMapper'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof deleteSpanMapper>>,
{ pathParams: DeleteSpanMapperPathParameters }
> = (props) => {
const { pathParams } = props ?? {};
return deleteSpanMapper(pathParams);
};
return { mutationFn, ...mutationOptions };
};
export type DeleteSpanMapperMutationResult = NonNullable<
Awaited<ReturnType<typeof deleteSpanMapper>>
>;
export type DeleteSpanMapperMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Delete a span mapper
*/
export const useDeleteSpanMapper = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof deleteSpanMapper>>,
TError,
{ pathParams: DeleteSpanMapperPathParameters },
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof deleteSpanMapper>>,
TError,
{ pathParams: DeleteSpanMapperPathParameters },
TContext
> => {
const mutationOptions = getDeleteSpanMapperMutationOptions(options);
return useMutation(mutationOptions);
};
/**
* Partially updates an existing mapper's field context, config, or enabled state.
* @summary Update a span mapper
*/
export const updateSpanMapper = (
{ groupId, mapperId }: UpdateSpanMapperPathParameters,
spantypesUpdatableSpanMapperDTO: BodyType<SpantypesUpdatableSpanMapperDTO>,
) => {
return GeneratedAPIInstance<void>({
url: `/api/v1/span_mapper_groups/${groupId}/span_mappers/${mapperId}`,
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
data: spantypesUpdatableSpanMapperDTO,
});
};
export const getUpdateSpanMapperMutationOptions = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateSpanMapper>>,
TError,
{
pathParams: UpdateSpanMapperPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperDTO>;
},
TContext
>;
}): UseMutationOptions<
Awaited<ReturnType<typeof updateSpanMapper>>,
TError,
{
pathParams: UpdateSpanMapperPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperDTO>;
},
TContext
> => {
const mutationKey = ['updateSpanMapper'];
const { mutation: mutationOptions } = options
? options.mutation &&
'mutationKey' in options.mutation &&
options.mutation.mutationKey
? options
: { ...options, mutation: { ...options.mutation, mutationKey } }
: { mutation: { mutationKey } };
const mutationFn: MutationFunction<
Awaited<ReturnType<typeof updateSpanMapper>>,
{
pathParams: UpdateSpanMapperPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperDTO>;
}
> = (props) => {
const { pathParams, data } = props ?? {};
return updateSpanMapper(pathParams, data);
};
return { mutationFn, ...mutationOptions };
};
export type UpdateSpanMapperMutationResult = NonNullable<
Awaited<ReturnType<typeof updateSpanMapper>>
>;
export type UpdateSpanMapperMutationBody =
BodyType<SpantypesUpdatableSpanMapperDTO>;
export type UpdateSpanMapperMutationError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary Update a span mapper
*/
export const useUpdateSpanMapper = <
TError = ErrorType<RenderErrorResponseDTO>,
TContext = unknown,
>(options?: {
mutation?: UseMutationOptions<
Awaited<ReturnType<typeof updateSpanMapper>>,
TError,
{
pathParams: UpdateSpanMapperPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperDTO>;
},
TContext
>;
}): UseMutationResult<
Awaited<ReturnType<typeof updateSpanMapper>>,
TError,
{
pathParams: UpdateSpanMapperPathParameters;
data: BodyType<SpantypesUpdatableSpanMapperDTO>;
},
TContext
> => {
const mutationOptions = getUpdateSpanMapperMutationOptions(options);
return useMutation(mutationOptions);
};

View File

@@ -39,8 +39,8 @@ jest.mock('axios', () => {
describe('interceptorRejected', () => {
beforeEach(() => {
jest.clearAllMocks();
(axios as unknown as jest.Mock).mockResolvedValue({ data: 'success' });
(axios.isAxiosError as unknown as jest.Mock).mockReturnValue(true);
((axios as unknown) as jest.Mock).mockResolvedValue({ data: 'success' });
((axios.isAxiosError as unknown) as jest.Mock).mockReturnValue(true);
});
it('should preserve array payload structure when retrying a 401 request', async () => {
@@ -49,7 +49,7 @@ describe('interceptorRejected', () => {
{ relation: 'assignee', object: { resource: { name: 'editor' } } },
];
const error = {
const error = ({
response: {
status: 401,
config: {
@@ -67,7 +67,7 @@ describe('interceptorRejected', () => {
headers: new AxiosHeaders(),
data: JSON.stringify(arrayPayload),
},
} as unknown as AxiosResponse;
} as unknown) as AxiosResponse;
try {
await interceptorRejected(error);
@@ -75,7 +75,7 @@ describe('interceptorRejected', () => {
// Expected to reject after retry
}
const mockAxiosFn = axios as unknown as jest.Mock;
const mockAxiosFn = (axios as unknown) as jest.Mock;
expect(mockAxiosFn.mock.calls.length).toBe(1);
const retryCallConfig = mockAxiosFn.mock.calls[0][0];
expect(Array.isArray(JSON.parse(retryCallConfig.data))).toBe(true);
@@ -85,7 +85,7 @@ describe('interceptorRejected', () => {
it('should preserve object payload structure when retrying a 401 request', async () => {
const objectPayload = { key: 'value', nested: { data: 123 } };
const error = {
const error = ({
response: {
status: 401,
config: {
@@ -103,7 +103,7 @@ describe('interceptorRejected', () => {
headers: new AxiosHeaders(),
data: JSON.stringify(objectPayload),
},
} as unknown as AxiosResponse;
} as unknown) as AxiosResponse;
try {
await interceptorRejected(error);
@@ -111,14 +111,14 @@ describe('interceptorRejected', () => {
// Expected to reject after retry
}
const mockAxiosFn = axios as unknown as jest.Mock;
const mockAxiosFn = (axios as unknown) as jest.Mock;
expect(mockAxiosFn.mock.calls.length).toBe(1);
const retryCallConfig = mockAxiosFn.mock.calls[0][0];
expect(JSON.parse(retryCallConfig.data)).toEqual(objectPayload);
});
it('should handle undefined data gracefully when retrying', async () => {
const error = {
const error = ({
response: {
status: 401,
config: {
@@ -136,7 +136,7 @@ describe('interceptorRejected', () => {
headers: new AxiosHeaders(),
data: undefined,
},
} as unknown as AxiosResponse;
} as unknown) as AxiosResponse;
try {
await interceptorRejected(error);
@@ -144,7 +144,7 @@ describe('interceptorRejected', () => {
// Expected to reject after retry
}
const mockAxiosFn = axios as unknown as jest.Mock;
const mockAxiosFn = (axios as unknown) as jest.Mock;
expect(mockAxiosFn.mock.calls.length).toBe(1);
const retryCallConfig = mockAxiosFn.mock.calls[0][0];
expect(retryCallConfig.data).toBeUndefined();

View File

@@ -9,8 +9,9 @@ const getRetentionV2 = async (): Promise<
SuccessResponseV2<PayloadProps<'logs'>>
> => {
try {
const response =
await ApiV2Instance.get<PayloadProps<'logs'>>(`/settings/ttl`);
const response = await ApiV2Instance.get<PayloadProps<'logs'>>(
`/settings/ttl`,
);
return {
httpStatusCode: response.status,

View File

@@ -52,18 +52,18 @@ describe('convertV5ResponseToLegacy', () => {
alias: '__result_0',
meta: {},
series: [
{
({
labels: [
{
key: { name: 'service.name' } as unknown as TelemetryFieldKey,
key: ({ name: 'service.name' } as unknown) as TelemetryFieldKey,
value: 'adservice',
},
],
values: [
{ timestamp: 1000, value: 10 } as unknown as TimeSeriesValue,
{ timestamp: 2000, value: 12 } as unknown as TimeSeriesValue,
({ timestamp: 1000, value: 10 } as unknown) as TimeSeriesValue,
({ timestamp: 2000, value: 12 } as unknown) as TimeSeriesValue,
],
} as unknown as TimeSeries,
} as unknown) as TimeSeries,
],
},
],
@@ -88,8 +88,10 @@ describe('convertV5ResponseToLegacy', () => {
},
]);
const input: SuccessResponse<MetricRangePayloadV5, QueryRangeRequestV5> =
makeBaseSuccess({ data: v5Data }, params);
const input: SuccessResponse<
MetricRangePayloadV5,
QueryRangeRequestV5
> = makeBaseSuccess({ data: v5Data }, params);
const legendMap = { A: '{{service.name}}' };
const result = convertV5ResponseToLegacy(input, legendMap, false);
@@ -119,33 +121,33 @@ describe('convertV5ResponseToLegacy', () => {
const scalar: ScalarData = {
columns: [
// group column
{
({
name: 'service.name',
queryName: 'A',
aggregationIndex: 0,
columnType: 'group',
} as unknown as ScalarData['columns'][number],
} as unknown) as ScalarData['columns'][number],
// aggregation 0
{
({
name: '__result_0',
queryName: 'A',
aggregationIndex: 0,
columnType: 'aggregation',
} as unknown as ScalarData['columns'][number],
} as unknown) as ScalarData['columns'][number],
// aggregation 1
{
({
name: '__result_1',
queryName: 'A',
aggregationIndex: 1,
columnType: 'aggregation',
} as unknown as ScalarData['columns'][number],
} as unknown) as ScalarData['columns'][number],
// formula F1
{
({
name: '__result',
queryName: 'F1',
aggregationIndex: 0,
columnType: 'aggregation',
} as unknown as ScalarData['columns'][number],
} as unknown) as ScalarData['columns'][number],
],
data: [['adservice', 606, 1.452, 151.5]],
};
@@ -172,15 +174,17 @@ describe('convertV5ResponseToLegacy', () => {
},
{
type: 'builder_formula',
spec: {
spec: ({
name: 'F1',
expression: 'A * 0.25',
} as unknown as QueryBuilderFormula,
} as unknown) as QueryBuilderFormula,
},
]);
const input: SuccessResponse<MetricRangePayloadV5, QueryRangeRequestV5> =
makeBaseSuccess({ data: v5Data }, params);
const input: SuccessResponse<
MetricRangePayloadV5,
QueryRangeRequestV5
> = makeBaseSuccess({ data: v5Data }, params);
const legendMap = { A: '{{service.name}}', F1: '' };
const result = convertV5ResponseToLegacy(input, legendMap, false);
@@ -250,8 +254,10 @@ describe('convertV5ResponseToLegacy', () => {
},
]);
const input: SuccessResponse<MetricRangePayloadV5, QueryRangeRequestV5> =
makeBaseSuccess({ data: v5Data }, params);
const input: SuccessResponse<
MetricRangePayloadV5,
QueryRangeRequestV5
> = makeBaseSuccess({ data: v5Data }, params);
const legendMap = { A: '{{service.name}}' };
const result = convertV5ResponseToLegacy(input, legendMap, true);

View File

@@ -93,7 +93,7 @@ function convertTimeSeriesData(
labels: series.labels
? Object.fromEntries(
series.labels.map((label: any) => [label.key.name, label.value]),
)
)
: {},
labelsArray: series.labels
? series.labels.map((label: any) => ({ [label.key.name]: label.value }))
@@ -358,19 +358,16 @@ export function convertV5ResponseToLegacy(
const aggregationPerQuery =
(params as QueryRangeRequestV5)?.compositeQuery?.queries
?.filter((query) => query.type === 'builder_query')
.reduce(
(acc, query) => {
if (
query.type === 'builder_query' &&
'aggregations' in query.spec &&
query.spec.name
) {
acc[query.spec.name] = query.spec.aggregations;
}
return acc;
},
{} as Record<string, any>,
) || {};
.reduce((acc, query) => {
if (
query.type === 'builder_query' &&
'aggregations' in query.spec &&
query.spec.name
) {
acc[query.spec.name] = query.spec.aggregations;
}
return acc;
}, {} as Record<string, any>) || {};
// If formatForWeb is true, return as-is (like existing logic)
if (formatForWeb && v5Data?.type === 'scalar') {

View File

@@ -713,7 +713,7 @@ describe('prepareQueryRangePayloadV5', () => {
baseBuilderQuery({
dataSource: DataSource.LOGS,
filter: { expression: 'http.status_code >= 500' },
filters: undefined as unknown as IBuilderQuery['filters'],
filters: (undefined as unknown) as IBuilderQuery['filters'],
}),
],
queryFormulas: [],
@@ -746,7 +746,7 @@ describe('prepareQueryRangePayloadV5', () => {
queryData: [
baseBuilderQuery({
dataSource: DataSource.LOGS,
filter: undefined as unknown as IBuilderQuery['filter'],
filter: (undefined as unknown) as IBuilderQuery['filter'],
filters: {
items: [
{
@@ -834,8 +834,8 @@ describe('prepareQueryRangePayloadV5', () => {
queryData: [
baseBuilderQuery({
dataSource: DataSource.LOGS,
filter: undefined as unknown as IBuilderQuery['filter'],
filters: undefined as unknown as IBuilderQuery['filters'],
filter: (undefined as unknown) as IBuilderQuery['filter'],
filters: (undefined as unknown) as IBuilderQuery['filters'],
}),
],
queryFormulas: [],

View File

@@ -139,9 +139,10 @@ function createBaseSpec(
requestType: RequestType,
panelType?: PANEL_TYPES,
): BaseBuilderQuery {
const nonEmptySelectColumns = (
queryData.selectColumns as (BaseAutocompleteData | TelemetryFieldKey)[]
)?.filter((c) => ('key' in c ? c?.key : c?.name));
const nonEmptySelectColumns = (queryData.selectColumns as (
| BaseAutocompleteData
| TelemetryFieldKey
)[])?.filter((c) => ('key' in c ? c?.key : c?.name));
return {
stepInterval: queryData?.stepInterval || null,
@@ -159,7 +160,7 @@ function createBaseSpec(
signal: item?.signal,
materialized: item?.materialized,
}),
)
)
: undefined,
limit:
panelType === PANEL_TYPES.TABLE || panelType === PANEL_TYPES.LIST
@@ -178,48 +179,52 @@ function createBaseSpec(
},
direction: order.order,
}),
)
)
: undefined,
legend: isEmpty(queryData.legend) ? undefined : queryData.legend,
having: isEmpty(queryData.having) ? undefined : (queryData?.having as Having),
functions: isEmpty(queryData.functions)
? undefined
: queryData.functions.map((func: QueryFunction): QueryFunction => {
// Normalize function name to handle case sensitivity
const normalizedName = normalizeFunctionName(func?.name);
return {
name: normalizedName as FunctionName,
args: isEmpty(func.namedArgs)
? func.args?.map((arg) => ({
value: arg?.value,
}))
: Object.entries(func?.namedArgs || {}).map(([name, value]) => ({
name,
value,
})),
};
}),
: queryData.functions.map(
(func: QueryFunction): QueryFunction => {
// Normalize function name to handle case sensitivity
const normalizedName = normalizeFunctionName(func?.name);
return {
name: normalizedName as FunctionName,
args: isEmpty(func.namedArgs)
? func.args?.map((arg) => ({
value: arg?.value,
}))
: Object.entries(func?.namedArgs || {}).map(([name, value]) => ({
name,
value,
})),
};
},
),
selectFields: isEmpty(nonEmptySelectColumns)
? undefined
: nonEmptySelectColumns?.map((column: any): TelemetryFieldKey => {
const fieldName = column.name ?? column.key;
const isDeprecated = isDeprecatedField(fieldName);
: nonEmptySelectColumns?.map(
(column: any): TelemetryFieldKey => {
const fieldName = column.name ?? column.key;
const isDeprecated = isDeprecatedField(fieldName);
const fieldObj: TelemetryFieldKey = {
name: fieldName,
fieldDataType:
column?.fieldDataType ?? (column?.dataType as FieldDataType),
signal: column?.signal ?? undefined,
};
const fieldObj: TelemetryFieldKey = {
name: fieldName,
fieldDataType:
column?.fieldDataType ?? (column?.dataType as FieldDataType),
signal: column?.signal ?? undefined,
};
// Only add fieldContext if the field is NOT deprecated
if (!isDeprecated && fieldName !== 'name') {
fieldObj.fieldContext =
column?.fieldContext ?? (column?.type as FieldContext);
}
// Only add fieldContext if the field is NOT deprecated
if (!isDeprecated && fieldName !== 'name') {
fieldObj.fieldContext =
column?.fieldContext ?? (column?.type as FieldContext);
}
return fieldObj;
}),
return fieldObj;
},
),
};
}
@@ -231,8 +236,7 @@ export function parseAggregations(
const result: { expression: string; alias?: string }[] = [];
// Matches function calls like "count()" or "sum(field)" with optional alias like "as 'alias'"
// Handles quoted ('alias'), dash-separated (field-name), and unquoted values after "as" keyword
const regex =
/([a-zA-Z0-9_]+\([^)]*\))(?:\s*as\s+((?:'[^']*'|"[^"]*"|[a-zA-Z0-9_-]+)))?/g;
const regex = /([a-zA-Z0-9_]+\([^)]*\))(?:\s*as\s+((?:'[^']*'|"[^"]*"|[a-zA-Z0-9_-]+)))?/g;
let match = regex.exec(expression);
while (match !== null) {
const expr = match[1];
@@ -361,9 +365,10 @@ function createTraceOperatorBaseSpec(
requestType: RequestType,
panelType?: PANEL_TYPES,
): BaseBuilderQuery {
const nonEmptySelectColumns = (
queryData.selectColumns as (BaseAutocompleteData | TelemetryFieldKey)[]
)?.filter((c) => ('key' in c ? c?.key : c?.name));
const nonEmptySelectColumns = (queryData.selectColumns as (
| BaseAutocompleteData
| TelemetryFieldKey
)[])?.filter((c) => ('key' in c ? c?.key : c?.name));
const {
stepInterval,
@@ -390,7 +395,7 @@ function createTraceOperatorBaseSpec(
signal: item?.signal,
materialized: item?.materialized,
}),
)
)
: undefined,
limit:
panelType === PANEL_TYPES.TABLE || panelType === PANEL_TYPES.LIST
@@ -406,7 +411,7 @@ function createTraceOperatorBaseSpec(
},
direction: order.order,
}),
)
)
: undefined,
legend: isEmpty(legend) ? undefined : legend,
having: isEmpty(having) ? undefined : (having as Having),
@@ -420,7 +425,7 @@ function createTraceOperatorBaseSpec(
fieldContext: column?.fieldContext ?? (column?.type as FieldContext),
signal: column?.signal ?? undefined,
}),
),
),
};
}
@@ -502,22 +507,18 @@ export function convertClickHouseQueriesToV5(
/**
* Helper function to reduce query arrays to objects
*/
function reduceQueriesToObject(queryArray: any[]): {
queries: Record<string, any>;
legends: Record<string, string>;
} {
function reduceQueriesToObject(
queryArray: any[],
): { queries: Record<string, any>; legends: Record<string, string> } {
const legends: Record<string, string> = {};
const queries = queryArray.reduce(
(acc, queryItem) => {
if (!queryItem.query) {
return acc;
}
acc[queryItem.name] = queryItem;
legends[queryItem.name] = queryItem.legend;
const queries = queryArray.reduce((acc, queryItem) => {
if (!queryItem.query) {
return acc;
},
{} as Record<string, any>,
);
}
acc[queryItem.name] = queryItem;
legends[queryItem.name] = queryItem.legend;
return acc;
}, {} as Record<string, any>);
return { queries, legends };
}
@@ -553,7 +554,7 @@ export const prepareQueryRangePayloadV5 = ({
queryTraceOperator && queryTraceOperator.length > 0
? queryTraceOperator.filter((traceOperator) =>
Boolean(traceOperator.expression.trim()),
)
)
: [];
const currentTraceOperator = mapQueryDataToApi(
@@ -647,18 +648,15 @@ export const prepareQueryRangePayloadV5 = ({
: graphType === PANEL_TYPES.TABLE),
fillGaps: fillGaps || false,
},
variables: Object.entries(variables).reduce(
(acc, [key, value]) => {
acc[key] = {
value,
type: dynamicVariables
?.find((v) => v.name === key)
?.type?.toLowerCase() as VariableType,
};
return acc;
},
{} as Record<string, VariableItem>,
),
variables: Object.entries(variables).reduce((acc, [key, value]) => {
acc[key] = {
value,
type: dynamicVariables
?.find((v) => v.name === key)
?.type?.toLowerCase() as VariableType,
};
return acc;
}, {} as Record<string, VariableItem>),
};
return { legendMap, queryPayload };

View File

@@ -1,70 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 142.5 145.6" style="enable-background:new 0 0 142.5 145.6;" xml:space="preserve">
<style type="text/css">
.st0{fill:#565656;}
.st1{fill:url(#SVGID_1_);}
</style>
<g>
<path class="st0" d="M28.7,131.5c-0.3,7.9-6.6,14.1-14.4,14.1C6.1,145.6,0,139,0,130.9s6.6-14.7,14.7-14.7c3.6,0,7.2,1.6,10.2,4.4
l-2.3,2.9c-2.3-2-5.1-3.4-7.9-3.4c-5.9,0-10.8,4.8-10.8,10.8c0,6.1,4.6,10.8,10.4,10.8c5.2,0,9.3-3.8,10.2-8.8H12.6v-3.5h16.1
V131.5z"/>
<path class="st0" d="M42.3,129.5h-2.2c-2.4,0-4.4,2-4.4,4.4v11.4h-3.9v-19.6H35v1.6c1.1-1.1,2.7-1.6,4.6-1.6h4.2L42.3,129.5z"/>
<path class="st0" d="M63.7,145.3h-3.4v-2.5c-2.6,2.5-6.6,3.7-10.7,1.9c-3-1.3-5.3-4.1-5.9-7.4c-1.2-6.3,3.7-11.9,9.9-11.9
c2.6,0,5,1.1,6.7,2.8v-2.5h3.4V145.3z M59.7,137c0.9-4-2.1-7.6-6-7.6c-3.4,0-6.1,2.8-6.1,6.1c0,3.8,3.3,6.7,7.2,6.1
C57.1,141.2,59.1,139.3,59.7,137z"/>
<path class="st0" d="M71.5,124.7v1.1h6.2v3.4h-6.2v16.1h-3.8v-20.5c0-4.3,3.1-6.8,7-6.8h4.7l-1.6,3.7h-3.1
C72.9,121.6,71.5,123,71.5,124.7z"/>
<path class="st0" d="M98.5,145.3h-3.3v-2.5c-2.6,2.5-6.6,3.7-10.7,1.9c-3-1.3-5.3-4.1-5.9-7.4c-1.2-6.3,3.7-11.9,9.9-11.9
c2.6,0,5,1.1,6.7,2.8v-2.5h3.4v19.6H98.5z M94.5,137c0.9-4-2.1-7.6-6-7.6c-3.4,0-6.1,2.8-6.1,6.1c0,3.8,3.3,6.7,7.2,6.1
C92,141.2,93.9,139.3,94.5,137z"/>
<path class="st0" d="M119.4,133.8v11.5h-3.9v-11.6c0-2.4-2-4.4-4.4-4.4c-2.5,0-4.4,2-4.4,4.4v11.6h-3.9v-19.6h3.2v1.7
c1.4-1.3,3.3-2,5.2-2C115.8,125.5,119.4,129.2,119.4,133.8z"/>
<path class="st0" d="M142.4,145.3h-3.3v-2.5c-2.6,2.5-6.6,3.7-10.7,1.9c-3-1.3-5.3-4.1-5.9-7.4c-1.2-6.3,3.7-11.9,9.9-11.9
c2.6,0,5,1.1,6.7,2.8v-2.5h3.4v19.6H142.4z M138.4,137c0.9-4-2.1-7.6-6-7.6c-3.4,0-6.1,2.8-6.1,6.1c0,3.8,3.3,6.7,7.2,6.1
C135.9,141.2,137.8,139.3,138.4,137z"/>
</g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="71.25" y1="10.4893" x2="71.25" y2="113.3415" gradientTransform="matrix(1 0 0 -1 0 148.6)">
<stop offset="0" style="stop-color:#FCEE1F"/>
<stop offset="1" style="stop-color:#F15B2A"/>
</linearGradient>
<path class="st1" d="M122.9,49.9c-0.2-1.9-0.5-4.1-1.1-6.5c-0.6-2.4-1.6-5-2.9-7.8c-1.4-2.7-3.1-5.6-5.4-8.3
c-0.9-1.1-1.9-2.1-2.9-3.2c1.6-6.3-1.9-11.8-1.9-11.8c-6.1-0.4-9.9,1.9-11.3,2.9c-0.2-0.1-0.5-0.2-0.7-0.3c-1-0.4-2.1-0.8-3.2-1.2
c-1.1-0.3-2.2-0.7-3.3-0.9c-1.1-0.3-2.3-0.5-3.5-0.7c-0.2,0-0.4-0.1-0.6-0.1C83.5,3.6,75.9,0,75.9,0c-8.7,5.6-10.4,13.1-10.4,13.1
s0,0.2-0.1,0.4c-0.5,0.1-0.9,0.3-1.4,0.4c-0.6,0.2-1.3,0.4-1.9,0.7c-0.6,0.3-1.3,0.5-1.9,0.8c-1.3,0.6-2.5,1.2-3.8,1.9
c-1.2,0.7-2.4,1.4-3.5,2.2c-0.2-0.1-0.3-0.2-0.3-0.2c-11.7-4.5-22.1,0.9-22.1,0.9c-0.9,12.5,4.7,20.3,5.8,21.7
c-0.3,0.8-0.5,1.5-0.8,2.3c-0.9,2.8-1.5,5.7-1.9,8.7c-0.1,0.4-0.1,0.9-0.2,1.3c-10.8,5.3-14,16.3-14,16.3c9,10.4,19.6,11,19.6,11
l0,0c1.3,2.4,2.9,4.7,4.6,6.8c0.7,0.9,1.5,1.7,2.3,2.6c-3.3,9.4,0.5,17.3,0.5,17.3c10.1,0.4,16.7-4.4,18.1-5.5c1,0.3,2,0.6,3,0.9
c3.1,0.8,6.3,1.3,9.4,1.4c0.8,0,1.6,0,2.4,0h0.4H80h0.5H81l0,0c4.7,6.8,13.1,7.7,13.1,7.7c5.9-6.3,6.3-12.4,6.3-13.8l0,0
c0,0,0,0,0-0.1s0-0.2,0-0.2l0,0c0-0.1,0-0.2,0-0.3c1.2-0.9,2.4-1.8,3.6-2.8c2.4-2.1,4.4-4.6,6.2-7.2c0.2-0.2,0.3-0.5,0.5-0.7
c6.7,0.4,11.4-4.2,11.4-4.2c-1.1-7-5.1-10.4-5.9-11l0,0c0,0,0,0-0.1-0.1l-0.1-0.1l0,0l-0.1-0.1c0-0.4,0.1-0.8,0.1-1.3
c0.1-0.8,0.1-1.5,0.1-2.3v-0.6v-0.3v-0.1c0-0.2,0-0.1,0-0.2v-0.5v-0.6c0-0.2,0-0.4,0-0.6s0-0.4-0.1-0.6l-0.1-0.6l-0.1-0.6
c-0.1-0.8-0.3-1.5-0.4-2.3c-0.7-3-1.9-5.9-3.4-8.4c-1.6-2.6-3.5-4.8-5.7-6.8c-2.2-1.9-4.6-3.5-7.2-4.6c-2.6-1.2-5.2-1.9-7.9-2.2
c-1.3-0.2-2.7-0.2-4-0.2h-0.5h-0.1h-0.2h-0.2h-0.5c-0.2,0-0.4,0-0.5,0c-0.7,0.1-1.4,0.2-2,0.3c-2.7,0.5-5.2,1.5-7.4,2.8
c-2.2,1.3-4.1,3-5.7,4.9s-2.8,3.9-3.6,6.1c-0.8,2.1-1.3,4.4-1.4,6.5c0,0.5,0,1.1,0,1.6c0,0.1,0,0.3,0,0.4v0.4c0,0.3,0,0.5,0.1,0.8
c0.1,1.1,0.3,2.1,0.6,3.1c0.6,2,1.5,3.8,2.7,5.4s2.5,2.8,4,3.8s3,1.7,4.6,2.2c1.6,0.5,3.1,0.7,4.5,0.6c0.2,0,0.4,0,0.5,0
c0.1,0,0.2,0,0.3,0s0.2,0,0.3,0c0.2,0,0.3,0,0.5,0h0.1h0.1c0.1,0,0.2,0,0.3,0c0.2,0,0.4-0.1,0.5-0.1c0.2,0,0.3-0.1,0.5-0.1
c0.3-0.1,0.7-0.2,1-0.3c0.6-0.2,1.2-0.5,1.8-0.7c0.6-0.3,1.1-0.6,1.5-0.9c0.1-0.1,0.3-0.2,0.4-0.3c0.5-0.4,0.6-1.1,0.2-1.6
c-0.4-0.4-1-0.5-1.5-0.3C88,74,87.9,74,87.7,74.1c-0.4,0.2-0.9,0.4-1.3,0.5c-0.5,0.1-1,0.3-1.5,0.4c-0.3,0-0.5,0.1-0.8,0.1
c-0.1,0-0.3,0-0.4,0c-0.1,0-0.3,0-0.4,0s-0.3,0-0.4,0c-0.2,0-0.3,0-0.5,0c0,0-0.1,0,0,0h-0.1h-0.1c-0.1,0-0.1,0-0.2,0
s-0.3,0-0.4-0.1c-1.1-0.2-2.3-0.5-3.4-1c-1.1-0.5-2.2-1.2-3.1-2.1c-1-0.9-1.8-1.9-2.5-3.1c-0.7-1.2-1.1-2.5-1.3-3.8
c-0.1-0.7-0.2-1.4-0.1-2.1c0-0.2,0-0.4,0-0.6c0,0.1,0,0,0,0v-0.1v-0.1c0-0.1,0-0.2,0-0.3c0-0.4,0.1-0.7,0.2-1.1c0.5-3,2-5.9,4.3-8.1
c0.6-0.6,1.2-1.1,1.9-1.5c0.7-0.5,1.4-0.9,2.1-1.2c0.7-0.3,1.5-0.6,2.3-0.8s1.6-0.4,2.4-0.4c0.4,0,0.8-0.1,1.2-0.1
c0.1,0,0.2,0,0.3,0h0.3h0.2c0.1,0,0,0,0,0h0.1h0.3c0.9,0.1,1.8,0.2,2.6,0.4c1.7,0.4,3.4,1,5,1.9c3.2,1.8,5.9,4.5,7.5,7.8
c0.8,1.6,1.4,3.4,1.7,5.3c0.1,0.5,0.1,0.9,0.2,1.4v0.3V66c0,0.1,0,0.2,0,0.3c0,0.1,0,0.2,0,0.3v0.3v0.3c0,0.2,0,0.6,0,0.8
c0,0.5-0.1,1-0.1,1.5c-0.1,0.5-0.1,1-0.2,1.5s-0.2,1-0.3,1.5c-0.2,1-0.6,1.9-0.9,2.9c-0.7,1.9-1.7,3.7-2.9,5.3
c-2.4,3.3-5.7,6-9.4,7.7c-1.9,0.8-3.8,1.5-5.8,1.8c-1,0.2-2,0.3-3,0.3H81h-0.2h-0.3H80h-0.3c0.1,0,0,0,0,0h-0.1
c-0.5,0-1.1,0-1.6-0.1c-2.2-0.2-4.3-0.6-6.4-1.2c-2.1-0.6-4.1-1.4-6-2.4c-3.8-2-7.2-4.9-9.9-8.2c-1.3-1.7-2.5-3.5-3.5-5.4
s-1.7-3.9-2.3-5.9c-0.6-2-0.9-4.1-1-6.2v-0.4v-0.1v-0.1v-0.2V60v-0.1v-0.1v-0.2v-0.5V59l0,0v-0.2c0-0.3,0-0.5,0-0.8
c0-1,0.1-2.1,0.3-3.2c0.1-1.1,0.3-2.1,0.5-3.2c0.2-1.1,0.5-2.1,0.8-3.2c0.6-2.1,1.3-4.1,2.2-6c1.8-3.8,4.1-7.2,6.8-9.9
c0.7-0.7,1.4-1.3,2.2-1.9c0.3-0.3,1-0.9,1.8-1.4c0.8-0.5,1.6-1,2.5-1.4c0.4-0.2,0.8-0.4,1.3-0.6c0.2-0.1,0.4-0.2,0.7-0.3
c0.2-0.1,0.4-0.2,0.7-0.3c0.9-0.4,1.8-0.7,2.7-1c0.2-0.1,0.5-0.1,0.7-0.2c0.2-0.1,0.5-0.1,0.7-0.2c0.5-0.1,0.9-0.2,1.4-0.4
c0.2-0.1,0.5-0.1,0.7-0.2c0.2,0,0.5-0.1,0.7-0.1c0.2,0,0.5-0.1,0.7-0.1l0.4-0.1l0.4-0.1c0.2,0,0.5-0.1,0.7-0.1
c0.3,0,0.5-0.1,0.8-0.1c0.2,0,0.6-0.1,0.8-0.1c0.2,0,0.3,0,0.5-0.1h0.3h0.2h0.2c0.3,0,0.5,0,0.8-0.1h0.4c0,0,0.1,0,0,0h0.1h0.2
c0.2,0,0.5,0,0.7,0c0.9,0,1.8,0,2.7,0c1.8,0.1,3.6,0.3,5.3,0.6c3.4,0.6,6.7,1.7,9.6,3.2c2.9,1.4,5.6,3.2,7.8,5.1
c0.1,0.1,0.3,0.2,0.4,0.4c0.1,0.1,0.3,0.2,0.4,0.4c0.3,0.2,0.5,0.5,0.8,0.7c0.3,0.2,0.5,0.5,0.8,0.7c0.2,0.3,0.5,0.5,0.7,0.8
c1,1,1.9,2.1,2.7,3.1c1.6,2.1,2.9,4.2,3.9,6.2c0.1,0.1,0.1,0.2,0.2,0.4c0.1,0.1,0.1,0.2,0.2,0.4s0.2,0.5,0.4,0.7
c0.1,0.2,0.2,0.5,0.3,0.7c0.1,0.2,0.2,0.5,0.3,0.7c0.4,0.9,0.7,1.8,1,2.7c0.5,1.4,0.8,2.6,1.1,3.6c0.1,0.4,0.5,0.7,0.9,0.7
c0.5,0,0.8-0.4,0.8-0.9C123,52.7,123,51.4,122.9,49.9z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 142.5 145.6" style="enable-background:new 0 0 142.5 145.6;" xml:space="preserve">
<style type="text/css">
.st0{fill:#565656;}
.st1{fill:url(#SVGID_1_);}
</style>
<g>
<path class="st0" d="M28.7,131.5c-0.3,7.9-6.6,14.1-14.4,14.1C6.1,145.6,0,139,0,130.9s6.6-14.7,14.7-14.7c3.6,0,7.2,1.6,10.2,4.4
l-2.3,2.9c-2.3-2-5.1-3.4-7.9-3.4c-5.9,0-10.8,4.8-10.8,10.8c0,6.1,4.6,10.8,10.4,10.8c5.2,0,9.3-3.8,10.2-8.8H12.6v-3.5h16.1
V131.5z"/>
<path class="st0" d="M42.3,129.5h-2.2c-2.4,0-4.4,2-4.4,4.4v11.4h-3.9v-19.6H35v1.6c1.1-1.1,2.7-1.6,4.6-1.6h4.2L42.3,129.5z"/>
<path class="st0" d="M63.7,145.3h-3.4v-2.5c-2.6,2.5-6.6,3.7-10.7,1.9c-3-1.3-5.3-4.1-5.9-7.4c-1.2-6.3,3.7-11.9,9.9-11.9
c2.6,0,5,1.1,6.7,2.8v-2.5h3.4V145.3z M59.7,137c0.9-4-2.1-7.6-6-7.6c-3.4,0-6.1,2.8-6.1,6.1c0,3.8,3.3,6.7,7.2,6.1
C57.1,141.2,59.1,139.3,59.7,137z"/>
<path class="st0" d="M71.5,124.7v1.1h6.2v3.4h-6.2v16.1h-3.8v-20.5c0-4.3,3.1-6.8,7-6.8h4.7l-1.6,3.7h-3.1
C72.9,121.6,71.5,123,71.5,124.7z"/>
<path class="st0" d="M98.5,145.3h-3.3v-2.5c-2.6,2.5-6.6,3.7-10.7,1.9c-3-1.3-5.3-4.1-5.9-7.4c-1.2-6.3,3.7-11.9,9.9-11.9
c2.6,0,5,1.1,6.7,2.8v-2.5h3.4v19.6H98.5z M94.5,137c0.9-4-2.1-7.6-6-7.6c-3.4,0-6.1,2.8-6.1,6.1c0,3.8,3.3,6.7,7.2,6.1
C92,141.2,93.9,139.3,94.5,137z"/>
<path class="st0" d="M119.4,133.8v11.5h-3.9v-11.6c0-2.4-2-4.4-4.4-4.4c-2.5,0-4.4,2-4.4,4.4v11.6h-3.9v-19.6h3.2v1.7
c1.4-1.3,3.3-2,5.2-2C115.8,125.5,119.4,129.2,119.4,133.8z"/>
<path class="st0" d="M142.4,145.3h-3.3v-2.5c-2.6,2.5-6.6,3.7-10.7,1.9c-3-1.3-5.3-4.1-5.9-7.4c-1.2-6.3,3.7-11.9,9.9-11.9
c2.6,0,5,1.1,6.7,2.8v-2.5h3.4v19.6H142.4z M138.4,137c0.9-4-2.1-7.6-6-7.6c-3.4,0-6.1,2.8-6.1,6.1c0,3.8,3.3,6.7,7.2,6.1
C135.9,141.2,137.8,139.3,138.4,137z"/>
</g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="71.25" y1="10.4893" x2="71.25" y2="113.3415" gradientTransform="matrix(1 0 0 -1 0 148.6)">
<stop offset="0" style="stop-color:#FCEE1F"/>
<stop offset="1" style="stop-color:#F15B2A"/>
</linearGradient>
<path class="st1" d="M122.9,49.9c-0.2-1.9-0.5-4.1-1.1-6.5c-0.6-2.4-1.6-5-2.9-7.8c-1.4-2.7-3.1-5.6-5.4-8.3
c-0.9-1.1-1.9-2.1-2.9-3.2c1.6-6.3-1.9-11.8-1.9-11.8c-6.1-0.4-9.9,1.9-11.3,2.9c-0.2-0.1-0.5-0.2-0.7-0.3c-1-0.4-2.1-0.8-3.2-1.2
c-1.1-0.3-2.2-0.7-3.3-0.9c-1.1-0.3-2.3-0.5-3.5-0.7c-0.2,0-0.4-0.1-0.6-0.1C83.5,3.6,75.9,0,75.9,0c-8.7,5.6-10.4,13.1-10.4,13.1
s0,0.2-0.1,0.4c-0.5,0.1-0.9,0.3-1.4,0.4c-0.6,0.2-1.3,0.4-1.9,0.7c-0.6,0.3-1.3,0.5-1.9,0.8c-1.3,0.6-2.5,1.2-3.8,1.9
c-1.2,0.7-2.4,1.4-3.5,2.2c-0.2-0.1-0.3-0.2-0.3-0.2c-11.7-4.5-22.1,0.9-22.1,0.9c-0.9,12.5,4.7,20.3,5.8,21.7
c-0.3,0.8-0.5,1.5-0.8,2.3c-0.9,2.8-1.5,5.7-1.9,8.7c-0.1,0.4-0.1,0.9-0.2,1.3c-10.8,5.3-14,16.3-14,16.3c9,10.4,19.6,11,19.6,11
l0,0c1.3,2.4,2.9,4.7,4.6,6.8c0.7,0.9,1.5,1.7,2.3,2.6c-3.3,9.4,0.5,17.3,0.5,17.3c10.1,0.4,16.7-4.4,18.1-5.5c1,0.3,2,0.6,3,0.9
c3.1,0.8,6.3,1.3,9.4,1.4c0.8,0,1.6,0,2.4,0h0.4H80h0.5H81l0,0c4.7,6.8,13.1,7.7,13.1,7.7c5.9-6.3,6.3-12.4,6.3-13.8l0,0
c0,0,0,0,0-0.1s0-0.2,0-0.2l0,0c0-0.1,0-0.2,0-0.3c1.2-0.9,2.4-1.8,3.6-2.8c2.4-2.1,4.4-4.6,6.2-7.2c0.2-0.2,0.3-0.5,0.5-0.7
c6.7,0.4,11.4-4.2,11.4-4.2c-1.1-7-5.1-10.4-5.9-11l0,0c0,0,0,0-0.1-0.1l-0.1-0.1l0,0l-0.1-0.1c0-0.4,0.1-0.8,0.1-1.3
c0.1-0.8,0.1-1.5,0.1-2.3v-0.6v-0.3v-0.1c0-0.2,0-0.1,0-0.2v-0.5v-0.6c0-0.2,0-0.4,0-0.6s0-0.4-0.1-0.6l-0.1-0.6l-0.1-0.6
c-0.1-0.8-0.3-1.5-0.4-2.3c-0.7-3-1.9-5.9-3.4-8.4c-1.6-2.6-3.5-4.8-5.7-6.8c-2.2-1.9-4.6-3.5-7.2-4.6c-2.6-1.2-5.2-1.9-7.9-2.2
c-1.3-0.2-2.7-0.2-4-0.2h-0.5h-0.1h-0.2h-0.2h-0.5c-0.2,0-0.4,0-0.5,0c-0.7,0.1-1.4,0.2-2,0.3c-2.7,0.5-5.2,1.5-7.4,2.8
c-2.2,1.3-4.1,3-5.7,4.9s-2.8,3.9-3.6,6.1c-0.8,2.1-1.3,4.4-1.4,6.5c0,0.5,0,1.1,0,1.6c0,0.1,0,0.3,0,0.4v0.4c0,0.3,0,0.5,0.1,0.8
c0.1,1.1,0.3,2.1,0.6,3.1c0.6,2,1.5,3.8,2.7,5.4s2.5,2.8,4,3.8s3,1.7,4.6,2.2c1.6,0.5,3.1,0.7,4.5,0.6c0.2,0,0.4,0,0.5,0
c0.1,0,0.2,0,0.3,0s0.2,0,0.3,0c0.2,0,0.3,0,0.5,0h0.1h0.1c0.1,0,0.2,0,0.3,0c0.2,0,0.4-0.1,0.5-0.1c0.2,0,0.3-0.1,0.5-0.1
c0.3-0.1,0.7-0.2,1-0.3c0.6-0.2,1.2-0.5,1.8-0.7c0.6-0.3,1.1-0.6,1.5-0.9c0.1-0.1,0.3-0.2,0.4-0.3c0.5-0.4,0.6-1.1,0.2-1.6
c-0.4-0.4-1-0.5-1.5-0.3C88,74,87.9,74,87.7,74.1c-0.4,0.2-0.9,0.4-1.3,0.5c-0.5,0.1-1,0.3-1.5,0.4c-0.3,0-0.5,0.1-0.8,0.1
c-0.1,0-0.3,0-0.4,0c-0.1,0-0.3,0-0.4,0s-0.3,0-0.4,0c-0.2,0-0.3,0-0.5,0c0,0-0.1,0,0,0h-0.1h-0.1c-0.1,0-0.1,0-0.2,0
s-0.3,0-0.4-0.1c-1.1-0.2-2.3-0.5-3.4-1c-1.1-0.5-2.2-1.2-3.1-2.1c-1-0.9-1.8-1.9-2.5-3.1c-0.7-1.2-1.1-2.5-1.3-3.8
c-0.1-0.7-0.2-1.4-0.1-2.1c0-0.2,0-0.4,0-0.6c0,0.1,0,0,0,0v-0.1v-0.1c0-0.1,0-0.2,0-0.3c0-0.4,0.1-0.7,0.2-1.1c0.5-3,2-5.9,4.3-8.1
c0.6-0.6,1.2-1.1,1.9-1.5c0.7-0.5,1.4-0.9,2.1-1.2c0.7-0.3,1.5-0.6,2.3-0.8s1.6-0.4,2.4-0.4c0.4,0,0.8-0.1,1.2-0.1
c0.1,0,0.2,0,0.3,0h0.3h0.2c0.1,0,0,0,0,0h0.1h0.3c0.9,0.1,1.8,0.2,2.6,0.4c1.7,0.4,3.4,1,5,1.9c3.2,1.8,5.9,4.5,7.5,7.8
c0.8,1.6,1.4,3.4,1.7,5.3c0.1,0.5,0.1,0.9,0.2,1.4v0.3V66c0,0.1,0,0.2,0,0.3c0,0.1,0,0.2,0,0.3v0.3v0.3c0,0.2,0,0.6,0,0.8
c0,0.5-0.1,1-0.1,1.5c-0.1,0.5-0.1,1-0.2,1.5s-0.2,1-0.3,1.5c-0.2,1-0.6,1.9-0.9,2.9c-0.7,1.9-1.7,3.7-2.9,5.3
c-2.4,3.3-5.7,6-9.4,7.7c-1.9,0.8-3.8,1.5-5.8,1.8c-1,0.2-2,0.3-3,0.3H81h-0.2h-0.3H80h-0.3c0.1,0,0,0,0,0h-0.1
c-0.5,0-1.1,0-1.6-0.1c-2.2-0.2-4.3-0.6-6.4-1.2c-2.1-0.6-4.1-1.4-6-2.4c-3.8-2-7.2-4.9-9.9-8.2c-1.3-1.7-2.5-3.5-3.5-5.4
s-1.7-3.9-2.3-5.9c-0.6-2-0.9-4.1-1-6.2v-0.4v-0.1v-0.1v-0.2V60v-0.1v-0.1v-0.2v-0.5V59l0,0v-0.2c0-0.3,0-0.5,0-0.8
c0-1,0.1-2.1,0.3-3.2c0.1-1.1,0.3-2.1,0.5-3.2c0.2-1.1,0.5-2.1,0.8-3.2c0.6-2.1,1.3-4.1,2.2-6c1.8-3.8,4.1-7.2,6.8-9.9
c0.7-0.7,1.4-1.3,2.2-1.9c0.3-0.3,1-0.9,1.8-1.4c0.8-0.5,1.6-1,2.5-1.4c0.4-0.2,0.8-0.4,1.3-0.6c0.2-0.1,0.4-0.2,0.7-0.3
c0.2-0.1,0.4-0.2,0.7-0.3c0.9-0.4,1.8-0.7,2.7-1c0.2-0.1,0.5-0.1,0.7-0.2c0.2-0.1,0.5-0.1,0.7-0.2c0.5-0.1,0.9-0.2,1.4-0.4
c0.2-0.1,0.5-0.1,0.7-0.2c0.2,0,0.5-0.1,0.7-0.1c0.2,0,0.5-0.1,0.7-0.1l0.4-0.1l0.4-0.1c0.2,0,0.5-0.1,0.7-0.1
c0.3,0,0.5-0.1,0.8-0.1c0.2,0,0.6-0.1,0.8-0.1c0.2,0,0.3,0,0.5-0.1h0.3h0.2h0.2c0.3,0,0.5,0,0.8-0.1h0.4c0,0,0.1,0,0,0h0.1h0.2
c0.2,0,0.5,0,0.7,0c0.9,0,1.8,0,2.7,0c1.8,0.1,3.6,0.3,5.3,0.6c3.4,0.6,6.7,1.7,9.6,3.2c2.9,1.4,5.6,3.2,7.8,5.1
c0.1,0.1,0.3,0.2,0.4,0.4c0.1,0.1,0.3,0.2,0.4,0.4c0.3,0.2,0.5,0.5,0.8,0.7c0.3,0.2,0.5,0.5,0.8,0.7c0.2,0.3,0.5,0.5,0.7,0.8
c1,1,1.9,2.1,2.7,3.1c1.6,2.1,2.9,4.2,3.9,6.2c0.1,0.1,0.1,0.2,0.2,0.4c0.1,0.1,0.1,0.2,0.2,0.4s0.2,0.5,0.4,0.7
c0.1,0.2,0.2,0.5,0.3,0.7c0.1,0.2,0.2,0.5,0.3,0.7c0.4,0.9,0.7,1.8,1,2.7c0.5,1.4,0.8,2.6,1.1,3.6c0.1,0.4,0.5,0.7,0.9,0.7
c0.5,0,0.8-0.4,0.8-0.9C123,52.7,123,51.4,122.9,49.9z"/>
</svg>

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@@ -1,21 +1,21 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 512 512" xml:space="preserve">
<polygon style="fill:#FFD500;" points="382.395,228.568 291.215,228.568 330.762,10.199 129.603,283.43 220.785,283.43
181.238,501.799 "/>
<g>
<path style="fill:#3D3D3D;" d="M181.234,512c-1.355,0-2.726-0.271-4.033-0.833c-4.357-1.878-6.845-6.514-5.999-11.184
l37.371-206.353h-78.969c-3.846,0-7.367-2.164-9.103-5.597c-1.735-3.433-1.391-7.55,0.889-10.648L322.548,4.153
c2.814-3.822,7.891-5.196,12.25-3.32c4.357,1.878,6.845,6.514,5.999,11.184L303.427,218.37h78.969c3.846,0,7.367,2.164,9.103,5.597
c1.735,3.433,1.391,7.55-0.889,10.648L189.451,507.846C187.481,510.523,184.399,512,181.234,512z M149.777,273.231h71.007
c3.023,0,5.89,1.341,7.828,3.662c1.938,2.32,2.747,5.38,2.208,8.355l-31.704,175.065l163.105-221.545h-71.007
c-3.023,0-5.89-1.341-7.828-3.661c-1.938-2.32-2.747-5.38-2.208-8.355l31.704-175.065L149.777,273.231z"/>
<path style="fill:#3D3D3D;" d="M267.666,171.348c-0.604,0-1.215-0.054-1.829-0.165c-5.543-1.004-9.223-6.31-8.22-11.853l0.923-5.1
c1.003-5.543,6.323-9.225,11.852-8.219c5.543,1.004,9.223,6.31,8.22,11.853l-0.923,5.1
C276.797,167.892,272.503,171.348,267.666,171.348z"/>
<path style="fill:#3D3D3D;" d="M255.455,238.77c-0.604,0-1.215-0.054-1.83-0.165c-5.543-1.004-9.222-6.31-8.218-11.853
l7.037-38.864c1.004-5.543,6.317-9.225,11.854-8.219c5.543,1.004,9.222,6.31,8.219,11.853l-7.037,38.864
C264.587,235.314,260.293,238.77,255.455,238.77z"/>
</g>
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 512 512" xml:space="preserve">
<polygon style="fill:#FFD500;" points="382.395,228.568 291.215,228.568 330.762,10.199 129.603,283.43 220.785,283.43
181.238,501.799 "/>
<g>
<path style="fill:#3D3D3D;" d="M181.234,512c-1.355,0-2.726-0.271-4.033-0.833c-4.357-1.878-6.845-6.514-5.999-11.184
l37.371-206.353h-78.969c-3.846,0-7.367-2.164-9.103-5.597c-1.735-3.433-1.391-7.55,0.889-10.648L322.548,4.153
c2.814-3.822,7.891-5.196,12.25-3.32c4.357,1.878,6.845,6.514,5.999,11.184L303.427,218.37h78.969c3.846,0,7.367,2.164,9.103,5.597
c1.735,3.433,1.391,7.55-0.889,10.648L189.451,507.846C187.481,510.523,184.399,512,181.234,512z M149.777,273.231h71.007
c3.023,0,5.89,1.341,7.828,3.662c1.938,2.32,2.747,5.38,2.208,8.355l-31.704,175.065l163.105-221.545h-71.007
c-3.023,0-5.89-1.341-7.828-3.661c-1.938-2.32-2.747-5.38-2.208-8.355l31.704-175.065L149.777,273.231z"/>
<path style="fill:#3D3D3D;" d="M267.666,171.348c-0.604,0-1.215-0.054-1.829-0.165c-5.543-1.004-9.223-6.31-8.22-11.853l0.923-5.1
c1.003-5.543,6.323-9.225,11.852-8.219c5.543,1.004,9.223,6.31,8.22,11.853l-0.923,5.1
C276.797,167.892,272.503,171.348,267.666,171.348z"/>
<path style="fill:#3D3D3D;" d="M255.455,238.77c-0.604,0-1.215-0.054-1.83-0.165c-5.543-1.004-9.222-6.31-8.218-11.853
l7.037-38.864c1.004-5.543,6.317-9.225,11.854-8.219c5.543,1.004,9.222,6.31,8.219,11.853l-7.037,38.864
C264.587,235.314,260.293,238.77,255.455,238.77z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -9,7 +9,7 @@ jest.mock('../../../api/browser/localstorage/get', () => ({
}));
// Access the mocked function
const mockGet = getLocal as unknown as jest.Mock;
const mockGet = (getLocal as unknown) as jest.Mock;
describe('AppLoading', () => {
const SIGNOZ_TEXT = 'SigNoz';

View File

@@ -31,8 +31,9 @@ export function FilterSelect({
onChange,
isMultiple,
}: SelectOptionConfig): JSX.Element {
const { handleSearch, isFetching, options } =
useCeleryFilterOptions(filterType);
const { handleSearch, isFetching, options } = useCeleryFilterOptions(
filterType,
);
const urlQuery = useUrlQuery();
const history = useHistory();

View File

@@ -280,28 +280,30 @@ function getTableData(data: QueueOverviewResponse['data']): RowData[] {
];
const tableData: RowData[] =
data?.map((row, index: number): RowData => {
const rowData: Record<string, string | number> = {};
columnOrder.forEach((key) => {
const value = row.data[key as keyof typeof row.data];
if (typeof value === 'string' || typeof value === 'number') {
rowData[key] = value;
}
});
Object.entries(row.data).forEach(([key, value]) => {
if (
!columnOrder.includes(key) &&
(typeof value === 'string' || typeof value === 'number')
) {
rowData[key] = value;
}
});
data?.map(
(row, index: number): RowData => {
const rowData: Record<string, string | number> = {};
columnOrder.forEach((key) => {
const value = row.data[key as keyof typeof row.data];
if (typeof value === 'string' || typeof value === 'number') {
rowData[key] = value;
}
});
Object.entries(row.data).forEach(([key, value]) => {
if (
!columnOrder.includes(key) &&
(typeof value === 'string' || typeof value === 'number')
) {
rowData[key] = value;
}
});
return {
...rowData,
key: index,
};
}) || [];
return {
...rowData,
key: index,
};
},
) || [];
return tableData;
}
@@ -478,10 +480,10 @@ export default function CeleryOverviewTable({
[searchText],
);
const filteredData = useMemo(
() => getFilteredData(tableData),
[getFilteredData, tableData],
);
const filteredData = useMemo(() => getFilteredData(tableData), [
getFilteredData,
tableData,
]);
const prevTableDataRef = useRef<string>();

View File

@@ -13,8 +13,9 @@ import { useCeleryFilterOptions } from '../useCeleryFilterOptions';
import './CeleryTaskConfigOptions.styles.scss';
function CeleryTaskConfigOptions(): JSX.Element {
const { handleSearch, isFetching, options } =
useCeleryFilterOptions('celery.task_name');
const { handleSearch, isFetching, options } = useCeleryFilterOptions(
'celery.task_name',
);
const history = useHistory();
const location = useLocation();

View File

@@ -469,7 +469,8 @@ export const celeryActiveTasksWidgetData = (
{
aggregateAttribute: {
dataType: DataTypes.Float64,
id: 'flower_worker_number_of_currently_executing_tasks--float64--Gauge--true',
id:
'flower_worker_number_of_currently_executing_tasks--float64--Gauge--true',
key: 'flower_worker_number_of_currently_executing_tasks',
type: 'Gauge',
},

View File

@@ -127,17 +127,22 @@ function CeleryTaskLatencyGraph({
const onGraphClickHandler = useGraphClickHandler(handleSetTimeStamp);
const onGraphClick = useCallback(
(type: string): OnClickPluginOpts['onClick'] =>
(xValue, yValue, mouseX, mouseY, data): Promise<void> => {
const [firstDataPoint] = Object.entries(data || {});
const [entity, value] = firstDataPoint;
setEntityData({
entity,
value,
});
(type: string): OnClickPluginOpts['onClick'] => (
xValue,
yValue,
mouseX,
mouseY,
data,
): Promise<void> => {
const [firstDataPoint] = Object.entries(data || {});
const [entity, value] = firstDataPoint;
setEntityData({
entity,
value,
});
return onGraphClickHandler(xValue, yValue, mouseX, mouseY, type);
},
return onGraphClickHandler(xValue, yValue, mouseX, mouseY, type);
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[handleSetTimeStamp],
);

View File

@@ -92,10 +92,10 @@ function CeleryTaskStateGraphConfig({
{isLoading
? '-'
: isError
? '-'
: Number.isNaN(values[index])
? '-'
: Math.round(Number(values[index]))}
? '-'
: Number.isNaN(values[index])
? '-'
: Math.round(Number(values[index]))}
</div>
</div>
{tab.key === barState && <div className="celery-task-states__indicator" />}

View File

@@ -65,7 +65,7 @@ export function applyCeleryFilterOnWidgetData(
items: [...(queryItem.filters?.items || []), ...filters],
op: queryItem.filters?.op || 'AND',
},
}
}
: queryItem,
),
},

View File

@@ -9,7 +9,7 @@ import { paths } from './CeleryUtils';
interface UseGetGraphCustomSeriesProps {
isDarkMode: boolean;
drawStyle?: (typeof drawStyles)[keyof typeof drawStyles];
drawStyle?: typeof drawStyles[keyof typeof drawStyles];
colorMapping?: Record<string, string>;
}

View File

@@ -37,8 +37,9 @@ function ChangelogModal({ changelog, onClose }: Props): JSX.Element {
preference.name === USER_PREFERENCES.LAST_SEEN_CHANGELOG_VERSION,
)?.value as string;
const { mutate: updateUserPreferenceMutation } =
useMutation(updateUserPreference);
const { mutate: updateUserPreferenceMutation } = useMutation(
updateUserPreference,
);
useEffect(() => {
// Update the seen version
@@ -59,8 +60,11 @@ function ChangelogModal({ changelog, onClose }: Props): JSX.Element {
const checkScroll = useCallback((): void => {
if (changelogContentSectionRef.current) {
const { scrollHeight, clientHeight, scrollTop } =
changelogContentSectionRef.current;
const {
scrollHeight,
clientHeight,
scrollTop,
} = changelogContentSectionRef.current;
const isAtBottom = scrollHeight - clientHeight - scrollTop <= 8;
setHasScroll(scrollHeight > clientHeight + 24 && !isAtBottom); // 24px - buffer height to show show more
}

View File

@@ -14,8 +14,9 @@ import { getBaseUrl } from 'utils/basePath';
export default function ChatSupportGateway(): JSX.Element {
const { notifications } = useNotifications();
const [isAddCreditCardModalOpen, setIsAddCreditCardModalOpen] =
useState(false);
const [isAddCreditCardModalOpen, setIsAddCreditCardModalOpen] = useState(
false,
);
const handleBillingOnSuccess = (
data: SuccessResponseV2<CheckoutSuccessPayloadProps>,

View File

@@ -388,7 +388,7 @@ function ClientSideQBSearch(
({
label: key.key,
value: key,
}) as Option,
} as Option),
) || [],
);
}
@@ -462,7 +462,7 @@ function ClientSideQBSearch(
({
label: checkCommaInValue(String(val)),
value: val,
}) as Option,
} as Option),
),
);
} else {
@@ -490,7 +490,7 @@ function ClientSideQBSearch(
Array.isArray(tag.value) &&
tag.value[tag.value.length - 1] === ''
? tag.value?.slice(0, -1)
: (tag.value ?? '');
: tag.value ?? '';
filterTags.items.push({
id: tag.id || uuid().slice(0, 8),
key: tag.key,

View File

@@ -47,23 +47,25 @@ function CreateServiceAccountModal(): JSX.Element {
},
});
const { mutate: createServiceAccount, isLoading: isSubmitting } =
useCreateServiceAccount({
mutation: {
onSuccess: async () => {
toast.success('Service account created successfully');
reset();
await setIsOpen(null);
await invalidateListServiceAccounts(queryClient);
},
onError: (err) => {
const errMessage = convertToApiError(
err as AxiosError<RenderErrorResponseDTO, unknown> | null,
);
showErrorModal(errMessage as APIError);
},
const {
mutate: createServiceAccount,
isLoading: isSubmitting,
} = useCreateServiceAccount({
mutation: {
onSuccess: async () => {
toast.success('Service account created successfully');
reset();
await setIsOpen(null);
await invalidateListServiceAccounts(queryClient);
},
});
onError: (err) => {
const errMessage = convertToApiError(
err as AxiosError<RenderErrorResponseDTO, unknown> | null,
);
showErrorModal(errMessage as APIError);
},
},
});
function handleClose(): void {
reset();

View File

@@ -96,8 +96,10 @@ function CustomTimePicker({
maxTime,
isModalTimeSelection = false,
}: CustomTimePickerProps): JSX.Element {
const [selectedTimePlaceholderValue, setSelectedTimePlaceholderValue] =
useState('Select / Enter Time Range');
const [
selectedTimePlaceholderValue,
setSelectedTimePlaceholderValue,
] = useState('Select / Enter Time Range');
const [inputValue, setInputValue] = useState('');
const [inputStatus, setInputStatus] = useState<CustomTimePickerInputStatus>(

View File

@@ -116,10 +116,9 @@ function CustomTimePickerPopoverContent({
}: CustomTimePickerPopoverContentProps): JSX.Element {
const { pathname } = useLocation();
const isLogsExplorerPage = useMemo(
() => pathname === ROUTES.LOGS_EXPLORER,
[pathname],
);
const isLogsExplorerPage = useMemo(() => pathname === ROUTES.LOGS_EXPLORER, [
pathname,
]);
const url = new URLSearchParams(window.location.search);
@@ -155,8 +154,8 @@ function CustomTimePickerPopoverContent({
if (!customDateTimeVisible) {
const customTimeRanges = getCustomTimeRanges();
const formattedCustomTimeRanges: RecentlyUsedDateTimeRange[] =
customTimeRanges.map((range) => ({
const formattedCustomTimeRanges: RecentlyUsedDateTimeRange[] = customTimeRanges.map(
(range) => ({
label: `${dayjs(range.from)
.tz(timezone.value)
.format(DATE_TIME_FORMATS.DD_MMM_YYYY_HH_MM_SS)} - ${dayjs(range.to)
@@ -166,7 +165,8 @@ function CustomTimePickerPopoverContent({
to: range.to,
value: range.timestamp,
timestamp: range.timestamp,
}));
}),
);
setRecentlyUsedTimeRanges(formattedCustomTimeRanges);
}

View File

@@ -19,7 +19,7 @@ const TIMEZONE_TYPES = {
STANDARD: 'STANDARD',
} as const;
type TimezoneType = (typeof TIMEZONE_TYPES)[keyof typeof TIMEZONE_TYPES];
type TimezoneType = typeof TIMEZONE_TYPES[keyof typeof TIMEZONE_TYPES];
export const UTC_TIMEZONE: Timezone = {
name: 'Coordinated Universal Time — UTC, GMT',

View File

@@ -41,7 +41,8 @@ function DraggableTableRow({
);
}
interface DraggableTableRowProps extends React.HTMLAttributes<HTMLTableRowElement> {
interface DraggableTableRowProps
extends React.HTMLAttributes<HTMLTableRowElement> {
index: number;
moveRow: (dragIndex: number, hoverIndex: number) => void;
}

View File

@@ -6,9 +6,9 @@ export function dropHandler(monitor: DropTargetMonitor): { isOver: boolean } {
};
}
export function dragHandler(monitor: DragSourceMonitor): {
isDragging: boolean;
} {
export function dragHandler(
monitor: DragSourceMonitor,
): { isDragging: boolean } {
return {
isDragging: monitor.isDragging(),
};

View File

@@ -158,8 +158,10 @@ function EditMemberDrawer({
new Date(String(existingToken.expiresAt)) < new Date();
// Create/regenerate token mutation
const { mutateAsync: createTokenMutation, isLoading: isGeneratingLink } =
useCreateResetPasswordToken();
const {
mutateAsync: createTokenMutation,
isLoading: isGeneratingLink,
} = useCreateResetPasswordToken();
const fetchedDisplayName =
fetchedUser?.data?.displayName ?? member?.name ?? '';
@@ -219,20 +221,22 @@ function EditMemberDrawer({
});
const makeRoleRetry = useCallback(
(context: string, rawRetry: () => Promise<void>) =>
async (): Promise<void> => {
try {
await rawRetry();
setSaveErrors((prev) => prev.filter((e) => e.context !== context));
refetchUser();
} catch (err) {
setSaveErrors((prev) =>
prev.map((e) =>
e.context === context ? { ...e, apiError: toSaveApiError(err) } : e,
),
);
}
},
(
context: string,
rawRetry: () => Promise<void>,
) => async (): Promise<void> => {
try {
await rawRetry();
setSaveErrors((prev) => prev.filter((e) => e.context !== context));
refetchUser();
} catch (err) {
setSaveErrors((prev) =>
prev.map((e) =>
e.context === context ? { ...e, apiError: toSaveApiError(err) } : e,
),
);
}
},
[refetchUser],
);
@@ -276,7 +280,7 @@ function EditMemberDrawer({
: updateUser({
pathParams: { id: member.id },
data: { displayName: localDisplayName },
})
})
: Promise.resolve();
const [nameResult, rolesResult] = await Promise.allSettled([
@@ -385,7 +389,7 @@ function EditMemberDrawer({
? formatTimezoneAdjustedTimestamp(
String(response.data.expiresAt),
DATE_TIME_FORMATS.DASH_DATETIME,
)
)
: null,
);
setHasCopiedResetLink(false);
@@ -494,8 +498,8 @@ function EditMemberDrawer({
isRootUser
? ROOT_USER_TOOLTIP
: isDeleted
? undefined
: 'You cannot modify your own role'
? undefined
: 'You cannot modify your own role'
}
>
<div className="edit-member-drawer__input-wrapper edit-member-drawer__input-wrapper--disabled">
@@ -618,13 +622,13 @@ function EditMemberDrawer({
{isGeneratingLink
? 'Generating...'
: isInvited
? getInviteButtonLabel(
isLoadingTokenStatus,
existingToken,
isTokenExpired,
tokenNotFound,
)
: 'Generate Password Reset Link'}
? getInviteButtonLabel(
isLoadingTokenStatus,
existingToken,
isTokenExpired,
tokenNotFound,
)
: 'Generate Password Reset Link'}
</Button>
</span>
</Tooltip>

View File

@@ -168,12 +168,9 @@
gap: 3px;
background: var(--l1-border);
border-radius: 20px;
box-shadow:
0px 103px 12px 0px rgba(0, 0, 0, 0.01),
0px 66px 18px 0px rgba(0, 0, 0, 0.01),
0px 37px 22px 0px rgba(0, 0, 0, 0.03),
0px 17px 17px 0px rgba(0, 0, 0, 0.04),
0px 4px 9px 0px rgba(0, 0, 0, 0.04);
box-shadow: 0px 103px 12px 0px rgba(0, 0, 0, 0.01),
0px 66px 18px 0px rgba(0, 0, 0, 0.01), 0px 37px 22px 0px rgba(0, 0, 0, 0.03),
0px 17px 17px 0px rgba(0, 0, 0, 0.04), 0px 4px 9px 0px rgba(0, 0, 0, 0.04);
}
&__scroll-hint-text {

View File

@@ -25,14 +25,15 @@ function ErrorContent({ error, icon }: ErrorContentProps): JSX.Element {
errors: errorMessages,
code: errorCode,
message: errorMessage,
} = error && 'error' in error
? error?.error?.error || {}
: {
url: undefined,
errors: [],
code: error.code || 500,
message: error.message || 'Something went wrong',
};
} =
error && 'error' in error
? error?.error?.error || {}
: {
url: undefined,
errors: [],
code: error.code || 500,
message: error.message || 'Something went wrong',
};
return (
<section className="error-content">
{/* Summary Header */}

View File

@@ -23,8 +23,11 @@ function MenuItemGenerator({
refetchAllView,
sourcePage,
}: MenuItemLabelGeneratorProps): JSX.Element {
const { panelType, redirectWithQueryBuilderData, updateAllQueriesOperators } =
useQueryBuilder();
const {
panelType,
redirectWithQueryBuilderData,
updateAllQueriesOperators,
} = useQueryBuilder();
const { handleExplorerTabChange } = useHandleExplorerTabChange();
const { notifications } = useNotifications();

View File

@@ -17,8 +17,11 @@ function SaveViewWithName({
}: SaveViewWithNameProps): JSX.Element {
const [form] = Form.useForm<SaveViewFormProps>();
const { t } = useTranslation(['explorer']);
const { currentQuery, panelType, redirectWithQueryBuilderData } =
useQueryBuilder();
const {
currentQuery,
panelType,
redirectWithQueryBuilderData,
} = useQueryBuilder();
const { notifications } = useNotifications();
const compositeQuery = mapCompositeQueryFromQuery(currentQuery, panelType);

View File

@@ -1,7 +1,8 @@
import { QueryParams } from 'constants/query';
export const ExploreHeaderToolTip = {
url: 'https://signoz.io/docs/userguide/query-builder/?utm_source=product&utm_medium=new-query-builder',
url:
'https://signoz.io/docs/userguide/query-builder/?utm_source=product&utm_medium=new-query-builder',
text: 'More details on how to use query builder',
};

View File

@@ -55,8 +55,9 @@ function createMousedownHandler(
startDragPositionX = right;
}
const startValuePositionX =
chart.scales.x.getValueForPixel(startDragPositionX);
const startValuePositionX = chart.scales.x.getValueForPixel(
startDragPositionX,
);
dragData.onDragStart(startDragPositionX, startValuePositionX);
};
@@ -108,8 +109,9 @@ function createMouseupHandler(
endRelativePostionX = right;
}
const endValuePositionX =
chart.scales.x.getValueForPixel(endRelativePostionX);
const endValuePositionX = chart.scales.x.getValueForPixel(
endRelativePostionX,
);
dragData.onDragEnd(endRelativePostionX, endValuePositionX);

View File

@@ -12,12 +12,11 @@ export type IntersectionCursorPluginOptions = {
gapSize?: number;
};
export const defaultIntersectionCursorPluginOptions: Required<IntersectionCursorPluginOptions> =
{
color: 'white',
dashSize: 3,
gapSize: 3,
};
export const defaultIntersectionCursorPluginOptions: Required<IntersectionCursorPluginOptions> = {
color: 'white',
dashSize: 3,
gapSize: 3,
};
export function createIntersectionCursorPluginOptions(
isEnabled: boolean,

View File

@@ -52,7 +52,7 @@ export const legend = (id: string, isLonger: boolean): Plugin<ChartType> => ({
])
? get(chart, ['options', 'plugins', 'legend', 'labels', 'generateLabels'])(
chart,
)
)
: null;
items?.forEach((item: Record<any, any>, index: number) => {

View File

@@ -95,7 +95,7 @@ export const getGraphOptions = (
},
],
},
}
}
: {}),
title: {
display: title !== undefined,

View File

@@ -177,9 +177,7 @@
color: var(--destructive);
opacity: 0.6;
padding: 0;
transition:
background-color 0.2s,
opacity 0.2s;
transition: background-color 0.2s, opacity 0.2s;
box-shadow: none;
&:hover {

View File

@@ -47,8 +47,9 @@ function LaunchChatSupport({
featureFlagsFetchError,
isLoggedIn,
} = useAppContext();
const [isAddCreditCardModalOpen, setIsAddCreditCardModalOpen] =
useState(false);
const [isAddCreditCardModalOpen, setIsAddCreditCardModalOpen] = useState(
false,
);
const { pathname } = useLocation();

View File

@@ -5,7 +5,7 @@ export const VIEW_TYPES = {
INFRAMETRICS: 'INFRAMETRICS',
} as const;
export type VIEWS = (typeof VIEW_TYPES)[keyof typeof VIEW_TYPES];
export type VIEWS = typeof VIEW_TYPES[keyof typeof VIEW_TYPES];
export const RESOURCE_KEYS = {
CLUSTER_NAME: 'k8s.cluster.name',

View File

@@ -261,7 +261,7 @@ function LogDetailInner({
...query.filter,
expression: value,
},
}
}
: query,
),
},

View File

@@ -20,10 +20,9 @@ function AddToQueryHOC({
onAddToQuery(fieldKey, fieldValue, OPERATORS['='], dataType);
};
const popOverContent = useMemo(
() => <span>Add to query: {fieldKey}</span>,
[fieldKey],
);
const popOverContent = useMemo(() => <span>Add to query: {fieldKey}</span>, [
fieldKey,
]);
return (
<div className={cx('addToQueryContainer', fontSize)} onClick={handleQueryAdd}>

View File

@@ -104,7 +104,7 @@ type ListLogViewProps = {
selectedFields: IField[];
onSetActiveLog: (
log: ILog,
selectedTab?: (typeof VIEW_TYPES)[keyof typeof VIEW_TYPES],
selectedTab?: typeof VIEW_TYPES[keyof typeof VIEW_TYPES],
) => void;
onAddToQuery: AddToQueryHOCProps['onAddToQuery'];
activeLog?: ILog | null;
@@ -166,11 +166,11 @@ function ListLogView({
? formatTimezoneAdjustedTimestamp(
flattenLogData.timestamp,
DATE_TIME_FORMATS.ISO_DATETIME_MS,
)
)
: formatTimezoneAdjustedTimestamp(
flattenLogData.timestamp / 1e6,
DATE_TIME_FORMATS.ISO_DATETIME_MS,
),
),
[flattenLogData.timestamp, formatTimezoneAdjustedTimestamp],
);

View File

@@ -24,10 +24,10 @@ export const Container = styled(Card)<{
fontSize === FontSize.SMALL
? `margin-bottom:0.1rem;`
: fontSize === FontSize.MEDIUM
? `margin-bottom: 0.2rem;`
: fontSize === FontSize.LARGE
? `margin-bottom:0.3rem;`
: ``}
? `margin-bottom: 0.2rem;`
: fontSize === FontSize.LARGE
? `margin-bottom:0.3rem;`
: ``}
cursor: pointer;
&:not(:hover) .log-line-action-buttons {
@@ -41,10 +41,10 @@ export const Container = styled(Card)<{
fontSize === FontSize.SMALL
? `padding:0.1rem 0.6rem;`
: fontSize === FontSize.MEDIUM
? `padding: 0.2rem 0.6rem;`
: fontSize === FontSize.LARGE
? `padding:0.3rem 0.6rem;`
: ``}
? `padding: 0.2rem 0.6rem;`
: fontSize === FontSize.LARGE
? `padding:0.3rem 0.6rem;`
: ``}
${({ $isActiveLog, $isDarkMode, $logType }): string =>
getActiveLogBackground($isActiveLog, $isDarkMode, $logType)}
@@ -65,8 +65,8 @@ export const LogContainer = styled.div<LogContainerProps>`
fontSize === FontSize.SMALL
? `gap: 2px;`
: fontSize === FontSize.MEDIUM
? ` gap:4px;`
: `gap:6px;`}
? ` gap:4px;`
: `gap:6px;`}
`;
export const LogText = styled.div<LogTextProps>`

View File

@@ -1,4 +1,6 @@
.log-state-indicator {
padding-left: 8px;
.line {
margin: 0 8px;
min-height: 24px;

View File

@@ -1,43 +0,0 @@
import { Color } from '@signozhq/design-tokens';
import { LogType } from './LogStateIndicator';
export function getRowBackgroundColor(
isDarkMode: boolean,
logType?: string,
): string {
if (isDarkMode) {
switch (logType) {
case LogType.INFO:
return `${Color.BG_ROBIN_500}40`;
case LogType.WARN:
return `${Color.BG_AMBER_500}40`;
case LogType.ERROR:
return `${Color.BG_CHERRY_500}40`;
case LogType.TRACE:
return `${Color.BG_FOREST_400}40`;
case LogType.DEBUG:
return `${Color.BG_AQUA_500}40`;
case LogType.FATAL:
return `${Color.BG_SAKURA_500}40`;
default:
return `${Color.BG_ROBIN_500}40`;
}
}
switch (logType) {
case LogType.INFO:
return Color.BG_ROBIN_100;
case LogType.WARN:
return Color.BG_AMBER_100;
case LogType.ERROR:
return Color.BG_CHERRY_100;
case LogType.TRACE:
return Color.BG_FOREST_200;
case LogType.DEBUG:
return Color.BG_AQUA_100;
case LogType.FATAL:
return Color.BG_SAKURA_100;
default:
return Color.BG_VANILLA_300;
}
}

View File

@@ -88,11 +88,11 @@ function RawLogView({
? formatTimezoneAdjustedTimestamp(
data.timestamp,
DATE_TIME_FORMATS.ISO_DATETIME_MS,
)
)
: formatTimezoneAdjustedTimestamp(
data.timestamp / 1e6,
DATE_TIME_FORMATS.ISO_DATETIME_MS,
);
);
parts.push(date);
}

View File

@@ -39,22 +39,22 @@ export const RawLogViewContainer = styled(Row)<{
fontSize === FontSize.SMALL
? `margin: 1px 0;`
: fontSize === FontSize.MEDIUM
? `margin: 1px 0;`
: `margin: 2px 0;`}
? `margin: 1px 0;`
: `margin: 2px 0;`}
}
${({ $isReadOnly, $isActiveLog, $isDarkMode, $logType }): string =>
$isActiveLog
? getActiveLogBackground($isActiveLog, $isDarkMode, $logType)
: !$isReadOnly
? `&:hover { ${getActiveLogBackground(true, $isDarkMode, $logType)} }`
: ''}
? `&:hover { ${getActiveLogBackground(true, $isDarkMode, $logType)} }`
: ''}
${({ $isHightlightedLog, $isDarkMode }): string =>
$isHightlightedLog
? `background-color: ${
$isDarkMode ? Color.BG_ROBIN_600 : Color.BG_VANILLA_400
};
};
transition: background-color 2s ease-in;`
: ''}
@@ -104,8 +104,8 @@ export const RawLogContent = styled.div<RawLogContentProps>`
fontSize === FontSize.SMALL
? `font-size:11px; line-height:16px; padding:1px;`
: fontSize === FontSize.MEDIUM
? `font-size:13px; line-height:20px; padding:1px;`
: `font-size:14px; line-height:24px; padding:2px;`}
? `font-size:13px; line-height:20px; padding:1px;`
: `font-size:14px; line-height:24px; padding:2px;`}
cursor: ${({ $isActiveLog, $isReadOnly }): string =>
$isActiveLog || $isReadOnly ? 'initial' : 'pointer'};

View File

@@ -19,7 +19,7 @@ export interface RawLogViewProps {
handleChangeSelectedView?: ChangeViewFunctionType;
onSetActiveLog?: (
log: ILog,
selectedTab?: (typeof VIEW_TYPES)[keyof typeof VIEW_TYPES],
selectedTab?: typeof VIEW_TYPES[keyof typeof VIEW_TYPES],
) => void;
onClearActiveLog?: () => void;
}

View File

@@ -27,6 +27,6 @@ export const TableBodyContent = styled.div<TableBodyContentProps>`
fontSize === FontSize.SMALL
? `font-size:11px; line-height:16px;`
: fontSize === FontSize.MEDIUM
? `font-size:13px; line-height:20px;`
: `font-size:14px; line-height:24px;`}
? `font-size:13px; line-height:20px;`
: `font-size:14px; line-height:24px;`}
`;

View File

@@ -1,114 +0,0 @@
import type { ReactElement } from 'react';
import { useMemo } from 'react';
import TanStackTable from 'components/TanStackTableView';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { getSanitizedLogBody } from 'container/LogDetailedView/utils';
import { FontSize } from 'container/OptionsMenu/types';
import { FlatLogData } from 'lib/logs/flatLogData';
import { useTimezone } from 'providers/Timezone';
import { IField } from 'types/api/logs/fields';
import { ILog } from 'types/api/logs/log';
import type { TableColumnDef } from '../../TanStackTableView/types';
import LogStateIndicator from '../LogStateIndicator/LogStateIndicator';
type UseLogsTableColumnsProps = {
fields: IField[];
fontSize: FontSize;
appendTo?: 'center' | 'end';
};
export function useLogsTableColumns({
fields,
fontSize,
appendTo = 'center',
}: UseLogsTableColumnsProps): TableColumnDef<ILog>[] {
const { formatTimezoneAdjustedTimestamp } = useTimezone();
return useMemo<TableColumnDef<ILog>[]>(() => {
const stateIndicatorCol: TableColumnDef<ILog> = {
id: 'state-indicator',
header: '',
pin: 'left',
enableMove: false,
enableResize: false,
enableRemove: false,
canBeHidden: false,
width: { fixed: 24 },
cell: ({ row }): ReactElement => (
<LogStateIndicator
fontSize={fontSize}
severityText={row.severity_text as string}
severityNumber={row.severity_number as number}
/>
),
};
const fieldColumns: TableColumnDef<ILog>[] = fields
.filter((f): boolean => !['id', 'body', 'timestamp'].includes(f.name))
.map(
(f): TableColumnDef<ILog> => ({
id: f.name,
header: f.name,
accessorFn: (log): unknown => FlatLogData(log)[f.name],
enableRemove: true,
width: { min: 192 },
cell: ({ value }): ReactElement => (
<TanStackTable.Text>{String(value ?? '')}</TanStackTable.Text>
),
}),
);
const timestampCol: TableColumnDef<ILog> | null = fields.some(
(f) => f.name === 'timestamp',
)
? {
id: 'timestamp',
header: 'Timestamp',
accessorFn: (log): unknown => log.timestamp,
width: { default: 170, min: 170 },
cell: ({ value }): ReactElement => {
const ts = value as string | number;
const formatted =
typeof ts === 'string'
? formatTimezoneAdjustedTimestamp(ts, DATE_TIME_FORMATS.ISO_DATETIME_MS)
: formatTimezoneAdjustedTimestamp(
ts / 1e6,
DATE_TIME_FORMATS.ISO_DATETIME_MS,
);
return <TanStackTable.Text>{formatted}</TanStackTable.Text>;
},
}
: null;
const bodyCol: TableColumnDef<ILog> | null = fields.some(
(f) => f.name === 'body',
)
? {
id: 'body',
header: 'Body',
accessorFn: (log): string => log.body,
canBeHidden: false,
width: { default: '100%', min: 300 },
cell: ({ value, isActive }): ReactElement => (
<TanStackTable.Text
dangerouslySetInnerHTML={{
__html: getSanitizedLogBody(value as string, {
shouldEscapeHtml: true,
}),
}}
data-active={isActive}
/>
),
}
: null;
return [
stateIndicatorCol,
...(timestampCol ? [timestampCol] : []),
...(appendTo === 'center' ? fieldColumns : []),
...(bodyCol ? [bodyCol] : []),
...(appendTo === 'end' ? fieldColumns : []),
];
}, [fields, appendTo, fontSize, formatTimezoneAdjustedTimestamp]);
}

View File

@@ -34,10 +34,9 @@ export const useTableView = (props: UseTableViewProps): UseTableViewResult => {
const isDarkMode = useIsDarkMode();
const flattenLogData = useMemo(
() => logs.map((log) => FlatLogData(log)),
[logs],
);
const flattenLogData = useMemo(() => logs.map((log) => FlatLogData(log)), [
logs,
]);
const { formatTimezoneAdjustedTimestamp } = useTimezone();
@@ -116,11 +115,11 @@ export const useTableView = (props: UseTableViewProps): UseTableViewResult => {
? formatTimezoneAdjustedTimestamp(
field,
DATE_TIME_FORMATS.ISO_DATETIME_MS,
)
)
: formatTimezoneAdjustedTimestamp(
field / 1e6,
DATE_TIME_FORMATS.ISO_DATETIME_MS,
);
);
return {
children: (
<div className="table-timestamp">
@@ -130,7 +129,7 @@ export const useTableView = (props: UseTableViewProps): UseTableViewResult => {
};
},
},
]
]
: []),
...(appendTo === 'center' ? fieldColumns : []),
...(fields.some((field) => field.name === 'body')
@@ -161,7 +160,7 @@ export const useTableView = (props: UseTableViewProps): UseTableViewResult => {
),
}),
},
]
]
: []),
...(appendTo === 'end' ? fieldColumns : []),
];

View File

@@ -35,11 +35,13 @@ function OptionsMenu({
const [fontSizeValue, setFontSizeValue] = useState<FontSize>(
fontSize?.value || FontSize.SMALL,
);
const [isFontSizeOptionsOpen, setIsFontSizeOptionsOpen] =
useState<boolean>(false);
const [isFontSizeOptionsOpen, setIsFontSizeOptionsOpen] = useState<boolean>(
false,
);
const [showAddNewColumnContainer, setShowAddNewColumnContainer] =
useState(false);
const [showAddNewColumnContainer, setShowAddNewColumnContainer] = useState(
false,
);
const [selectedValue, setSelectedValue] = useState<string | null>(null);
const listRef = useRef<HTMLDivElement>(null);

View File

@@ -260,28 +260,23 @@ const CustomMultiSelect: React.FC<CustomMultiSelectProps> = ({
/**
* Separates section and non-section options
*/
const splitOptions = useCallback(
(
options: OptionData[],
): {
sectionOptions: OptionData[];
nonSectionOptions: OptionData[];
} => {
const sectionOptions: OptionData[] = [];
const nonSectionOptions: OptionData[] = [];
const splitOptions = useCallback((options: OptionData[]): {
sectionOptions: OptionData[];
nonSectionOptions: OptionData[];
} => {
const sectionOptions: OptionData[] = [];
const nonSectionOptions: OptionData[] = [];
options.forEach((option) => {
if ('options' in option && Array.isArray(option.options)) {
sectionOptions.push(option);
} else {
nonSectionOptions.push(option);
}
});
options.forEach((option) => {
if ('options' in option && Array.isArray(option.options)) {
sectionOptions.push(option);
} else {
nonSectionOptions.push(option);
}
});
return { sectionOptions, nonSectionOptions };
},
[],
);
return { sectionOptions, nonSectionOptions };
}, []);
/**
* Apply search filtering to options
@@ -1634,7 +1629,7 @@ const CustomMultiSelect: React.FC<CustomMultiSelectProps> = ({
}}
data={enhancedNonSectionOptions}
itemContent={(index, item): React.ReactNode =>
mapOptions([item]) as unknown as React.ReactElement
(mapOptions([item]) as unknown) as React.ReactElement
}
totalCount={enhancedNonSectionOptions.length}
itemSize={(): number => 40}
@@ -1676,7 +1671,7 @@ const CustomMultiSelect: React.FC<CustomMultiSelectProps> = ({
}}
data={section.options || []}
itemContent={(index, item): React.ReactNode =>
mapOptions([item]) as unknown as React.ReactElement
(mapOptions([item]) as unknown) as React.ReactElement
}
totalCount={section.options?.length || 0}
itemSize={(): number => 40}
@@ -1941,7 +1936,7 @@ const CustomMultiSelect: React.FC<CustomMultiSelectProps> = ({
? {
borderColor: Color.BG_ROBIN_500,
backgroundColor: Color.BG_SLATE_400,
}
}
: undefined
}
>

View File

@@ -112,28 +112,23 @@ const CustomSelect: React.FC<CustomSelectProps> = ({
/**
* Separates section and non-section options
*/
const splitOptions = useCallback(
(
options: OptionData[],
): {
sectionOptions: OptionData[];
nonSectionOptions: OptionData[];
} => {
const sectionOptions: OptionData[] = [];
const nonSectionOptions: OptionData[] = [];
const splitOptions = useCallback((options: OptionData[]): {
sectionOptions: OptionData[];
nonSectionOptions: OptionData[];
} => {
const sectionOptions: OptionData[] = [];
const nonSectionOptions: OptionData[] = [];
options.forEach((option) => {
if ('options' in option && Array.isArray(option.options)) {
sectionOptions.push(option);
} else {
nonSectionOptions.push(option);
}
});
options.forEach((option) => {
if ('options' in option && Array.isArray(option.options)) {
sectionOptions.push(option);
} else {
nonSectionOptions.push(option);
}
});
return { sectionOptions, nonSectionOptions };
},
[],
);
return { sectionOptions, nonSectionOptions };
}, []);
/**
* Apply search filtering to options
@@ -327,8 +322,9 @@ const CustomSelect: React.FC<CustomSelectProps> = ({
processedOptions = filterOptionsBySearch(processedOptions, searchText);
}
const { sectionOptions, nonSectionOptions } =
splitOptions(processedOptions);
const { sectionOptions, nonSectionOptions } = splitOptions(
processedOptions,
);
// Add custom option if needed
if (

View File

@@ -336,7 +336,7 @@ describe('CustomMultiSelect Component', () => {
renderWithVirtuoso(
<CustomMultiSelect
options={mockGroupedOptions}
value={'__ALL__' as unknown as string[]}
value={('__ALL__' as unknown) as string[]}
/>,
);

View File

@@ -180,9 +180,7 @@ $custom-border-color: #2c3044;
.custom-multiselect-dropdown-container {
z-index: 1050 !important;
padding: 0;
box-shadow:
0 3px 6px -4px rgba(0, 0, 0, 0.5),
0 6px 16px 0 rgba(0, 0, 0, 0.4),
box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.5), 0 6px 16px 0 rgba(0, 0, 0, 0.4),
0 9px 28px 8px rgba(0, 0, 0, 0.3);
background-color: var(--l2-background);
border: 1px solid var(--l1-border);
@@ -806,10 +804,8 @@ $custom-border-color: #2c3044;
.custom-multiselect-dropdown-container {
background-color: var(--l1-background);
border: 1px solid var(--l1-border);
box-shadow:
0 3px 6px -4px rgba(0, 0, 0, 0.12),
0 6px 16px 0 rgba(0, 0, 0, 0.08),
0 9px 28px 8px rgba(0, 0, 0, 0.05);
box-shadow: 0 3px 6px -4px rgba(0, 0, 0, 0.12),
0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
.empty-message {
color: var(--l2-foreground);
@@ -980,9 +976,7 @@ $custom-border-color: #2c3044;
font-weight: 500;
z-index: 2;
pointer-events: none;
transition:
opacity 0.2s ease,
visibility 0.2s ease;
transition: opacity 0.2s ease, visibility 0.2s ease;
.lightMode & {
color: rgba(0, 0, 0, 0.85);

View File

@@ -40,10 +40,8 @@ export interface CustomTagProps {
onClose: () => void;
}
export interface CustomMultiSelectProps extends Omit<
SelectProps<string[] | string>,
'options'
> {
export interface CustomMultiSelectProps
extends Omit<SelectProps<string[] | string>, 'options'> {
placeholder?: string;
className?: string;
loading?: boolean;

View File

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

View File

@@ -10,14 +10,8 @@
border-bottom: 1px solid var(--l1-border);
border-top: 1px solid var(--l1-border);
font-family:
Inter,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
'Helvetica Neue',
sans-serif;
font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
'Helvetica Neue', sans-serif;
border-right: none;
border-left: none;

View File

@@ -76,34 +76,32 @@ export const QueryBuilderV2 = memo(function QueryBuilderV2({
[showTraceOperator, isListViewPanel],
);
const listViewLogFilterConfigs: QueryBuilderProps['filterConfigs'] =
useMemo(() => {
const config: QueryBuilderProps['filterConfigs'] = {
stepInterval: { isHidden: true, isDisabled: true },
having: { isHidden: true, isDisabled: true },
filters: {
customKey: 'body',
customOp: OPERATORS.CONTAINS,
},
};
const listViewLogFilterConfigs: QueryBuilderProps['filterConfigs'] = useMemo(() => {
const config: QueryBuilderProps['filterConfigs'] = {
stepInterval: { isHidden: true, isDisabled: true },
having: { isHidden: true, isDisabled: true },
filters: {
customKey: 'body',
customOp: OPERATORS.CONTAINS,
},
};
return config;
}, []);
return config;
}, []);
const listViewTracesFilterConfigs: QueryBuilderProps['filterConfigs'] =
useMemo(() => {
const config: QueryBuilderProps['filterConfigs'] = {
stepInterval: { isHidden: true, isDisabled: true },
having: { isHidden: true, isDisabled: true },
limit: { isHidden: true, isDisabled: true },
filters: {
customKey: 'body',
customOp: OPERATORS.CONTAINS,
},
};
const listViewTracesFilterConfigs: QueryBuilderProps['filterConfigs'] = useMemo(() => {
const config: QueryBuilderProps['filterConfigs'] = {
stepInterval: { isHidden: true, isDisabled: true },
having: { isHidden: true, isDisabled: true },
limit: { isHidden: true, isDisabled: true },
filters: {
customKey: 'body',
customOp: OPERATORS.CONTAINS,
},
};
return config;
}, []);
return config;
}, []);
const queryFilterConfigs = useMemo(() => {
if (isListViewPanel) {

View File

@@ -49,8 +49,11 @@ export const MetricsSelect = memo(function MetricsSelect({
entityVersion: version,
});
const { updateAllQueriesOperators, handleSetQueryData, panelType } =
useQueryBuilder();
const {
updateAllQueriesOperators,
handleSetQueryData,
panelType,
} = useQueryBuilder();
const source = useMemo(
() => (signalSource === 'meter' ? 'meter' : 'metrics'),
@@ -120,8 +123,9 @@ export const MetricsSelect = memo(function MetricsSelect({
signalSource: newSignalSource,
panelType: panelType || '',
});
const savedQuery: IBuilderQuery | null =
getPreviousQueryFromKey(newQueryKey);
const savedQuery: IBuilderQuery | null = getPreviousQueryFromKey(
newQueryKey,
);
// remove the new query key from session storage
removeKeyFromPreviousQuery(newQueryKey);

View File

@@ -464,37 +464,36 @@ function QueryAddOns({
</div>
)}
{selectedViews.find((view) => view.key === 'reduce_to') &&
showReduceTo && (
<div className="add-on-content" data-testid="reduce-to-content">
<div className="periscope-input-with-label">
<Tooltip
title={
<TooltipContent
label="Reduce to"
description="Apply mathematical operations like sum, average, min, max, or percentiles to reduce multiple time series into a single value."
docLink="https://signoz.io/docs/userguide/query-builder-v5/#reduce-operations"
/>
}
placement="top"
mouseEnterDelay={0.5}
>
<div className="label" style={{ cursor: 'help' }}>
Reduce to
</div>
</Tooltip>
<div className="input">
<ReduceToFilter query={query} onChange={handleChangeReduceToV5} />
{selectedViews.find((view) => view.key === 'reduce_to') && showReduceTo && (
<div className="add-on-content" data-testid="reduce-to-content">
<div className="periscope-input-with-label">
<Tooltip
title={
<TooltipContent
label="Reduce to"
description="Apply mathematical operations like sum, average, min, max, or percentiles to reduce multiple time series into a single value."
docLink="https://signoz.io/docs/userguide/query-builder-v5/#reduce-operations"
/>
}
placement="top"
mouseEnterDelay={0.5}
>
<div className="label" style={{ cursor: 'help' }}>
Reduce to
</div>
<Button
className="close-btn periscope-btn ghost"
icon={<ChevronUp size={16} />}
onClick={(): void => handleRemoveView('reduce_to')}
/>
</Tooltip>
<div className="input">
<ReduceToFilter query={query} onChange={handleChangeReduceToV5} />
</div>
<Button
className="close-btn periscope-btn ghost"
icon={<ChevronUp size={16} />}
onClick={(): void => handleRemoveView('reduce_to')}
/>
</div>
)}
</div>
)}
{selectedViews.find((view) => view.key === 'legend_format') && (
<div className="add-on-content" data-testid="legend-format-content">

View File

@@ -290,12 +290,12 @@ function QueryAggregationSelect({
}
const regex = /([a-zA-Z_][\w]*)\s*\(([^)]*)\)/g;
const oldMatches = [...tr.startState.doc.toString().matchAll(regex)].filter(
(match) => validFunctions.includes(match[1].toLowerCase()),
);
const newMatches = [...tr.newDoc.toString().matchAll(regex)].filter(
(match) => validFunctions.includes(match[1].toLowerCase()),
);
const oldMatches = [
...tr.startState.doc.toString().matchAll(regex),
].filter((match) => validFunctions.includes(match[1].toLowerCase()));
const newMatches = [
...tr.newDoc.toString().matchAll(regex),
].filter((match) => validFunctions.includes(match[1].toLowerCase()));
if (
newMatches.length > oldMatches.length &&
@@ -558,7 +558,7 @@ function QueryAggregationSelect({
? availableSuggestions
: availableSuggestions.filter((suggestion) =>
suggestion.label.toLowerCase().includes(inputText.toLowerCase()),
);
);
return {
from: startOfArg,

View File

@@ -5,14 +5,8 @@
display: flex;
flex-direction: column;
gap: 8px;
font-family:
Inter,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
'Helvetica Neue',
sans-serif;
font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
'Helvetica Neue', sans-serif;
.query-where-clause-editor-container {
position: relative;

View File

@@ -194,8 +194,10 @@ function QuerySearch({
const [cursorPos, setCursorPos] = useState({ line: 0, ch: 0 });
const [isFetchingCompleteValuesList, setIsFetchingCompleteValuesList] =
useState<boolean>(false);
const [
isFetchingCompleteValuesList,
setIsFetchingCompleteValuesList,
] = useState<boolean>(false);
const lastPosRef = useRef<{ line: number; ch: number }>({ line: 0, ch: 0 });

View File

@@ -93,10 +93,9 @@ export const QueryV2 = forwardRef(function QueryV2(
[dataSource, panelType],
);
const showSpanScopeSelector = useMemo(
() => dataSource === DataSource.TRACES,
[dataSource],
);
const showSpanScopeSelector = useMemo(() => dataSource === DataSource.TRACES, [
dataSource,
]);
const showInlineQuerySearch = useMemo(() => {
if (!showTraceOperator) {
@@ -213,7 +212,7 @@ export const QueryV2 = forwardRef(function QueryV2(
icon: <Trash size={14} />,
onClick: handleDeleteQuery,
},
]
]
: []),
],
}}

View File

@@ -3,7 +3,7 @@ import { IBuilderTraceOperator } from 'types/api/queryBuilder/queryBuilderData';
import { getInvolvedQueriesInTraceOperator } from '../utils/utils';
const makeTraceOperator = (expression: string): IBuilderTraceOperator =>
({ expression }) as unknown as IBuilderTraceOperator;
(({ expression } as unknown) as IBuilderTraceOperator);
describe('getInvolvedQueriesInTraceOperator', () => {
it('returns empty array for empty input', () => {

View File

@@ -98,7 +98,9 @@ export function createTraceOperatorContext(
}
// Helper to determine token context
function determineTraceTokenContext(token: IToken): {
function determineTraceTokenContext(
token: IToken,
): {
isInAtom: boolean;
isInOperator: boolean;
isInParenthesis: boolean;

View File

@@ -36,14 +36,14 @@ beforeAll(() => {
const mockRange = {
// CodeMirror uses these for text measurement
getClientRects: (): DOMRectList =>
({
(({
length: 1,
item: (index: number): DOMRect | null => (index === 0 ? mockRect : null),
0: mockRect,
*[Symbol.iterator](): Generator<DOMRect> {
yield mockRect;
},
}) as unknown as DOMRectList,
} as unknown) as DOMRectList),
getBoundingClientRect: (): DOMRect => mockRect,
// CodeMirror calls these to set up text ranges
setStart: (node: Node, offset: number): void => {
@@ -72,7 +72,7 @@ beforeAll(() => {
},
commonAncestorContainer: document.body,
};
return mockRange as unknown as Range;
return (mockRange as unknown) as Range;
};
// Mock document.createRange to return a new Range instance each time

View File

@@ -94,12 +94,13 @@ describe('QueryBuilderV2 + QueryV2 - base render', () => {
},
};
const updateAllQueriesOperators: QueryBuilderContextType['updateAllQueriesOperators'] =
(q) => q;
const updateAllQueriesOperators: QueryBuilderContextType['updateAllQueriesOperators'] = (
q,
) => q;
const updateQueriesData: QueryBuilderContextType['updateQueriesData'] = (q) =>
q;
const baseContext = {
const baseContext = ({
currentQuery: currentQueryObj,
stagedQuery: null,
lastUsedQuery: null,
@@ -132,7 +133,7 @@ describe('QueryBuilderV2 + QueryV2 - base render', () => {
initQueryBuilderData: jest.fn(),
isStagedQueryUpdated: jest.fn(() => false),
isDefaultQuery: jest.fn(() => false),
} as unknown as QueryBuilderContextType;
} as unknown) as QueryBuilderContextType;
baseQBContext = baseContext;
mockedUseQueryBuilder.mockReturnValue(baseQBContext);
@@ -148,8 +149,7 @@ describe('QueryBuilderV2 + QueryV2 - base render', () => {
handleChangeAggregatorAttribute: jest.fn(),
handleChangeDataSource: jest.fn(),
handleDeleteQuery: jest.fn(),
handleChangeQueryData:
jest.fn() as unknown as ReturnType<UseQueryOperations>['handleChangeQueryData'],
handleChangeQueryData: (jest.fn() as unknown) as ReturnType<UseQueryOperations>['handleChangeQueryData'],
handleChangeFormulaData: jest.fn(),
handleQueryFunctionsUpdates: handleQueryFunctionsUpdatesMock,
listOfAdditionalFormulaFilters: [],

View File

@@ -57,7 +57,7 @@ describe('MetricsSelect - signal source switching (standalone)', () => {
beforeEach(() => {
clearPreviousQuery();
handleSetQueryDataMock = jest.fn() as unknown as jest.MockedFunction<
handleSetQueryDataMock = (jest.fn() as unknown) as jest.MockedFunction<
(index: number, q: IBuilderQuery) => void
>;
@@ -222,7 +222,7 @@ describe('DataSource change - Logs to Traces', () => {
beforeEach(() => {
clearPreviousQuery();
handleSetQueryDataMock = jest.fn() as unknown as jest.MockedFunction<
handleSetQueryDataMock = (jest.fn() as unknown) as jest.MockedFunction<
(i: number, q: IBuilderQuery) => void
>;

View File

@@ -947,7 +947,7 @@ describe('convertAggregationToExpression', () => {
it('should handle undefined aggregateAttribute parameter with traces', () => {
const result = convertAggregationToExpression({
aggregateOperator: 'noop',
aggregateAttribute: undefined as unknown as BaseAutocompleteData,
aggregateAttribute: (undefined as unknown) as BaseAutocompleteData,
dataSource: DataSource.TRACES,
});
@@ -961,7 +961,7 @@ describe('convertAggregationToExpression', () => {
it('should handle undefined aggregateAttribute parameter with logs', () => {
const result = convertAggregationToExpression({
aggregateOperator: 'noop',
aggregateAttribute: undefined as unknown as BaseAutocompleteData,
aggregateAttribute: (undefined as unknown) as BaseAutocompleteData,
dataSource: DataSource.LOGS,
});

View File

@@ -210,8 +210,8 @@ export const convertExpressionToFilters = (
type: '',
},
value: pair.isMultiValue
? (formatValuesForFilter(pair.valueList as string[]) ?? [])
: (formatValuesForFilter(pair.value as string) ?? ''),
? formatValuesForFilter(pair.valueList as string[]) ?? []
: formatValuesForFilter(pair.value as string) ?? '',
});
});
@@ -469,8 +469,8 @@ export const convertFiltersToExpressionWithExistingQuery = (
type: '',
},
value: pair.isMultiValue
? (formatValuesForFilter(pair.valueList as string[]) ?? '')
: (formatValuesForFilter(pair.value as string) ?? ''),
? formatValuesForFilter(pair.valueList as string[]) ?? ''
: formatValuesForFilter(pair.value as string) ?? '',
});
}
});
@@ -554,7 +554,7 @@ export const removeKeysFromExpression = (
}
const value = pair.value?.toString().trim();
return value && value.includes('$');
})
})
: existingQueryPairs;
// Build a map for quick lookup of query pairs by their lowercase trimmed keys
@@ -744,18 +744,15 @@ export function getQueryLabelWithAggregation(
const labels: { label: string; value: string }[] = [];
const aggregationPerQuery =
queryData.reduce(
(acc, query) => {
if (query.queryName && query.aggregations?.length) {
acc[query.queryName] = createAggregation(query).map((a: any) => ({
alias: a.alias,
expression: a.expression,
}));
}
return acc;
},
{} as Record<string, any>,
) || {};
queryData.reduce((acc, query) => {
if (query.queryName && query.aggregations?.length) {
acc[query.queryName] = createAggregation(query).map((a: any) => ({
alias: a.alias,
expression: a.expression,
}));
}
return acc;
}, {} as Record<string, any>) || {};
Object.entries(aggregationPerQuery).forEach(([queryName, aggregations]) => {
const isMultipleAggregations = aggregations.length > 1;

View File

@@ -83,7 +83,7 @@ const createMockQueryBuilderData = (hasActiveFilters = false): any => ({
op: 'in',
value: [OTEL_DEMO, SAMPLE_FLASK],
},
]
]
: [],
},
},
@@ -99,7 +99,7 @@ describe('CheckboxFilter - User Flows', () => {
jest.clearAllMocks();
// Default mock implementations for useGetAggregateValues
mockUseGetAggregateValues.mockReturnValue({
mockUseGetAggregateValues.mockReturnValue(({
data: {
payload: {
stringAttributeValues: MOCK_SERVICE_NAMES,
@@ -107,7 +107,7 @@ describe('CheckboxFilter - User Flows', () => {
},
isLoading: false,
refetch: jest.fn(),
} as unknown as UseQueryResult<SuccessResponse<IAttributeValuesResponse>>);
} as unknown) as UseQueryResult<SuccessResponse<IAttributeValuesResponse>>);
// Default mock implementations for useGetQueryKeyValueSuggestions
// Returns data in the format expected by the hook

View File

@@ -82,8 +82,10 @@ export default function CheckboxFilter(props: ICheckboxProps): JSX.Element {
// Check if this filter has active filters in the query
const isSomeFilterPresentForCurrentAttribute = useMemo(
() =>
currentQuery.builder.queryData?.[activeQueryIndex]?.filters?.items?.some(
(item) => isKeyMatch(item.key?.key, filter.attributeKey.key),
currentQuery.builder.queryData?.[
activeQueryIndex
]?.filters?.items?.some((item) =>
isKeyMatch(item.key?.key, filter.attributeKey.key),
),
[currentQuery.builder.queryData, activeQueryIndex, filter.attributeKey.key],
);
@@ -124,16 +126,18 @@ export default function CheckboxFilter(props: ICheckboxProps): JSX.Element {
},
);
const { data: keyValueSuggestions, isLoading: isLoadingKeyValueSuggestions } =
useGetQueryKeyValueSuggestions({
key: filter.attributeKey.key,
signal: filter.dataSource || DataSource.LOGS,
signalSource: 'meter',
options: {
enabled: isOpen && source === QuickFiltersSource.METER_EXPLORER,
keepPreviousData: true,
},
});
const {
data: keyValueSuggestions,
isLoading: isLoadingKeyValueSuggestions,
} = useGetQueryKeyValueSuggestions({
key: filter.attributeKey.key,
signal: filter.dataSource || DataSource.LOGS,
signalSource: 'meter',
options: {
enabled: isOpen && source === QuickFiltersSource.METER_EXPLORER,
keepPreviousData: true,
},
});
const attributeValues: string[] = useMemo(() => {
const dataType = filter.attributeKey.dataType || DataTypes.String;
@@ -278,7 +282,7 @@ export default function CheckboxFilter(props: ICheckboxProps): JSX.Element {
idx === activeQueryIndex
? item.filters?.items?.filter(
(fil) => !isKeyMatch(fil.key?.key, filter.attributeKey.key),
) || []
) || []
: [...(item.filters?.items || [])],
op: item.filters?.op || 'AND',
},

View File

@@ -36,13 +36,12 @@ function Duration({
onFilterChange?: (query: Query) => void;
source?: QuickFiltersSource;
}): JSX.Element {
const [selectedFilters, setSelectedFilters] =
useState<
Record<
AllTraceFilterKeys,
{ values: string[] | string; keys: BaseAutocompleteData }
>
>();
const [selectedFilters, setSelectedFilters] = useState<
Record<
AllTraceFilterKeys,
{ values: string[] | string; keys: BaseAutocompleteData }
>
>();
const [activeKeys, setActiveKeys] = useState<string[]>([
filter.defaultOpen ? 'durationNano' : '',
]);

View File

@@ -30,8 +30,13 @@ function SortableFilter({
allowDrag: boolean;
allowRemove: boolean;
}): JSX.Element {
const { attributes, listeners, setNodeRef, transform, transition } =
useSortable({ id: filter.key });
const {
attributes,
listeners,
setNodeRef,
transform,
transition,
} = useSortable({ id: filter.key });
const style = {
transform: CSS.Transform.toString(transform),

View File

@@ -48,46 +48,52 @@ function OtherFilters({
[signal],
);
const { data: suggestionsData, isFetching: isFetchingSuggestions } =
useGetAttributeSuggestions(
{
searchText: inputValue,
dataSource: SIGNAL_DATA_SOURCE_MAP[signal as SignalType],
filters: {} as TagFilter,
},
{
queryKey: [REACT_QUERY_KEY.GET_OTHER_FILTERS, inputValue],
enabled: !!signal && isLogDataSource,
},
);
const {
data: suggestionsData,
isFetching: isFetchingSuggestions,
} = useGetAttributeSuggestions(
{
searchText: inputValue,
dataSource: SIGNAL_DATA_SOURCE_MAP[signal as SignalType],
filters: {} as TagFilter,
},
{
queryKey: [REACT_QUERY_KEY.GET_OTHER_FILTERS, inputValue],
enabled: !!signal && isLogDataSource,
},
);
const { data: aggregateKeysData, isFetching: isFetchingAggregateKeys } =
useGetAggregateKeys(
{
searchText: inputValue,
dataSource: SIGNAL_DATA_SOURCE_MAP[signal as SignalType],
aggregateOperator: 'noop',
aggregateAttribute: '',
tagType: '',
},
{
queryKey: [REACT_QUERY_KEY.GET_OTHER_FILTERS, inputValue],
enabled: !!signal && !isLogDataSource && !isMeterDataSource,
},
);
const {
data: aggregateKeysData,
isFetching: isFetchingAggregateKeys,
} = useGetAggregateKeys(
{
searchText: inputValue,
dataSource: SIGNAL_DATA_SOURCE_MAP[signal as SignalType],
aggregateOperator: 'noop',
aggregateAttribute: '',
tagType: '',
},
{
queryKey: [REACT_QUERY_KEY.GET_OTHER_FILTERS, inputValue],
enabled: !!signal && !isLogDataSource && !isMeterDataSource,
},
);
const { data: fieldKeysData, isLoading: isLoadingFieldKeys } =
useGetQueryKeySuggestions(
{
searchText: inputValue,
signal: SIGNAL_DATA_SOURCE_MAP[signal as SignalType],
signalSource: 'meter',
},
{
queryKey: [REACT_QUERY_KEY.GET_OTHER_FILTERS, inputValue],
enabled: !!signal && isMeterDataSource,
},
);
const {
data: fieldKeysData,
isLoading: isLoadingFieldKeys,
} = useGetQueryKeySuggestions(
{
searchText: inputValue,
signal: SIGNAL_DATA_SOURCE_MAP[signal as SignalType],
signalSource: 'meter',
},
{
queryKey: [REACT_QUERY_KEY.GET_OTHER_FILTERS, inputValue],
enabled: !!signal && isMeterDataSource,
},
);
const otherFilters = useMemo(() => {
let filterAttributes;
@@ -104,7 +110,7 @@ function OtherFilters({
dataType: attr.fieldDataType,
type: attr.fieldContext,
signal: attr.signal,
}) as BaseAutocompleteData,
} as BaseAutocompleteData),
);
} else {
filterAttributes = aggregateKeysData?.payload?.attributeKeys || [];

View File

@@ -40,26 +40,28 @@ const useQuickFilterSettings = ({
const [addedFilters, setAddedFilters] = useState<FilterType[]>(customFilters);
const { notifications } = useNotifications();
const { mutate: updateCustomFilters, isLoading: isUpdatingCustomFilters } =
useMutation(updateCustomFiltersAPI, {
onSuccess: () => {
setIsSettingsOpen(false);
refetchCustomFilters();
logEvent('Quick Filters Settings: changes saved', {
addedFilters,
});
notifications.success({
message: 'Quick filters updated successfully',
placement: 'bottomRight',
});
},
onError: (error: AxiosError) => {
notifications.error({
message: axios.isAxiosError(error) ? error.message : SOMETHING_WENT_WRONG,
placement: 'bottomRight',
});
},
});
const {
mutate: updateCustomFilters,
isLoading: isUpdatingCustomFilters,
} = useMutation(updateCustomFiltersAPI, {
onSuccess: () => {
setIsSettingsOpen(false);
refetchCustomFilters();
logEvent('Quick Filters Settings: changes saved', {
addedFilters,
});
notifications.success({
message: 'Quick filters updated successfully',
placement: 'bottomRight',
});
},
onError: (error: AxiosError) => {
notifications.error({
message: axios.isAxiosError(error) ? error.message : SOMETHING_WENT_WRONG,
placement: 'bottomRight',
});
},
});
const debouncedUpdate = useDebouncedFn((value) => {
setDebouncedInputValue(value as string);
}, 400);

View File

@@ -38,10 +38,9 @@ const useFilterConfig = ({
},
);
const isDynamicFilters = useMemo(
() => customFilters.length > 0,
[customFilters],
);
const isDynamicFilters = useMemo(() => customFilters.length > 0, [
customFilters,
]);
const filterConfig = useMemo(
() => getFilterConfig(signal, customFilters, config),

View File

@@ -55,6 +55,6 @@ export const getFilterConfig = (
type: att.type,
},
defaultOpen: index < 2,
}) as IQuickFiltersConfig,
} as IQuickFiltersConfig),
);
};

View File

@@ -52,38 +52,39 @@ function DynamicColumnTable({
...prevColumns.slice(0, prevColumns.length - 1),
...visibleColumns,
prevColumns[prevColumns.length - 1],
]
]
: undefined,
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [columns, dynamicColumns]);
const onToggleHandler =
(index: number, column: ColumnGroupType<any> | ColumnType<any>) =>
(checked: boolean, event: React.MouseEvent<HTMLButtonElement>): void => {
event.stopPropagation();
const onToggleHandler = (
index: number,
column: ColumnGroupType<any> | ColumnType<any>,
) => (checked: boolean, event: React.MouseEvent<HTMLButtonElement>): void => {
event.stopPropagation();
if (shouldSendAlertsLogEvent) {
logEvent('Alert: Column toggled', {
column: column?.title,
action: checked ? 'Enable' : 'Disable',
});
}
setVisibleColumns({
tablesource,
dynamicColumns,
index,
checked,
if (shouldSendAlertsLogEvent) {
logEvent('Alert: Column toggled', {
column: column?.title,
action: checked ? 'Enable' : 'Disable',
});
setColumnsData((prevColumns) =>
getNewColumnData({
checked,
index,
prevColumns,
dynamicColumns,
}),
);
};
}
setVisibleColumns({
tablesource,
dynamicColumns,
index,
checked,
});
setColumnsData((prevColumns) =>
getNewColumnData({
checked,
index,
prevColumns,
dynamicColumns,
}),
);
};
const items: MenuProps['items'] =
dynamicColumns?.map((column, index) => ({

View File

@@ -45,18 +45,20 @@ function ResizeTable({
}, [onColumnWidthsChange]);
const handleResize = useCallback(
(index: number) =>
(e: SyntheticEvent<Element>, { size }: ResizeCallbackData): void => {
e.preventDefault();
e.stopPropagation();
(index: number) => (
e: SyntheticEvent<Element>,
{ size }: ResizeCallbackData,
): void => {
e.preventDefault();
e.stopPropagation();
const newColumns = [...columnsData];
newColumns[index] = {
...newColumns[index],
width: size.width,
};
setColumns(newColumns);
},
const newColumns = [...columnsData];
newColumns[index] = {
...newColumns[index],
width: size.width,
};
setColumns(newColumns);
},
[columnsData],
);

View File

@@ -27,7 +27,7 @@ export interface ResizeTableProps extends TableProps<any> {
onColumnWidthsChange?: (widths: ColumnWidths) => void;
}
export interface DynamicColumnTableProps extends TableProps<any> {
tablesource: (typeof TableDataSource)[keyof typeof TableDataSource];
tablesource: typeof TableDataSource[keyof typeof TableDataSource];
dynamicColumns: TableProps<any>['columns'];
onDragColumn?: (fromIndex: number, toIndex: number) => void;
facingIssueBtn?: LaunchChatSupportProps;
@@ -40,7 +40,7 @@ export type GetVisibleColumnsFunction = (
) => (ColumnGroupType<any> | ColumnType<any>)[];
export type GetVisibleColumnProps = {
tablesource: (typeof TableDataSource)[keyof typeof TableDataSource];
tablesource: typeof TableDataSource[keyof typeof TableDataSource];
dynamicColumns?: ColumnsType<any>;
columnsData?: ColumnsType;
};
@@ -48,7 +48,7 @@ export type GetVisibleColumnProps = {
export type SetVisibleColumnsProps = {
checked: boolean;
index: number;
tablesource: (typeof TableDataSource)[keyof typeof TableDataSource];
tablesource: typeof TableDataSource[keyof typeof TableDataSource];
dynamicColumns?: ColumnsType<any>;
};

View File

@@ -71,7 +71,7 @@ export const getNewColumnData: GetNewColumnDataFunction = ({
...prevColumns.slice(0, prevColumns.length - 1),
dynamicColumns[index],
prevColumns[prevColumns.length - 1],
]
]
: undefined;
}
return prevColumns && dynamicColumns

View File

@@ -37,8 +37,10 @@ function AddKeyModal(): JSX.Element {
const open = isAddKeyOpen && !!accountId;
const [phase, setPhase] = useState<Phase>(Phase.FORM);
const [createdKey, setCreatedKey] =
useState<ServiceaccounttypesGettableFactorAPIKeyWithKeyDTO | null>(null);
const [
createdKey,
setCreatedKey,
] = useState<ServiceaccounttypesGettableFactorAPIKeyWithKeyDTO | null>(null);
const [hasCopied, setHasCopied] = useState(false);
const {
@@ -65,28 +67,30 @@ function AddKeyModal(): JSX.Element {
}
}, [open, reset]);
const { mutate: createKey, isLoading: isSubmitting } =
useCreateServiceAccountKey({
mutation: {
onSuccess: async (response) => {
const keyData = response?.data;
if (keyData) {
setCreatedKey(keyData);
setPhase(Phase.CREATED);
if (accountId) {
await invalidateListServiceAccountKeys(queryClient, { id: accountId });
}
const {
mutate: createKey,
isLoading: isSubmitting,
} = useCreateServiceAccountKey({
mutation: {
onSuccess: async (response) => {
const keyData = response?.data;
if (keyData) {
setCreatedKey(keyData);
setPhase(Phase.CREATED);
if (accountId) {
await invalidateListServiceAccountKeys(queryClient, { id: accountId });
}
},
onError: (error) => {
showErrorModal(
convertToApiError(
error as AxiosError<RenderErrorResponseDTO, unknown> | null,
) as APIError,
);
},
}
},
});
onError: (error) => {
showErrorModal(
convertToApiError(
error as AxiosError<RenderErrorResponseDTO, unknown> | null,
) as APIError,
);
},
},
});
function handleCreate({
keyName,

View File

@@ -30,28 +30,30 @@ function DeleteAccountModal(): JSX.Element {
const cachedAccount = accountId
? queryClient.getQueryData<{
data: ServiceaccounttypesServiceAccountDTO;
}>(getGetServiceAccountQueryKey({ id: accountId }))
}>(getGetServiceAccountQueryKey({ id: accountId }))
: null;
const accountName = cachedAccount?.data?.name;
const { mutate: deleteAccount, isLoading: isDeleting } =
useDeleteServiceAccount({
mutation: {
onSuccess: async () => {
toast.success('Service account deleted');
await setIsDeleteOpen(null);
await setAccountId(null);
await invalidateListServiceAccounts(queryClient);
},
onError: (error) => {
showErrorModal(
convertToApiError(
error as AxiosError<RenderErrorResponseDTO, unknown> | null,
) as APIError,
);
},
const {
mutate: deleteAccount,
isLoading: isDeleting,
} = useDeleteServiceAccount({
mutation: {
onSuccess: async () => {
toast.success('Service account deleted');
await setIsDeleteOpen(null);
await setAccountId(null);
await invalidateListServiceAccounts(queryClient);
},
});
onError: (error) => {
showErrorModal(
convertToApiError(
error as AxiosError<RenderErrorResponseDTO, unknown> | null,
) as APIError,
);
},
},
});
function handleConfirm(): void {
if (!accountId) {

View File

@@ -89,29 +89,31 @@ function EditKeyModal({ keyItem }: EditKeyModalProps): JSX.Element {
},
});
const { mutate: revokeKey, isLoading: isRevoking } =
useRevokeServiceAccountKey({
mutation: {
onSuccess: async () => {
toast.success('Key revoked successfully');
setIsRevokeConfirmOpen(false);
await setEditKeyId(null);
if (selectedAccountId) {
await invalidateListServiceAccountKeys(queryClient, {
id: selectedAccountId,
});
}
},
// eslint-disable-next-line sonarjs/no-identical-functions
onError: (error) => {
showErrorModal(
convertToApiError(
error as AxiosError<RenderErrorResponseDTO, unknown> | null,
) as APIError,
);
},
const {
mutate: revokeKey,
isLoading: isRevoking,
} = useRevokeServiceAccountKey({
mutation: {
onSuccess: async () => {
toast.success('Key revoked successfully');
setIsRevokeConfirmOpen(false);
await setEditKeyId(null);
if (selectedAccountId) {
await invalidateListServiceAccountKeys(queryClient, {
id: selectedAccountId,
});
}
},
});
// eslint-disable-next-line sonarjs/no-identical-functions
onError: (error) => {
showErrorModal(
convertToApiError(
error as AxiosError<RenderErrorResponseDTO, unknown> | null,
) as APIError,
);
},
},
});
function handleClose(): void {
setEditKeyId(null);

View File

@@ -67,29 +67,31 @@ function RevokeKeyModal(): JSX.Element {
const cachedKeys = accountId
? queryClient.getQueryData<{
data: ServiceaccounttypesGettableFactorAPIKeyDTO[];
}>(getListServiceAccountKeysQueryKey({ id: accountId }))
}>(getListServiceAccountKeysQueryKey({ id: accountId }))
: null;
const keyName = cachedKeys?.data?.find((k) => k.id === revokeKeyId)?.name;
const { mutate: revokeKey, isLoading: isRevoking } =
useRevokeServiceAccountKey({
mutation: {
onSuccess: async () => {
toast.success('Key revoked successfully');
await setRevokeKeyId(null);
if (accountId) {
await invalidateListServiceAccountKeys(queryClient, { id: accountId });
}
},
onError: (error) => {
showErrorModal(
convertToApiError(
error as AxiosError<RenderErrorResponseDTO, unknown> | null,
) as APIError,
);
},
const {
mutate: revokeKey,
isLoading: isRevoking,
} = useRevokeServiceAccountKey({
mutation: {
onSuccess: async () => {
toast.success('Key revoked successfully');
await setRevokeKeyId(null);
if (accountId) {
await invalidateListServiceAccountKeys(queryClient, { id: accountId });
}
},
});
onError: (error) => {
showErrorModal(
convertToApiError(
error as AxiosError<RenderErrorResponseDTO, unknown> | null,
) as APIError,
);
},
},
});
function handleConfirm(): void {
if (!revokeKeyId || !accountId) {

View File

@@ -231,19 +231,21 @@ function ServiceAccountDrawer({
}, []);
const makeRoleRetry = useCallback(
(context: string, rawRetry: () => Promise<void>) =>
async (): Promise<void> => {
try {
await rawRetry();
setSaveErrors((prev) => prev.filter((e) => e.context !== context));
} catch (err) {
setSaveErrors((prev) =>
prev.map((e) =>
e.context === context ? { ...e, apiError: toSaveApiError(err) } : e,
),
);
}
},
(
context: string,
rawRetry: () => Promise<void>,
) => async (): Promise<void> => {
try {
await rawRetry();
setSaveErrors((prev) => prev.filter((e) => e.context !== context));
} catch (err) {
setSaveErrors((prev) =>
prev.map((e) =>
e.context === context ? { ...e, apiError: toSaveApiError(err) } : e,
),
);
}
},
[],
);
@@ -300,7 +302,7 @@ function ServiceAccountDrawer({
? updateMutateAsync({
pathParams: { id: account.id },
data: { name: localName },
})
})
: Promise.resolve();
const [nameResult, rolesResult] = await Promise.allSettled([

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