Compare commits

..

23 Commits

Author SHA1 Message Date
swapnil-signoz
1296ae627d refactor: updating types 2026-04-23 01:34:10 +05:30
swapnil-signoz
3ab42a9012 refactor: update Azure service identifiers 2026-04-22 17:42:23 +05:30
swapnil-signoz
7f5d1d8ddb refactor: updating azure blob storage service name 2026-04-22 14:41:02 +05:30
swapnil-signoz
e3374d0bf3 refactor: updating strategy struct 2026-04-22 13:52:30 +05:30
swapnil-signoz
2714ded0b5 fix: handle optional connection URL in AWS integration 2026-04-22 01:45:56 +05:30
swapnil-signoz
c54513c327 Merge branch 'main' into feat/cloudintegration-azure-types 2026-04-22 01:44:25 +05:30
Yunus M
dfa8625e3d refactor: update styles and components for consistency and improved UI (#11043)
Some checks failed
build-staging / staging (push) Has been cancelled
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
2026-04-21 19:58:42 +00:00
swapnil-signoz
a60f8551dd feat: adding missing AWS regions (#11039)
* feat: adding missing AWS regions

* feat: fe add new AWS regions for Mexico and Asia Pacific

* refactor: adding missing region in migration as well
2026-04-21 19:28:01 +00:00
Tushar Vats
e607908b29 fix: not_in expression in having input box (#11035)
Some checks failed
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
* fix: not_in expression in having input box

* fix: revert spacing check
2026-04-21 17:05:35 +00:00
swapnil-signoz
210ac2e74b feat: adding migration AWS cloud integration regions config (#10983)
* feat: adding migration AWS cloud integration regions config

* refactor: removing raw queries

* refactor: using table expr for table name

* refactor: using updated AWS regions declaration

* refactor: cleanup

* refactor: update AWS region migration logic to use new configuration method

* refactor: adding aws regions in migration

---------

Co-authored-by: Vikrant Gupta <vikrant@signoz.io>
2026-04-21 16:53:55 +00:00
swapnil-signoz
7050a9a841 refactor: updating command key 2026-04-20 22:05:42 +05:30
swapnil-signoz
d65628d989 Merge branch 'main' into feat/cloudintegration-azure-types 2026-04-20 18:47:53 +05:30
swapnil-signoz
ff38502517 Merge branch 'main' into feat/cloudintegration-azure-types 2026-04-20 16:32:34 +05:30
swapnil-signoz
617afeb64b refactor: lint issues 2026-04-20 15:01:26 +05:30
swapnil-signoz
3737905670 feat: completing azure types 2026-04-20 14:37:49 +05:30
swapnil-signoz
54c79642f5 refactor: updating azure integration config 2026-04-20 11:19:41 +05:30
swapnil-signoz
0682c528da refactor: updating omitempty tags 2026-04-20 10:26:08 +05:30
swapnil-signoz
3377bc8a2b feat: adding azure services 2026-04-20 09:51:43 +05:30
swapnil-signoz
3b0d5dcf0e feat: adding cloud integration azure types 2026-04-19 19:20:06 +05:30
swapnil-signoz
aa8c4471dc refactor: using upper case key for AWS 2026-04-19 00:49:02 +05:30
swapnil-signoz
04b8ef4d86 refactor: separating cloud provider types 2026-04-19 00:24:13 +05:30
swapnil-signoz
9aee83607f Merge branch 'main' into refactor/cloudprovider-types-separation 2026-04-19 00:17:15 +05:30
swapnil-signoz
d8abbce47e refactor: moving types to cloud provider specific namespace/pkg 2026-04-17 11:57:41 +05:30
68 changed files with 918 additions and 1499 deletions

View File

@@ -668,8 +668,8 @@ components:
properties:
aws:
$ref: '#/components/schemas/CloudintegrationtypesAWSAccountConfig'
required:
- aws
azure:
$ref: '#/components/schemas/CloudintegrationtypesAzureAccountConfig'
type: object
CloudintegrationtypesAgentReport:
nullable: true
@@ -693,6 +693,90 @@ components:
nullable: true
type: array
type: object
CloudintegrationtypesAzureAccountConfig:
properties:
deploymentRegion:
type: string
resourceGroups:
items:
type: string
type: array
required:
- deploymentRegion
- resourceGroups
type: object
CloudintegrationtypesAzureConnectionArtifact:
properties:
cliCommand:
type: string
cloudPowerShellCommand:
type: string
required:
- cliCommand
- cloudPowerShellCommand
type: object
CloudintegrationtypesAzureIntegrationConfig:
properties:
deploymentRegion:
type: string
resourceGroups:
items:
type: string
type: array
telemetryCollectionStrategy:
items:
$ref: '#/components/schemas/CloudintegrationtypesAzureTelemetryCollectionStrategy'
type: array
required:
- deploymentRegion
- resourceGroups
- telemetryCollectionStrategy
type: object
CloudintegrationtypesAzureLogsCollectionStrategy:
properties:
categoryGroups:
items:
type: string
type: array
required:
- categoryGroups
type: object
CloudintegrationtypesAzureMetricsCollectionStrategy:
type: object
CloudintegrationtypesAzureServiceConfig:
properties:
logs:
$ref: '#/components/schemas/CloudintegrationtypesAzureServiceLogsConfig'
metrics:
$ref: '#/components/schemas/CloudintegrationtypesAzureServiceMetricsConfig'
required:
- logs
- metrics
type: object
CloudintegrationtypesAzureServiceLogsConfig:
properties:
enabled:
type: boolean
type: object
CloudintegrationtypesAzureServiceMetricsConfig:
properties:
enabled:
type: boolean
type: object
CloudintegrationtypesAzureTelemetryCollectionStrategy:
properties:
logs:
$ref: '#/components/schemas/CloudintegrationtypesAzureLogsCollectionStrategy'
metrics:
$ref: '#/components/schemas/CloudintegrationtypesAzureMetricsCollectionStrategy'
resourceProvider:
type: string
resourceType:
type: string
required:
- resourceProvider
- resourceType
type: object
CloudintegrationtypesCloudIntegrationService:
nullable: true
properties:
@@ -737,8 +821,8 @@ components:
properties:
aws:
$ref: '#/components/schemas/CloudintegrationtypesAWSConnectionArtifact'
required:
- aws
azure:
$ref: '#/components/schemas/CloudintegrationtypesAzureConnectionArtifact'
type: object
CloudintegrationtypesCredentials:
properties:
@@ -910,8 +994,8 @@ components:
properties:
aws:
$ref: '#/components/schemas/CloudintegrationtypesAWSPostableAccountConfig'
required:
- aws
azure:
$ref: '#/components/schemas/CloudintegrationtypesAzureAccountConfig'
type: object
CloudintegrationtypesPostableAgentCheckIn:
properties:
@@ -934,8 +1018,8 @@ components:
properties:
aws:
$ref: '#/components/schemas/CloudintegrationtypesAWSIntegrationConfig'
required:
- aws
azure:
$ref: '#/components/schemas/CloudintegrationtypesAzureIntegrationConfig'
type: object
CloudintegrationtypesService:
properties:
@@ -972,8 +1056,8 @@ components:
properties:
aws:
$ref: '#/components/schemas/CloudintegrationtypesAWSServiceConfig'
required:
- aws
azure:
$ref: '#/components/schemas/CloudintegrationtypesAzureServiceConfig'
type: object
CloudintegrationtypesServiceID:
enum:
@@ -990,6 +1074,8 @@ components:
- s3sync
- sns
- sqs
- storageaccountsblob
- cdnprofile
type: string
CloudintegrationtypesServiceMetadata:
properties:
@@ -1018,16 +1104,32 @@ components:
properties:
aws:
$ref: '#/components/schemas/CloudintegrationtypesAWSTelemetryCollectionStrategy'
required:
- aws
azure:
$ref: '#/components/schemas/CloudintegrationtypesAzureTelemetryCollectionStrategy'
type: object
CloudintegrationtypesUpdatableAccount:
properties:
config:
$ref: '#/components/schemas/CloudintegrationtypesAccountConfig'
$ref: '#/components/schemas/CloudintegrationtypesUpdatableAccountConfig'
required:
- config
type: object
CloudintegrationtypesUpdatableAccountConfig:
properties:
aws:
$ref: '#/components/schemas/CloudintegrationtypesAWSAccountConfig'
azure:
$ref: '#/components/schemas/CloudintegrationtypesUpdatableAzureAccountConfig'
type: object
CloudintegrationtypesUpdatableAzureAccountConfig:
properties:
resourceGroups:
items:
type: string
type: array
required:
- resourceGroups
type: object
CloudintegrationtypesUpdatableService:
properties:
config:

View File

@@ -795,7 +795,8 @@ export interface CloudintegrationtypesAccountDTO {
}
export interface CloudintegrationtypesAccountConfigDTO {
aws: CloudintegrationtypesAWSAccountConfigDTO;
aws?: CloudintegrationtypesAWSAccountConfigDTO;
azure?: CloudintegrationtypesAzureAccountConfigDTO;
}
/**
@@ -829,6 +830,86 @@ export interface CloudintegrationtypesAssetsDTO {
dashboards?: CloudintegrationtypesDashboardDTO[] | null;
}
export interface CloudintegrationtypesAzureAccountConfigDTO {
/**
* @type string
*/
deploymentRegion: string;
/**
* @type array
*/
resourceGroups: string[];
}
export interface CloudintegrationtypesAzureConnectionArtifactDTO {
/**
* @type string
*/
cliCommand: string;
/**
* @type string
*/
cloudPowerShellCommand: string;
}
export interface CloudintegrationtypesAzureIntegrationConfigDTO {
/**
* @type string
*/
deploymentRegion: string;
/**
* @type array
*/
resourceGroups: string[];
/**
* @type array
*/
telemetryCollectionStrategy: CloudintegrationtypesAzureTelemetryCollectionStrategyDTO[];
}
export interface CloudintegrationtypesAzureLogsCollectionStrategyDTO {
/**
* @type array
*/
categoryGroups: string[];
}
export interface CloudintegrationtypesAzureMetricsCollectionStrategyDTO {
[key: string]: unknown;
}
export interface CloudintegrationtypesAzureServiceConfigDTO {
logs: CloudintegrationtypesAzureServiceLogsConfigDTO;
metrics: CloudintegrationtypesAzureServiceMetricsConfigDTO;
}
export interface CloudintegrationtypesAzureServiceLogsConfigDTO {
/**
* @type boolean
*/
enabled?: boolean;
}
export interface CloudintegrationtypesAzureServiceMetricsConfigDTO {
/**
* @type boolean
*/
enabled?: boolean;
}
export interface CloudintegrationtypesAzureTelemetryCollectionStrategyDTO {
logs?: CloudintegrationtypesAzureLogsCollectionStrategyDTO;
metrics?: CloudintegrationtypesAzureMetricsCollectionStrategyDTO;
/**
* @type string
*/
resourceProvider: string;
/**
* @type string
*/
resourceType: string;
}
/**
* @nullable
*/
@@ -890,7 +971,8 @@ export interface CloudintegrationtypesCollectedMetricDTO {
}
export interface CloudintegrationtypesConnectionArtifactDTO {
aws: CloudintegrationtypesAWSConnectionArtifactDTO;
aws?: CloudintegrationtypesAWSConnectionArtifactDTO;
azure?: CloudintegrationtypesAzureConnectionArtifactDTO;
}
export interface CloudintegrationtypesCredentialsDTO {
@@ -1072,7 +1154,8 @@ export interface CloudintegrationtypesPostableAccountDTO {
}
export interface CloudintegrationtypesPostableAccountConfigDTO {
aws: CloudintegrationtypesAWSPostableAccountConfigDTO;
aws?: CloudintegrationtypesAWSPostableAccountConfigDTO;
azure?: CloudintegrationtypesAzureAccountConfigDTO;
}
/**
@@ -1107,7 +1190,8 @@ export interface CloudintegrationtypesPostableAgentCheckInDTO {
}
export interface CloudintegrationtypesProviderIntegrationConfigDTO {
aws: CloudintegrationtypesAWSIntegrationConfigDTO;
aws?: CloudintegrationtypesAWSIntegrationConfigDTO;
azure?: CloudintegrationtypesAzureIntegrationConfigDTO;
}
export interface CloudintegrationtypesServiceDTO {
@@ -1135,7 +1219,8 @@ export interface CloudintegrationtypesServiceDTO {
}
export interface CloudintegrationtypesServiceConfigDTO {
aws: CloudintegrationtypesAWSServiceConfigDTO;
aws?: CloudintegrationtypesAWSServiceConfigDTO;
azure?: CloudintegrationtypesAzureServiceConfigDTO;
}
export enum CloudintegrationtypesServiceIDDTO {
@@ -1152,6 +1237,8 @@ export enum CloudintegrationtypesServiceIDDTO {
s3sync = 's3sync',
sns = 'sns',
sqs = 'sqs',
storageaccountsblob = 'storageaccountsblob',
cdnprofile = 'cdnprofile',
}
export interface CloudintegrationtypesServiceMetadataDTO {
/**
@@ -1184,11 +1271,24 @@ export interface CloudintegrationtypesSupportedSignalsDTO {
}
export interface CloudintegrationtypesTelemetryCollectionStrategyDTO {
aws: CloudintegrationtypesAWSTelemetryCollectionStrategyDTO;
aws?: CloudintegrationtypesAWSTelemetryCollectionStrategyDTO;
azure?: CloudintegrationtypesAzureTelemetryCollectionStrategyDTO;
}
export interface CloudintegrationtypesUpdatableAccountDTO {
config: CloudintegrationtypesAccountConfigDTO;
config: CloudintegrationtypesUpdatableAccountConfigDTO;
}
export interface CloudintegrationtypesUpdatableAccountConfigDTO {
aws?: CloudintegrationtypesAWSAccountConfigDTO;
azure?: CloudintegrationtypesUpdatableAzureAccountConfigDTO;
}
export interface CloudintegrationtypesUpdatableAzureAccountConfigDTO {
/**
* @type array
*/
resourceGroups: string[];
}
export interface CloudintegrationtypesUpdatableServiceDTO {

View File

@@ -1,14 +1,8 @@
.download-popover {
.ant-popover-inner {
border-radius: 4px;
border: 1px solid var(--l1-border);
background: linear-gradient(
139deg,
var(--l2-background) 0%,
var(--l3-background) 98.68%
);
background-color: var(--l2-background);
box-shadow: 4px 10px 16px 2px rgba(0, 0, 0, 0.2);
backdrop-filter: blur(20px);
padding: 0 8px 12px 8px;
margin: 6px 0;
}
@@ -19,7 +13,7 @@
.title {
display: flex;
color: var(--l3-foreground);
color: var(--l1-foreground);
font-family: Inter;
font-size: 11px;
font-style: normal;
@@ -38,7 +32,7 @@
flex-direction: column;
:global(.ant-radio-wrapper) {
color: var(--foreground);
color: var(--l1-foreground);
font-family: Inter;
font-size: 13px;
}

View File

@@ -3,13 +3,13 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useSelector } from 'react-redux'; // old code, TODO: fix this correctly
import { useCopyToClipboard, useLocation } from 'react-use';
import { Color, Spacing } from '@signozhq/design-tokens';
import { Button, Divider, Drawer, Radio, Tooltip, Typography } from 'antd';
import { Button } from '@signozhq/ui';
import { Divider, Drawer, Radio, Tooltip, Typography } from 'antd';
import type { RadioChangeEvent } from 'antd/lib';
import cx from 'classnames';
import { LogType } from 'components/Logs/LogStateIndicator/LogStateIndicator';
import QuerySearch from 'components/QueryBuilderV2/QueryV2/QuerySearch/QuerySearch';
import { convertExpressionToFilters } from 'components/QueryBuilderV2/utils';
import { FeatureKeys } from 'constants/features';
import { LOCALSTORAGE } from 'constants/localStorage';
import { QueryParams } from 'constants/query';
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
@@ -46,7 +46,6 @@ import {
TextSelect,
X,
} from 'lucide-react';
import { useAppContext } from 'providers/App/App';
import { AppState } from 'store/reducers';
import { Query, TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { DataSource, StringOperators } from 'types/common/queryBuilder';
@@ -80,10 +79,6 @@ function LogDetailInner({
const [selectedView, setSelectedView] = useState<VIEWS>(selectedTab);
const [isFilterVisible, setIsFilterVisible] = useState<boolean>(false);
const { featureFlags } = useAppContext();
const isBodyJsonQueryEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.ENABLE_BODY_JSON_QUERY)
?.active || false;
const [filters, setFilters] = useState<TagFilter | null>(null);
const [isEdit, setIsEdit] = useState<boolean>(false);
@@ -213,29 +208,11 @@ function LogDetailInner({
}
};
const logBody = useMemo(() => {
if (!isBodyJsonQueryEnabled) {
return log?.body || '';
}
try {
const json = JSON.parse(log?.body || '');
if (typeof json?.message === 'string' && json.message !== '') {
return json.message;
}
return log?.body || '';
} catch (error) {
return log?.body || '';
}
}, [isBodyJsonQueryEnabled, log?.body]);
const htmlBody = useMemo(
() => ({
__html: getSanitizedLogBody(logBody || '', { shouldEscapeHtml: true }),
__html: getSanitizedLogBody(log?.body || '', { shouldEscapeHtml: true }),
}),
[logBody],
[log?.body],
);
const handleJSONCopy = (): void => {
@@ -387,7 +364,9 @@ function LogDetailInner({
mouseLeaveDelay={0}
>
<Button
icon={<ChevronUp size={14} />}
variant="outlined"
color="secondary"
prefix={<ChevronUp size={14} />}
className="log-arrow-btn log-arrow-btn-up"
disabled={isPrevDisabled}
onClick={(): void => handleNavigateLog({ direction: 'previous' })}
@@ -399,7 +378,9 @@ function LogDetailInner({
mouseLeaveDelay={0}
>
<Button
icon={<ChevronDown size={14} />}
variant="outlined"
color="secondary"
prefix={<ChevronDown size={14} />}
className="log-arrow-btn log-arrow-btn-down"
disabled={isNextDisabled}
onClick={(): void => handleNavigateLog({ direction: 'next' })}
@@ -409,8 +390,10 @@ function LogDetailInner({
{showOpenInExplorerBtn && (
<div>
<Button
variant="outlined"
color="secondary"
prefix={<Compass size={16} />}
className="open-in-explorer-btn"
icon={<Compass size={16} />}
onClick={handleOpenInExplorer}
>
Open in Explorer
@@ -435,7 +418,7 @@ function LogDetailInner({
<div className="log-detail-drawer__log">
<Divider type="vertical" className={cx('log-type-indicator', logType)} />
<Tooltip
title={removeEscapeCharacters(logBody)}
title={removeEscapeCharacters(log?.body)}
placement="left"
mouseLeaveDelay={0}
>
@@ -506,8 +489,10 @@ function LogDetailInner({
mouseLeaveDelay={0}
>
<Button
className="action-btn"
icon={<Filter size={16} />}
variant="link"
color="secondary"
size="sm"
prefix={<Filter size={12} />}
onClick={handleFilterVisible}
/>
</Tooltip>
@@ -522,8 +507,10 @@ function LogDetailInner({
mouseLeaveDelay={0}
>
<Button
className="action-btn"
icon={<Copy size={16} />}
variant="link"
color="secondary"
size="sm"
prefix={<Copy size={12} />}
onClick={selectedView === VIEW_TYPES.JSON ? handleJSONCopy : onLogCopy}
/>
</Tooltip>

View File

@@ -1,4 +1,5 @@
import { CSSProperties } from 'react';
import { Color } from '@signozhq/design-tokens';
import { TableProps } from 'antd';
export function getDefaultCellStyle(isDarkMode?: boolean): CSSProperties {
@@ -7,7 +8,7 @@ export function getDefaultCellStyle(isDarkMode?: boolean): CSSProperties {
paddingBottom: 6,
paddingRight: 8,
paddingLeft: 8,
color: isDarkMode ? 'var(--bg-vanilla-400)' : 'var(--bg-slate-400)',
color: isDarkMode ? Color.BG_VANILLA_100 : Color.BG_INK_400,
fontSize: '14px',
fontStyle: 'normal',
fontWeight: 400,

View File

@@ -1,3 +1,4 @@
import { Color } from '@signozhq/design-tokens';
import { FontSize } from 'container/OptionsMenu/types';
import styled from 'styled-components';
@@ -10,7 +11,7 @@ interface TableBodyContentProps {
export const TableBodyContent = styled.div<TableBodyContentProps>`
margin-bottom: 0;
color: ${(props): string =>
props.isDarkMode ? 'var(--bg-vanilla-400, #c0c1c3)' : 'var(--bg-slate-400)'};
props.isDarkMode ? Color.BG_VANILLA_100 : Color.BG_INK_400};
font-size: 14px;
font-style: normal;
font-weight: 400;

View File

@@ -33,8 +33,9 @@
display: flex;
align-items: center;
p {
margin-bottom: 0;
.timestamp-text {
color: var(--l1-foreground);
margin: 0 !important;
}
}

View File

@@ -123,7 +123,7 @@ export const useTableView = (props: UseTableViewProps): UseTableViewResult => {
return {
children: (
<div className="table-timestamp">
<p className={cx('text', fontSize)}>{date}</p>
<p className={cx('timestamp-text text', fontSize)}>{date}</p>
</div>
),
};

View File

@@ -35,7 +35,7 @@
}
.text {
color: var(--muted-foreground);
color: var(--l1-foreground);
font-family: Inter;
font-size: 11px;
font-style: normal;
@@ -93,7 +93,7 @@
gap: 12px;
.title {
color: var(--muted-foreground);
color: var(--l1-foreground);
font-family: Inter;
font-size: 11px;
font-style: normal;
@@ -139,7 +139,8 @@
line-height: 18px;
letter-spacing: 0.08em;
text-align: left;
color: var(--muted-foreground);
color: var(--l1-foreground);
}
.menu-items {
@@ -177,7 +178,7 @@
padding: 12px;
.title {
color: var(--muted-foreground);
color: var(--l1-foreground);
font-family: Inter;
font-size: 11px;
font-style: normal;
@@ -330,7 +331,7 @@
}
.title {
color: var(--muted-foreground);
color: var(--l1-foreground);
font-family: Inter;
font-size: 11px;
font-style: normal;
@@ -486,169 +487,3 @@
}
}
}
.lightMode {
.format-options-popover {
.ant-popover-inner {
border: 1px solid var(--l1-border);
background: linear-gradient(
139deg,
rgba(255, 255, 255, 0.8) 0%,
rgba(255, 255, 255, 0.9) 98.68%
);
box-shadow: 4px 10px 16px 2px rgba(255, 255, 255, 0.2);
.nested-menu-container {
.font-size-dropdown {
.back-btn {
.text {
color: var(--l2-background);
}
}
.content {
.option-btn {
.text {
color: var(--l2-background);
}
.text:hover {
color: var(--l3-background);
}
}
}
}
.add-new-column-container {
.add-new-column-header {
.title {
color: var(--l2-foreground);
}
}
.add-new-column-content {
.column-format-new-options {
.column-name {
color: var(--l2-background);
&.selected {
background-color: var(--l3-background);
}
}
}
.loading-container {
color: var(--l2-background);
}
}
}
.font-size-container {
.title {
color: var(--l2-foreground);
}
.value {
.font-value {
color: var(--l2-background);
}
}
}
.horizontal-line {
background: var(--l3-background);
}
.item-content {
.column-divider {
border-top: 2px solid var(--l1-border);
}
}
.max-lines-per-row {
.title {
color: var(--l2-foreground);
.lucide {
color: var(--l1-foreground);
}
}
.max-lines-per-row-input {
border: 1px solid var(--l1-border);
.periscope-btn {
background: var(--l3-background);
}
}
}
.menu-container {
.title {
color: var(--l2-foreground);
}
.item {
.item-label {
color: var(--l2-background);
}
}
}
.selected-item-content-container {
.title {
color: var(--l2-foreground);
.lucide {
color: var(--l1-foreground);
}
}
.horizontal-line {
background: var(--l3-background);
}
.item-content {
.max-lines-per-row-input {
border: 1px solid var(--l1-border);
.periscope-btn {
background: var(--l3-background);
}
}
.column-format,
.column-format-new-options {
.column-name {
color: var(--l1-foreground);
}
}
}
}
&.active {
.nested-menu-container {
backdrop-filter: blur(18px);
.item {
.item-label {
color: var(--l1-foreground);
}
}
}
.selected-item-content-container {
border: 1px solid var(--l1-border);
background: linear-gradient(
139deg,
rgba(255, 255, 255, 0.8) 0%,
rgba(255, 255, 255, 0.9) 98.68%
);
box-shadow: 4px 10px 16px 2px rgba(255, 255, 255, 0.2);
}
}
}
}
}
}

View File

@@ -50,8 +50,8 @@ const havingOperators = [
value: 'IN',
},
{
label: 'NOT_IN',
value: 'NOT_IN',
label: 'NOT IN',
value: 'NOT IN',
},
];
@@ -129,7 +129,7 @@ function HavingFilter({
const operator = havingOperators[j];
newOptions.push({
label: `${opt.func}(${opt.arg}) ${operator.label}`,
value: `${opt.func}(${opt.arg}) ${operator.label} `,
value: `${opt.func}(${opt.arg}) ${operator.value} `,
apply: (
view: EditorView,
completion: { label: string; value: string },

View File

@@ -11,6 +11,8 @@
&__title {
font-weight: 500;
font-size: 15px;
padding: 0;
margin: 0;
}
&__container {
@@ -19,7 +21,7 @@
background-color: var(--primary-background);
color: var(--primary-foreground);
border-radius: 8px;
padding: 16px;
padding: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
z-index: 1000;
}
@@ -43,14 +45,23 @@
&__footer {
display: flex;
justify-content: flex-end;
}
&__button {
background: var(--secondary-background);
color: var(--secondary-foreground);
border: none;
padding: 6px 12px;
border-radius: 4px;
cursor: pointer;
// TODO: Need to override the button styles for this component due to container styles.
// Fix - @aks07
&__button {
margin-top: 12px;
color: var(--base-black);
background-color: var(--base-white);
border: none;
padding: 6px 12px;
border-radius: 4px;
cursor: pointer;
&:hover {
background-color: var(--base-white);
color: var(--bg-robin-500);
}
}
}
}

View File

@@ -1,7 +1,7 @@
import { useState } from 'react';
import { Button, Typography } from 'antd';
import { Button } from '@signozhq/ui';
import classNames from 'classnames';
import { X } from 'lucide-react';
import { Check, X } from 'lucide-react';
import './AnnouncementTooltip.styles.scss';
@@ -46,13 +46,12 @@ function AnnouncementTooltip({
className={classNames('announcement-tooltip__container', className)}
style={{
top: position.top,
left: position.left + 30,
left: position.left + 20,
}}
>
<div className="announcement-tooltip__header">
<Typography.Text className="announcement-tooltip__title">
{title}
</Typography.Text>
<p className="announcement-tooltip__title">{title}</p>
<X
size={18}
onClick={closeTooltip}
@@ -61,7 +60,13 @@ function AnnouncementTooltip({
</div>
<p className="announcement-tooltip__message">{message}</p>
<div className="announcement-tooltip__footer">
<Button onClick={closeTooltip} className="announcement-tooltip__button">
<Button
variant="solid"
color="primary"
onClick={closeTooltip}
prefix={<Check size={16} />}
className="announcement-tooltip__footer__button"
>
Okay
</Button>
</div>

View File

@@ -9,5 +9,4 @@ export enum FeatureKeys {
ANOMALY_DETECTION = 'anomaly_detection',
ONBOARDING_V3 = 'onboarding_v3',
DOT_METRICS_ENABLED = 'dot_metrics_enabled',
ENABLE_BODY_JSON_QUERY = 'enable_body_json_query',
}

View File

@@ -22,7 +22,7 @@
.domain-detail-drawer {
border-left: 1px solid var(--l1-border);
background: var(--l2-background);
background: var(--l2-background) !important;
box-shadow: -4px 10px 16px 2px rgba(0, 0, 0, 0.2);
.ant-drawer-header {
@@ -309,16 +309,12 @@
}
.ant-table-tbody > tr:hover > td {
background: color-mix(in srgb, var(--l1-foreground) 4%, transparent);
background-color: var(--l2-background);
cursor: pointer;
}
.ant-table-tbody > tr:hover > td:has(.endpoint-name-value) {
background: color-mix(
in srgb,
var(--l1-foreground) 4%,
color-mix(in srgb, var(--l3-background) 60%, transparent)
);
background-color: var(--l2-background);
}
.ant-table-cell:first-child {
@@ -359,10 +355,6 @@
background: none;
}
.table-row-dark {
background: var(--l3-background);
}
.endpoint-name-value {
display: flex;
align-items: center;
@@ -536,7 +528,7 @@
}
.ant-table-tbody > tr:hover > td {
background: color-mix(in srgb, var(--l1-foreground) 4%, transparent);
background: color-mix(in srgb, var(--l1-background) 4%, transparent);
}
.ant-table-tbody > tr:hover > td:has(.status-code-value) {
@@ -586,7 +578,7 @@
}
.table-row-dark {
background: var(--l3-background);
background: var(--l2-background);
}
.endpoint-name-value {
@@ -768,6 +760,7 @@
.dependent-services-container {
border-radius: 3px;
border: 1px solid var(--l1-border);
.ant-table {
.ant-table-thead > tr > th {
padding: 12px;
@@ -797,7 +790,7 @@
}
.ant-table-cell {
padding: 12px;
padding: 0px;
font-size: 13px;
line-height: 20px;
color: var(--l1-foreground);
@@ -812,13 +805,11 @@
.ant-table-cell:has(.top-services-item-latency) {
text-align: center;
opacity: 0.8;
background: color-mix(in srgb, var(--bg-robin-200) 4%, transparent);
}
.ant-table-cell:has(.top-services-item-latency-title) {
text-align: center;
opacity: 0.8;
background: color-mix(in srgb, var(--bg-robin-200) 4%, transparent);
}
.ant-table-tbody > tr:hover > td {
@@ -853,7 +844,7 @@
}
.table-row-dark {
background: var(--l3-background);
background: var(--l2-background);
}
.ant-table-content {
@@ -911,7 +902,6 @@
}
.top-services-item-progress-bar {
background-color: var(--l1-border);
border-radius: 2px;
height: 100%;
position: absolute;
@@ -1027,213 +1017,3 @@
overflow-wrap: break-word;
}
}
.lightMode {
.domain-navigate-cta {
border: 1px solid var(--l1-border);
color: var(--l2-foreground);
}
.domain-detail-drawer {
.endpoint-details-card,
.status-code-table-container,
.endpoint-details-filters-container,
.endpoint-details-filters-container-dropdown,
.ant-radio-button-wrapper,
.views-tabs-container,
.ant-btn-default.tab,
.tab::before,
.endpoint-meta-data-pill,
.endpoint-meta-data-label,
.endpoints-table-container,
.group-by-label,
.ant-select-selector,
.ant-drawer-header {
border-color: var(--l1-border) !important;
}
.views-tabs .tab::before {
background: var(--l3-background);
}
.title {
color: var(--l2-foreground);
}
.domain-detail-drawer__endpoint {
.ant-typography {
color: var(--l2-foreground);
background: transparent;
}
}
.radio-button {
border: 1px solid var(--l1-border);
color: var(--l2-foreground);
}
.views-tabs {
.tab {
background: var(--l3-background);
}
.selected_view {
background: var(--l3-background);
}
.selected_view::before {
background: var(--l3-background);
border-left: 1px solid var(--l1-border);
}
}
}
.round-metric-tag {
color: var(--l1-foreground);
}
.group-by-container {
.group-by-label {
color: var(--l2-foreground);
}
}
.endpoints-table-container {
.ant-table {
.ant-table-cell {
color: var(--l1-foreground);
}
.table-row-light {
background: none;
}
.table-row-dark {
background: none;
}
.round-metric-tag {
color: var(--l1-foreground);
}
}
}
.endpoint-meta-data {
.endpoint-meta-data-pill {
.endpoint-meta-data-label {
color: var(--l2-foreground);
}
.endpoint-meta-data-value {
color: var(--l2-foreground);
}
}
}
.status-code-table-container {
.ant-table {
.ant-table-cell {
color: var(--l1-foreground);
}
.table-row-light {
background: none;
}
.table-row-dark {
background: none;
}
.round-metric-tag {
color: var(--l1-foreground);
}
}
}
.top-services-content {
border-color: var(--l1-border);
}
.dependent-services-container {
border: none;
padding: 10px 12px;
.top-services-item {
display: flex;
justify-content: space-between;
align-items: center;
.top-services-item-progress {
display: flex;
gap: 12px;
height: 34px;
width: 100%;
color: var(--l1-foreground);
padding: 0 12px;
margin-right: 12px;
align-items: center;
position: relative;
.top-services-item-key {
color: var(--l2-foreground);
}
.top-services-item-count {
background-color: var(--l3-background);
color: var(--l2-foreground);
}
.top-services-item-progress-bar {
background-color: var(--l2-background);
border: 1px solid var(--l1-border);
}
}
}
.ant-table {
.ant-table-thead > tr > th {
color: var(--l2-foreground);
}
.ant-table-cell {
color: var(--l2-foreground);
}
.ant-table-tbody > tr:hover > td {
background: var(--l2-background);
}
.table-row-dark {
background: var(--l3-background);
}
}
.top-services-item-percentage {
color: var(--l2-foreground);
}
.top-services-load-more {
color: var(--l2-foreground);
}
}
.error-state-container {
.error-state-content-wrapper {
.refresh-cta {
color: var(--l2-foreground);
border: 1px solid var(--l1-border);
}
}
}
.end-point-details-zero-state-wrapper {
.end-point-details-zero-state-content-wrapper {
.end-point-details-zero-state-text-content {
.title {
color: var(--l2-foreground);
}
.description {
color: var(--l1-foreground);
}
}
}
}
// Add border-bottom to table cells when pagination is not present
.ant-spin-container:not(:has(.ant-pagination)) .ant-table-cell {
border-bottom: 1px solid var(--l1-border) !important;
}
}

View File

@@ -71,7 +71,7 @@
}
.ant-table-thead > tr > th:has(.domain-list-name-col-header) {
background: color-mix(in srgb, var(--l3-background) 60%, transparent);
background: var(--l2-background);
}
.ant-table-cell {
@@ -83,7 +83,7 @@
}
.ant-table-cell:has(.domain-list-name-col-value) {
background: color-mix(in srgb, var(--l3-background) 60%, transparent);
background: var(--l2-background);
}
.round-metric-tag {
@@ -107,7 +107,7 @@
background: color-mix(
in srgb,
var(--l1-foreground) 4%,
color-mix(in srgb, var(--l3-background) 60%, transparent)
var(--l2-background)
);
}
@@ -147,7 +147,7 @@
}
.table-row-dark {
background: var(--l3-background);
background: var(--l2-background);
}
.expanded-clickable-row {

View File

@@ -98,27 +98,6 @@
align-items: center;
gap: 8px;
button {
display: flex;
justify-content: center;
align-items: center;
border: none;
border: 1px solid var(--l1-border);
box-shadow: none !important;
&.ant-btn-round {
padding: 8px 12px 8px 10px;
font-weight: 500;
}
&.ant-btn-round:disabled {
background-color: rgba(209, 209, 209, 0.074);
color: var(--muted-foreground);
}
}
.ant-select-focused {
border-color: transparent !important;
@@ -140,6 +119,12 @@
.hidden {
display: none;
}
button {
display: flex;
align-items: center;
justify-content: center;
}
}
.app-content {
@@ -233,19 +218,6 @@
justify-content: flex-end;
padding: 16px 16px;
margin: 0;
> button {
display: flex;
align-items: center;
border-radius: 2px;
background-color: var(--primary-background) !important;
color: var(--l1-foreground) !important;
font-family: Inter;
font-size: 12px;
font-style: normal;
font-weight: 500;
line-height: 24px;
}
}
}
.title {
@@ -257,97 +229,3 @@
line-height: 20px;
}
}
.lightMode {
.explorer-options-container {
background: var(--l1-background);
}
.explorer-options {
background: transparent;
box-shadow: none;
border: 1px solid var(--l1-border);
backdrop-filter: blur(20px);
hr {
border-color: var(--l1-border);
}
.view-options,
.actions {
button {
border: 1px solid var(--l1-border);
color: var(--l2-foreground);
background-color: var(--l3-background);
}
.info-icon {
color: var(--l2-foreground);
}
}
}
.render-options {
color: var(--l2-foreground);
}
.explorer-update {
border: 1px solid var(--l1-border);
background: transparent;
box-shadow: 4px 4px 16px 4px rgba(255, 255, 255, 0.55);
backdrop-filter: blur(20px);
.action-icon {
border: 1px solid var(--l1-border);
background: var(--l3-background);
}
.ant-divider {
border-color: var(--l1-border);
}
}
.ant-tooltip-arrow {
border-top-color: var(--l1-border) !important;
}
.ant-tooltip-inner {
background-color: var(--l3-background);
color: var(--l2-foreground);
}
.save-view-modal {
.ant-modal-content {
background: var(--l2-background);
border-color: var(--l1-border);
.ant-modal-header {
background: var(--l2-background);
border-bottom: 1px solid var(--l1-border);
}
.ant-modal-body {
.ant-typography {
color: var(--l2-foreground);
}
.ant-color-picker-trigger {
border: 1px solid var(--l1-border);
background: var(--l1-background);
.ant-color-picker-color-block {
.ant-color-picker-color-block-inner {
svg {
fill: var(--l2-foreground);
}
}
}
}
}
}
.title {
color: var(--l2-foreground);
}
}
}

View File

@@ -8,19 +8,8 @@ import {
OPERATORS,
QUERY_BUILDER_FUNCTIONS,
} from 'constants/antlrQueryConstants';
import { FeatureKeys } from 'constants/features';
import { QueryParams } from 'constants/query';
import { useActiveLog } from 'hooks/logs/useActiveLog';
import { useGetSearchQueryParam } from 'hooks/queryBuilder/useGetSearchQueryParam';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { ICurrentQueryData } from 'hooks/useHandleExplorerTabChange';
import { useNotifications } from 'hooks/useNotifications';
import { ExplorerViews } from 'pages/LogsExplorer/utils';
import { useAppContext } from 'providers/App/App';
import {
BaseAutocompleteData,
DataTypes,
} from 'types/api/queryBuilder/queryAutocompleteResponse';
import { TitleWrapper } from './BodyTitleRenderer.styles';
import { DROPDOWN_KEY } from './constant';
@@ -36,32 +25,17 @@ function BodyTitleRenderer({
parentIsArray = false,
nodeKey,
value,
handleChangeSelectedView,
}: BodyTitleRendererProps): JSX.Element {
const { onAddToQuery } = useActiveLog();
const { stagedQuery, updateQueriesData } = useQueryBuilder();
const { featureFlags } = useAppContext();
const [, setCopy] = useCopyToClipboard();
const { notifications } = useNotifications();
const viewName = useGetSearchQueryParam(QueryParams.viewName) || '';
const cleanedNodeKey = removeObjectFromString(nodeKey);
const isBodyJsonQueryEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.ENABLE_BODY_JSON_QUERY)
?.active || false;
// Group by is supported only for body json query enabled and not for array elements
const isGroupBySupported =
isBodyJsonQueryEnabled && !cleanedNodeKey.includes('[]');
const filterHandler = (isFilterIn: boolean) => (): void => {
if (parentIsArray) {
onAddToQuery(
generateFieldKeyForArray(
cleanedNodeKey,
removeObjectFromString(nodeKey),
getDataTypes(value),
isBodyJsonQueryEnabled,
),
`${value}`,
isFilterIn
@@ -71,7 +45,7 @@ function BodyTitleRenderer({
);
} else {
onAddToQuery(
`body.${cleanedNodeKey}`,
`body.${removeObjectFromString(nodeKey)}`,
`${value}`,
isFilterIn ? OPERATORS['='] : OPERATORS['!='],
getDataTypes(value),
@@ -79,67 +53,10 @@ function BodyTitleRenderer({
}
};
const groupByHandler = useCallback((): void => {
if (!stagedQuery) {
return;
}
const groupByKey = parentIsArray
? generateFieldKeyForArray(
cleanedNodeKey,
getDataTypes(value),
isBodyJsonQueryEnabled,
)
: `body.${cleanedNodeKey}`;
const fieldDataType = getDataTypes(value);
const normalizedDataType: DataTypes | undefined = Object.values(
DataTypes,
).includes(fieldDataType as DataTypes)
? (fieldDataType as DataTypes)
: undefined;
const updatedQuery = updateQueriesData(
stagedQuery,
'queryData',
(item, index) => {
if (index === 0) {
const newGroupByItem: BaseAutocompleteData = {
key: groupByKey,
type: '',
dataType: normalizedDataType,
};
return { ...item, groupBy: [...(item.groupBy || []), newGroupByItem] };
}
return item;
},
);
const queryData: ICurrentQueryData = {
name: viewName,
id: updatedQuery.id,
query: updatedQuery,
};
handleChangeSelectedView?.(ExplorerViews.TIMESERIES, queryData);
}, [
cleanedNodeKey,
handleChangeSelectedView,
isBodyJsonQueryEnabled,
parentIsArray,
stagedQuery,
updateQueriesData,
value,
viewName,
]);
const onClickHandler: MenuProps['onClick'] = (props): void => {
const mapper = {
[DROPDOWN_KEY.FILTER_IN]: filterHandler(true),
[DROPDOWN_KEY.FILTER_OUT]: filterHandler(false),
[DROPDOWN_KEY.GROUP_BY]: groupByHandler,
};
const handler = mapper[props.key];
@@ -159,14 +76,6 @@ function BodyTitleRenderer({
key: DROPDOWN_KEY.FILTER_OUT,
label: `Filter out ${value}`,
},
...(isGroupBySupported
? [
{
key: DROPDOWN_KEY.GROUP_BY,
label: `Group by ${nodeKey}`,
},
]
: []),
],
onClick: onClickHandler,
};
@@ -175,6 +84,7 @@ function BodyTitleRenderer({
(e: React.MouseEvent): void => {
// Prevent tree node expansion/collapse
e.stopPropagation();
const cleanedKey = removeObjectFromString(nodeKey);
let copyText: string;
// Check if value is an object or array
@@ -196,8 +106,8 @@ function BodyTitleRenderer({
if (copyText) {
const notificationMessage = isObject
? `${cleanedNodeKey} object copied to clipboard`
: `${cleanedNodeKey} copied to clipboard`;
? `${cleanedKey} object copied to clipboard`
: `${cleanedKey} copied to clipboard`;
notifications.success({
message: notificationMessage,
@@ -205,7 +115,7 @@ function BodyTitleRenderer({
});
}
},
[cleanedNodeKey, parentIsArray, setCopy, value, notifications],
[nodeKey, parentIsArray, setCopy, value, notifications],
);
return (

View File

@@ -1,4 +1,3 @@
import { ChangeViewFunctionType } from 'container/ExplorerOptions/types';
import { MetricsType } from 'container/MetricsApplication/constant';
import { ILog } from 'types/api/logs/log';
@@ -7,7 +6,6 @@ export interface BodyTitleRendererProps {
nodeKey: string;
value: unknown;
parentIsArray?: boolean;
handleChangeSelectedView?: ChangeViewFunctionType;
}
export type AnyObject = { [key: string]: any };

View File

@@ -50,7 +50,8 @@
.ant-collapse-header {
align-items: center;
border-radius: 2px;
background: color-mix(in srgb, var(--bg-robin-200) 4%, transparent);
background-color: var(--l3-background);
border: 1px solid var(--l3-border);
padding: 8px;
@@ -70,7 +71,7 @@
.ant-collapse-content {
padding: 0;
background: var(--l1-background);
background: var(--l2-background);
border-top: 1px solid var(--l1-border);
.ant-collapse-content-box {

View File

@@ -1,15 +1,8 @@
import { ReactNode, useState } from 'react';
import MEditor, { EditorProps, Monaco } from '@monaco-editor/react';
import { Color } from '@signozhq/design-tokens';
import {
Button,
Collapse,
Divider,
Input,
Switch,
Tag,
Typography,
} from 'antd';
import { Button } from '@signozhq/ui';
import { Collapse, Divider, Input, Switch, Tag, Typography } from 'antd';
import { AddToQueryHOCProps } from 'components/Logs/AddToQueryHOC';
import { ChangeViewFunctionType } from 'container/ExplorerOptions/types';
import { OptionsQuery } from 'container/OptionsMenu/types';
@@ -178,13 +171,17 @@ function Overview({
{isAttributesExpanded && (
<Button
variant="link"
color="none"
className="action-btn"
icon={<Search size={12} />}
prefix={<Search size={12} />}
onClick={(e): void => {
e.stopPropagation();
handleSearchVisible();
}}
/>
>
Search
</Button>
)}
</div>
),

View File

@@ -1,6 +1,6 @@
.attribute-table-container {
.ant-table {
background: var(--l1-background);
background: var(--l2-background);
.ant-table-row:hover {
.ant-table-cell {
@@ -19,6 +19,7 @@
.ant-table-cell {
border: 1px solid var(--l1-border);
background: var(--l2-background);
}
.attribute-name {
@@ -54,10 +55,10 @@
}
.value-field-container {
background: var(--l3-background);
background: var(--l2-background);
&.attribute-pin {
background: var(--l1-background);
background: var(--l2-background);
}
.value-field {

View File

@@ -2,7 +2,6 @@ import React, { useCallback, useMemo, useState } from 'react';
import { useLocation } from 'react-router-dom';
import { Color } from '@signozhq/design-tokens';
import { Button, Popover, Spin, Tooltip, Tree } from 'antd';
import type { DataNode } from 'antd/es/tree';
import GroupByIcon from 'assets/CustomIcons/GroupByIcon';
import cx from 'classnames';
import CopyClipboardHOC from 'components/Logs/CopyClipboardHOC';
@@ -58,7 +57,7 @@ interface ITableViewActionsProps {
}
// Memoized Tree Component
const MemoizedTree = React.memo<{ treeData: DataNode[] }>(({ treeData }) => (
const MemoizedTree = React.memo<{ treeData: any[] }>(({ treeData }) => (
<Tree
defaultExpandAll
showLine
@@ -75,54 +74,50 @@ const BodyContent: React.FC<{
record: DataType;
bodyHtml: { __html: string };
textToCopy: string;
handleChangeSelectedView?: ChangeViewFunctionType;
}> = React.memo(
({ fieldData, record, bodyHtml, textToCopy, handleChangeSelectedView }) => {
const { isLoading, treeData, error } = useAsyncJSONProcessing(
fieldData.value,
record.field === 'body',
handleChangeSelectedView,
}> = React.memo(({ fieldData, record, bodyHtml, textToCopy }) => {
const { isLoading, treeData, error } = useAsyncJSONProcessing(
fieldData.value,
record.field === 'body',
);
// Show JSON tree if available, otherwise show HTML content
if (record.field === 'body' && treeData) {
return <MemoizedTree treeData={treeData} />;
}
if (record.field === 'body' && isLoading) {
return (
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
<Spin size="small" />
<span style={{ color: Color.BG_SIENNA_400 }}>Processing JSON...</span>
</div>
);
}
// Show JSON tree if available, otherwise show HTML content
if (record.field === 'body' && treeData) {
return <MemoizedTree treeData={treeData} />;
}
if (record.field === 'body' && error) {
return (
<span
style={{ color: Color.BG_SIENNA_400, whiteSpace: 'pre-wrap', tabSize: 4 }}
>
Error parsing Body JSON
</span>
);
}
if (record.field === 'body' && isLoading) {
return (
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
<Spin size="small" />
<span style={{ color: Color.BG_SIENNA_400 }}>Processing JSON...</span>
</div>
);
}
if (record.field === 'body' && error) {
return (
if (record.field === 'body') {
return (
<CopyClipboardHOC entityKey="body" textToCopy={textToCopy}>
<span
style={{ color: Color.BG_SIENNA_400, whiteSpace: 'pre-wrap', tabSize: 4 }}
>
Error parsing Body JSON
<span dangerouslySetInnerHTML={bodyHtml} />
</span>
);
}
</CopyClipboardHOC>
);
}
if (record.field === 'body') {
return (
<CopyClipboardHOC entityKey="body" textToCopy={textToCopy}>
<span
style={{ color: Color.BG_SIENNA_400, whiteSpace: 'pre-wrap', tabSize: 4 }}
>
<span dangerouslySetInnerHTML={bodyHtml} />
</span>
</CopyClipboardHOC>
);
}
return null;
},
);
return null;
});
BodyContent.displayName = 'BodyContent';
@@ -324,7 +319,6 @@ export default function TableViewActions(
record={record}
bodyHtml={bodyHtml}
textToCopy={textToCopy}
handleChangeSelectedView={handleChangeSelectedView}
/>
);
@@ -348,7 +342,6 @@ export default function TableViewActions(
fieldData,
bodyHtml,
textToCopy,
handleChangeSelectedView,
formatTimezoneAdjustedTimestamp,
cleanTimestamp,
]);
@@ -362,7 +355,6 @@ export default function TableViewActions(
record={record}
bodyHtml={bodyHtml}
textToCopy={textToCopy}
handleChangeSelectedView={handleChangeSelectedView}
/>
{!isListViewPanel && !RESTRICTED_SELECTED_FIELDS.includes(fieldFilterKey) && (
<span className="action-btn">

View File

@@ -1,8 +1,5 @@
import { useEffect, useRef, useState } from 'react';
import { FeatureKeys } from 'constants/features';
import { ChangeViewFunctionType } from 'container/ExplorerOptions/types';
import { isEmpty } from 'lodash-es';
import { useAppContext } from 'providers/App/App';
import { jsonToDataNodes, recursiveParseJSON } from '../utils';
@@ -12,7 +9,6 @@ const MAX_BODY_BYTES = 100 * 1024; // 100 KB
const useAsyncJSONProcessing = (
value: string,
shouldProcess: boolean,
handleChangeSelectedView?: ChangeViewFunctionType,
): {
isLoading: boolean;
treeData: any[] | null;
@@ -29,10 +25,6 @@ const useAsyncJSONProcessing = (
});
const processingRef = useRef<boolean>(false);
const { featureFlags } = useAppContext();
const isBodyJsonQueryEnabled =
featureFlags?.find((flag) => flag.name === FeatureKeys.ENABLE_BODY_JSON_QUERY)
?.active || false;
// eslint-disable-next-line sonarjs/cognitive-complexity
useEffect((): (() => void) => {
@@ -55,10 +47,7 @@ const useAsyncJSONProcessing = (
try {
const parsedBody = recursiveParseJSON(value);
if (!isEmpty(parsedBody)) {
const treeData = jsonToDataNodes(parsedBody, {
isBodyJsonQueryEnabled,
handleChangeSelectedView,
});
const treeData = jsonToDataNodes(parsedBody);
setJsonState({ isLoading: false, treeData, error: null });
} else {
setJsonState({ isLoading: false, treeData: null, error: null });
@@ -84,10 +73,7 @@ const useAsyncJSONProcessing = (
try {
const parsedBody = recursiveParseJSON(value);
if (!isEmpty(parsedBody)) {
const treeData = jsonToDataNodes(parsedBody, {
isBodyJsonQueryEnabled,
handleChangeSelectedView,
});
const treeData = jsonToDataNodes(parsedBody);
setJsonState({ isLoading: false, treeData, error: null });
} else {
setJsonState({ isLoading: false, treeData: null, error: null });
@@ -115,7 +101,7 @@ const useAsyncJSONProcessing = (
return (): void => {
processingRef.current = false;
};
}, [value, shouldProcess, isBodyJsonQueryEnabled, handleChangeSelectedView]);
}, [value, shouldProcess]);
return jsonState;
};

View File

@@ -1,5 +1,4 @@
export const DROPDOWN_KEY = {
FILTER_IN: 'filterIn',
FILTER_OUT: 'filterOut',
GROUP_BY: 'groupBy',
};

View File

@@ -1,6 +1,5 @@
import Convert from 'ansi-to-html';
import type { DataNode } from 'antd/es/tree';
import { ChangeViewFunctionType } from 'container/ExplorerOptions/types';
import { MetricsType } from 'container/MetricsApplication/constant';
import dompurify from 'dompurify';
import { uniqueId } from 'lodash-es';
@@ -35,32 +34,13 @@ export const recursiveParseJSON = (obj: string): Record<string, unknown> => {
}
};
type JsonToDataNodesOptions = {
parentKey?: string;
parentIsArray?: boolean;
isBodyJsonQueryEnabled?: boolean;
handleChangeSelectedView?: ChangeViewFunctionType;
};
type ComputeDataNodeOptions = {
key: string;
valueIsArray: boolean;
value: unknown;
nodeKey: string;
parentIsArray: boolean;
isBodyJsonQueryEnabled?: boolean;
handleChangeSelectedView?: ChangeViewFunctionType;
};
export const computeDataNode = ({
key,
valueIsArray,
value,
nodeKey,
parentIsArray,
isBodyJsonQueryEnabled = false,
handleChangeSelectedView,
}: ComputeDataNodeOptions): DataNode => ({
export const computeDataNode = (
key: string,
valueIsArray: boolean,
value: unknown,
nodeKey: string,
parentIsArray: boolean,
): DataNode => ({
key: uniqueId(),
title: (
<BodyTitleRenderer
@@ -68,30 +48,20 @@ export const computeDataNode = ({
nodeKey={nodeKey}
value={value}
parentIsArray={parentIsArray}
handleChangeSelectedView={handleChangeSelectedView}
/>
),
children: jsonToDataNodes(value as Record<string, unknown>, {
parentKey: valueIsArray
? `${nodeKey}${isBodyJsonQueryEnabled ? '[]' : '[*]'}`
: nodeKey,
parentIsArray: valueIsArray,
isBodyJsonQueryEnabled,
handleChangeSelectedView,
}),
children: jsonToDataNodes(
value as Record<string, unknown>,
valueIsArray ? `${nodeKey}[*]` : nodeKey,
valueIsArray,
),
});
export function jsonToDataNodes(
json: Record<string, unknown>,
options: JsonToDataNodesOptions = {},
parentKey = '',
parentIsArray = false,
): DataNode[] {
const {
parentKey = '',
parentIsArray = false,
isBodyJsonQueryEnabled = false,
handleChangeSelectedView,
} = options;
return Object.entries(json).map(([key, value]) => {
let nodeKey = parentKey || key;
if (parentIsArray) {
@@ -104,15 +74,7 @@ export function jsonToDataNodes(
if (parentIsArray) {
if (typeof value === 'object' && value !== null) {
return computeDataNode({
key,
valueIsArray,
value,
nodeKey,
parentIsArray,
isBodyJsonQueryEnabled,
handleChangeSelectedView,
});
return computeDataNode(key, valueIsArray, value, nodeKey, parentIsArray);
}
return {
@@ -123,31 +85,14 @@ export function jsonToDataNodes(
nodeKey={nodeKey}
value={value}
parentIsArray={parentIsArray}
handleChangeSelectedView={handleChangeSelectedView}
/>
),
children: jsonToDataNodes(
{},
{
parentKey: nodeKey,
parentIsArray: valueIsArray,
isBodyJsonQueryEnabled,
handleChangeSelectedView,
},
),
children: jsonToDataNodes({}, nodeKey, valueIsArray),
};
}
if (typeof value === 'object' && value !== null) {
return computeDataNode({
key,
valueIsArray,
value,
nodeKey,
parentIsArray,
isBodyJsonQueryEnabled,
handleChangeSelectedView,
});
return computeDataNode(key, valueIsArray, value, nodeKey, parentIsArray);
}
return {
key: uniqueId(),
@@ -157,7 +102,6 @@ export function jsonToDataNodes(
nodeKey={nodeKey}
value={value}
parentIsArray={parentIsArray}
handleChangeSelectedView={handleChangeSelectedView}
/>
),
};
@@ -179,7 +123,6 @@ export function flattenObject(obj: AnyObject, prefix = ''): AnyObject {
export const generateFieldKeyForArray = (
fieldKey: string,
dataType: DataTypes,
isBodyJsonQueryEnabled = false,
): string => {
let lastDotIndex = fieldKey.lastIndexOf('.');
let resultNodeKey = fieldKey;
@@ -195,16 +138,6 @@ export const generateFieldKeyForArray = (
newResultNodeKey = resultNodeKey.substring(0, lastDotIndex);
}
}
// When filtering for a value inside an array, the query builder expects the
// last array segment to be referenced without the trailing `[]`.
// Examples:
// - has(body.config.features, 'fast_checkout')
// - has(body.config.features[].items, 'pen')
// - has(body.config.features[].items[].variants, 'ballpen')
if (isBodyJsonQueryEnabled && newResultNodeKey.endsWith('[]')) {
newResultNodeKey = newResultNodeKey.slice(0, -2);
}
return `body.${newResultNodeKey}`;
};

View File

@@ -17,6 +17,9 @@
&.is-resizing {
background: var(--l2-background-hover);
}
border: none !important;
background-color: var(--l2-background) !important;
}
.tanstack-header-content {

View File

@@ -2,7 +2,6 @@ import { useTranslation } from 'react-i18next';
import { Form, Input } from 'antd';
import { ProcessorFormField } from '../../AddNewProcessor/config';
import { FormLabelStyle } from '../styles';
function DescriptionTextArea({
fieldData,
@@ -13,7 +12,7 @@ function DescriptionTextArea({
<Form.Item
required={false}
name={fieldData.name}
label={<FormLabelStyle>{fieldData.fieldName}</FormLabelStyle>}
label={fieldData.fieldName}
key={fieldData.id}
>
<Input.TextArea rows={3} placeholder={t(fieldData.placeholder)} />

View File

@@ -8,7 +8,6 @@ import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { ProcessorFormField } from '../../../AddNewProcessor/config';
import { formValidationRules } from '../../../config';
import LogsFilterPreview from '../../../Preview/LogsFilterPreview';
import { FormLabelStyle } from '../../styles';
import './styles.scss';
@@ -68,7 +67,7 @@ function FilterInput({ fieldData }: FilterInputProps): JSX.Element {
return (
<Form.Item
required={false}
label={<FormLabelStyle>{fieldData.fieldName}</FormLabelStyle>}
label={fieldData.fieldName}
key={fieldData.id}
rules={formValidationRules}
name={fieldData.name}

View File

@@ -3,7 +3,6 @@ import { Form, Input } from 'antd';
import { ProcessorFormField } from '../../AddNewProcessor/config';
import { formValidationRules } from '../../config';
import { FormLabelStyle } from '../styles';
function NameInput({ fieldData }: NameInputProps): JSX.Element {
const { t } = useTranslation('pipeline');
@@ -11,7 +10,7 @@ function NameInput({ fieldData }: NameInputProps): JSX.Element {
return (
<Form.Item
required={false}
label={<FormLabelStyle>{fieldData.fieldName}</FormLabelStyle>}
label={fieldData.fieldName}
key={fieldData.id}
rules={formValidationRules}
name={fieldData.name}

View File

@@ -3,7 +3,6 @@ import { Form } from 'antd';
import TagInput from 'container/PipelinePage/components/TagInput';
import { ProcessorFormField } from '../../AddNewProcessor/config';
import { FormLabelStyle } from '../styles';
function ProcessorTags({
fieldData,
@@ -15,7 +14,7 @@ function ProcessorTags({
return (
<Form.Item
required={false}
label={<FormLabelStyle>{fieldData.fieldName}</FormLabelStyle>}
label={fieldData.fieldName}
key={fieldData.id}
name={fieldData.name}
>

View File

@@ -1,11 +1,12 @@
import React, { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { Button, Divider, Form, FormInstance, Modal } from 'antd';
import { Button } from '@signozhq/ui';
import { Form, FormInstance, Modal } from 'antd';
import { useAppContext } from 'providers/App/App';
import { ActionMode, ActionType, PipelineData } from 'types/api/pipeline/def';
import { v4 } from 'uuid';
import { ModalButtonWrapper, ModalTitle } from '../styles';
import { ModalButtonWrapper } from '../styles';
import { getEditedDataSource, getRecordIndex } from '../utils';
import { renderPipelineForm } from './utils';
@@ -90,34 +91,39 @@ function AddNewPipeline({
return (
<Modal
title={<ModalTitle level={4}>{modalTitle}</ModalTitle>}
title={modalTitle}
centered
open={isOpen}
width={800}
footer={null}
onCancel={onCancelModalHandler}
>
<Divider plain />
<Form
name="add-new-pipeline"
layout="vertical"
onFinish={onFinish}
autoComplete="off"
form={form}
className="add-new-pipeline-form"
>
{renderPipelineForm()}
<Divider plain />
<Form.Item>
<ModalButtonWrapper>
<Button
key="submit"
type="primary"
htmlType="submit"
variant="solid"
color="primary"
onClick={onOkModalHandler}
>
{isEdit ? t('update') : t('create')}
</Button>
<Button key="cancel" onClick={onCancelModalHandler}>
<Button
key="cancel"
variant="solid"
color="secondary"
onClick={onCancelModalHandler}
>
{t('cancel')}
</Button>
</ModalButtonWrapper>

View File

@@ -1,7 +0,0 @@
import styled from 'styled-components';
export const FormLabelStyle = styled.span`
font-size: 0.75rem;
font-weight: 400;
line-height: 1.25rem;
`;

View File

@@ -97,6 +97,7 @@
}
.steps-content {
padding: 0 16px;
max-height: 500px;
}
}

View File

@@ -164,7 +164,8 @@ export function useIntegrationModal({
{
onSuccess: (response: CreateAccountMutationResult) => {
const accountId = response.data.id;
const connectionUrl = response.data.connectionArtifact.aws.connectionUrl;
const connectionUrl =
response.data.connectionArtifact.aws?.connectionUrl ?? '';
logEvent(
'AWS Integration: Account connection attempt redirected to AWS',

View File

@@ -218,30 +218,9 @@
.ant-modal-footer {
display: flex;
justify-content: flex-end;
gap: 8px;
padding: 16px 16px;
margin: 0;
.cancel-btn {
display: flex;
align-items: center;
border: none;
border-radius: 2px;
background: var(--l1-border);
}
.delete-btn {
display: flex;
align-items: center;
border: none;
border-radius: 2px;
background: var(--danger-background);
margin-left: 12px;
}
.delete-btn:hover {
color: var(--l1-foreground);
background: var(--bg-cherry-600);
}
}
}
.title {
@@ -252,98 +231,3 @@
line-height: 20px; /* 142.857% */
}
}
.lightMode {
.save-view-container {
.save-view-content {
.title {
color: var(--l1-foreground);
}
.ant-table-row {
.ant-table-cell {
background: var(--l2-background);
}
&:hover {
.ant-table-cell {
background: var(--l2-background) !important;
}
}
.column-render {
border: 1px solid var(--l1-border);
background: var(--l1-background);
.title-with-action {
.save-view-title {
.ant-typography {
color: var(--l1-foreground);
}
}
.action-btn {
.ant-typography {
color: var(--l1-foreground);
}
}
}
.view-details {
.view-tag {
background: var(--l2-background);
.tag-text {
color: var(--l1-foreground);
}
}
.view-created-by {
color: var(--l1-foreground);
}
.view-created-at {
.ant-typography {
color: var(--l1-foreground);
}
}
}
}
}
}
}
.delete-view-modal {
.ant-modal-content {
border: 1px solid var(--l1-border);
background: var(--card);
.ant-modal-header {
background: var(--card);
.title {
color: var(--l1-foreground);
}
}
.ant-modal-body {
.ant-typography {
color: var(--l1-foreground);
}
.save-view-input {
.ant-input {
background: var(--l1-background);
color: var(--l1-foreground);
}
}
}
.ant-modal-footer {
.cancel-btn {
background: var(--l3-background);
color: var(--l2-foreground);
}
}
}
}
}

View File

@@ -2,15 +2,8 @@ import { ChangeEvent, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router-dom';
import { Color } from '@signozhq/design-tokens';
import {
Button,
ColorPicker,
Input,
Modal,
Table,
TableProps,
Typography,
} from 'antd';
import { Button } from '@signozhq/ui';
import { ColorPicker, Input, Modal, Table, TableProps, Typography } from 'antd';
import logEvent from 'api/common/logEvent';
import {
getViewDetailsUsingViewKey,
@@ -348,15 +341,19 @@ function SaveView(): JSX.Element {
footer={[
<Button
key="cancel"
variant="solid"
color="secondary"
onClick={hideDeleteViewModal}
className="cancel-btn"
icon={<X size={16} />}
prefix={<X size={16} />}
>
Cancel
</Button>,
<Button
key="submit"
icon={<Trash2 size={16} />}
variant="solid"
color="destructive"
prefix={<Trash2 size={16} />}
onClick={onDeleteHandler}
className="delete-btn"
disabled={isDeleteLoading}
@@ -382,7 +379,9 @@ function SaveView(): JSX.Element {
footer={[
<Button
key="submit"
icon={<Check size={16} color={Color.BG_VANILLA_100} />}
variant="solid"
color="primary"
prefix={<Check size={16} color={Color.BG_VANILLA_100} />}
onClick={onUpdateQueryHandler}
disabled={isViewUpdating}
data-testid="save-view"

View File

@@ -149,62 +149,3 @@
}
}
}
.lightMode {
.traces-module-container {
.trace-module {
.ant-tabs-tab {
.tab-item {
color: var(--l2-foreground);
}
}
.ant-tabs-tab-active {
.tab-item {
color: var(--l1-foreground);
}
}
.ant-tabs-nav::before {
border-bottom: 1px solid var(--l1-border) !important;
}
}
.old-switch {
color: var(--l2-foreground);
}
.trace-layout {
.flamegraph-waterfall-toggle {
color: var(--l2-foreground);
}
.span-list-toggle {
color: var(--l2-foreground);
}
.trace-visualisation-tabs {
.ant-tabs-tab {
background: var(--l3-background);
border: 1px solid var(--l1-border);
}
.ant-tabs-tab-active {
background-color: var(--l1-background);
.ant-btn {
color: var(--l1-foreground) !important;
}
}
.ant-tabs-ink-bar {
height: 1px !important;
background: var(--l1-background) !important;
}
.ant-tabs-nav::before {
border-bottom: 1px solid var(--l1-border);
}
}
}
}
}

View File

@@ -87,49 +87,3 @@
}
}
}
// Light mode styles
.lightMode {
.funnel-step-modal {
.ant-modal-content {
.ant-modal-header {
background: var(--l1-foreground);
.ant-modal-title {
color: var(--l2-background);
}
}
}
&__cancel-btn {
color: var(--l2-background);
}
}
.funnel-step-modal-content {
&__label {
color: var(--l2-background);
}
&__input {
background: var(--l2-foreground);
border: 1px solid var(--l1-border);
color: var(--l2-background);
&::placeholder {
color: var(--l2-foreground);
}
&.ant-input-textarea {
.ant-input {
background: var(--l2-foreground);
border: 1px solid var(--l1-border);
color: var(--l2-background);
&::placeholder {
color: var(--l2-foreground);
}
}
}
}
}
}

View File

@@ -87,52 +87,3 @@
}
}
}
// Light mode styles
.lightMode {
.funnel-step-modal {
.ant-modal-content {
.ant-modal-header {
.ant-modal-title {
color: var(--l2-background);
}
}
}
&__ok-btn {
background: var(--primary-background) !important;
}
&__cancel-btn {
color: var(--l2-background);
}
}
.funnel-step-modal-content {
&__label {
color: var(--l2-background);
}
&__input {
background: var(--l2-foreground);
border: 1px solid var(--l1-border);
color: var(--l2-background);
&::placeholder {
color: var(--l2-foreground);
}
&.ant-input-textarea {
.ant-input {
background: var(--l2-foreground);
border: 1px solid var(--l1-border);
color: var(--l2-background);
&::placeholder {
color: var(--l2-foreground);
}
}
}
}
}
}

View File

@@ -87,48 +87,3 @@
}
}
}
// Light mode styles
.lightMode {
.funnel-step-modal {
.ant-modal-content {
.ant-modal-header {
.ant-modal-title {
color: var(--l2-background);
}
}
}
&__cancel-btn {
color: var(--l2-background);
}
}
.funnel-step-modal-content {
&__label {
color: var(--l2-background);
}
&__input {
background: var(--l2-foreground);
border: 1px solid var(--l1-border);
color: var(--l2-background);
&::placeholder {
color: var(--l2-foreground);
}
&.ant-input-textarea {
.ant-input {
background: var(--l2-foreground);
border: 1px solid var(--l1-border);
color: var(--l2-background);
&::placeholder {
color: var(--l2-foreground);
}
}
}
}
}
}

View File

@@ -6,7 +6,7 @@
}
li:first-of-type {
.funnel-breadcrumb__title {
color: var(--l2-foreground);
color: var(--l1-foreground);
}
}
.ant-breadcrumb-separator {
@@ -24,15 +24,3 @@
line-height: 20px; /* 142.857% */
}
}
.lightMode {
.funnel-breadcrumb__title,
.ant-breadcrumb-separator {
color: var(--l2-foreground);
}
li:first-of-type {
.funnel-breadcrumb__title {
color: var(--l2-foreground);
}
}
}

View File

@@ -107,6 +107,7 @@ function FunnelConfiguration({
)}
<div className="funnel-configuration__steps">
{!isTraceDetailsPage && <StepsHeader />}
<StepsContent isTraceDetailsPage={isTraceDetailsPage} span={span} />
</div>
</>

View File

@@ -112,6 +112,7 @@
gap: 6px;
padding: 16px;
padding-left: 12px;
.ant-form-item {
margin: 0;
width: 100%;
@@ -121,6 +122,8 @@
display: flex;
flex-direction: column;
gap: 10px;
width: 100%;
.ant-select-selector {
background: var(--l3-background);
border: 1px solid var(--l1-border);
@@ -129,15 +132,23 @@
line-height: 16px;
}
}
&__service-and-span {
display: flex;
align-items: center;
gap: 12px;
.service,
.span {
flex: 1;
}
.ant-select-selection-placeholder {
color: var(--l2-foreground);
}
.ant-select {
width: 239px;
width: 100%;
}
}
&__where-filter {

View File

@@ -1,4 +1,6 @@
.steps-content {
padding: 0 16px;
.ant-btn {
box-shadow: none;
&-icon {
@@ -110,29 +112,3 @@
}
}
}
// Light mode styles
.lightMode {
.steps-content {
.ant-steps-item-process .ant-steps-item-icon,
.ant-steps-item-icon {
background-color: var(--l3-background) !important;
& > .ant-steps-icon {
color: var(--l1-foreground);
}
}
.ant-steps-item-tail {
&::after {
background-color: var(--l1-border) !important;
}
}
.latency-step-marker {
&::before {
background-color: var(--l3-background);
}
}
}
}

View File

@@ -52,29 +52,3 @@
}
}
}
.lightMode {
.steps-footer {
border-top: 1px solid var(--l1-border);
background: var(--l2-background);
&__left {
color: var(--l2-background);
}
&__valid-traces {
&--none {
color: var(--text-amber-600);
}
}
&__button {
&--save {
background: var(--l3-background);
}
&--run {
background-color: var(--bg-robin-400);
}
}
}
}

View File

@@ -1,10 +1,14 @@
.steps-header {
display: flex;
align-items: center;
justify-content: center;
align-items: flex-start;
gap: 6px;
padding: 16px;
margin-bottom: 16px;
margin-top: 16px;
flex-wrap: wrap;
&__label {
color: var(--muted-foreground);
color: var(--l1-foreground);
font-size: 12px;
font-weight: 600;
line-height: 18px;
@@ -12,6 +16,7 @@
text-transform: uppercase;
flex-shrink: 0;
}
&__divider {
width: 100%;
.ant-divider {
@@ -19,8 +24,9 @@
border-color: var(--l1-border);
}
}
&__time-range {
min-width: 192px;
width: 100%;
height: 32px;
flex-shrink: 0;
.timeSelection-input {
@@ -29,23 +35,9 @@
}
&,
input {
background: var(--l3-background);
background: var(--l2-background);
font-size: 12px;
}
}
}
}
.lightMode {
.steps-header {
&__label {
color: var(--l2-foreground);
}
.timeSelection-input {
&,
input {
background: unset;
}
}
}
}

View File

@@ -1,4 +1,3 @@
import { Divider } from 'antd';
import DateTimeSelectionV2 from 'container/TopNav/DateTimeSelectionV2';
import './StepsHeader.styles.scss';
@@ -7,14 +6,12 @@ function StepsHeader(): JSX.Element {
return (
<div className="steps-header">
<div className="steps-header__label">FUNNEL STEPS</div>
<div className="steps-header__divider">
<Divider dashed />
</div>
<div className="steps-header__time-range">
<DateTimeSelectionV2
showAutoRefresh={false}
showRefreshText={false}
hideShareModal
showRecentlyUsed={false}
/>
</div>
</div>

View File

@@ -28,15 +28,3 @@
margin-top: 8px;
}
}
.lightMode {
.empty-funnel-results {
&__title {
color: var(--l1-foreground);
}
&__description {
color: var(--l2-foreground);
}
}
}

View File

@@ -79,44 +79,3 @@
}
}
}
.lightMode {
.funnel-metrics {
background: var(--l1-foreground);
border: 1px solid var(--l1-border);
box-shadow: 0px 4px 12px 0px rgba(0, 0, 0, 0.05);
&__header {
border-bottom: 1px solid var(--l1-border);
}
&__title {
color: var(--l2-foreground);
}
&__subtitle {
&-label {
color: var(--l2-foreground);
}
&-value {
color: var(--l1-foreground);
}
}
&__item {
&:not(:last-child) {
border-right: 1px solid var(--l1-border);
}
&-title {
color: var(--l1-foreground);
}
&-value,
&-unit {
color: var(--l2-foreground);
}
}
}
}

View File

@@ -115,39 +115,3 @@
}
}
}
.lightMode {
.funnel-table {
border-color: var(--l1-border);
.ant-table {
.ant-table-thead > tr > th {
background: var(--l1-foreground);
color: var(--l2-foreground);
}
.ant-table-cell {
background: var(--l1-foreground);
color: var(--l1-background);
}
.ant-table-tbody > tr:hover > td {
background: rgba(0, 0, 0, 0.04);
}
.table-row-light {
background: none;
color: var(--l1-background);
}
.table-row-dark {
background: none;
color: var(--l1-background);
}
}
&__header {
background: var(--l1-foreground);
color: var(--l2-foreground);
}
}
}

View File

@@ -2,6 +2,7 @@
display: flex;
flex-direction: column;
gap: 20px;
&__steps-selector {
display: flex;
justify-content: center;
@@ -13,26 +14,3 @@
gap: 16px;
}
}
.lightMode {
.steps-transition-results {
&__steps-selector {
.views-tabs {
.tab {
background: var(--l1-foreground);
}
.selected_view {
background: var(--l3-background);
border: 1px solid var(--l1-border);
color: var(--l2-foreground);
}
.selected_view::before {
background: var(--l3-background);
border-left: 1px solid var(--l1-border);
}
}
}
}
}

View File

@@ -2,10 +2,11 @@
@use 'components/SearchBar/SearchBar.styles.scss';
.traces-funnels {
margin-top: 113px;
padding: 64px 0;
display: flex;
justify-content: center;
width: 100%;
.ant-btn-icon {
margin: 0 !important;
}

View File

@@ -17,9 +17,3 @@
padding-bottom: 24px;
}
}
.lightMode {
.delete-funnel-modal-content {
color: var(--l2-foreground) !important;
}
}

View File

@@ -60,23 +60,3 @@
}
}
}
.lightMode {
.funnels-empty {
&__content {
border: 1px dashed var(--l2-foreground);
}
&__icon {
color: var(--l1-background);
}
&__title {
color: var(--l1-background);
}
&__subtitle {
color: var(--l2-background);
}
}
}

View File

@@ -12,7 +12,7 @@
&,
input {
font-family: Inter;
background: var(--l3-background);
background: var(--l2-background);
font-size: 14px;
line-height: 18px;
font-style: normal;

View File

@@ -2,6 +2,20 @@ import { orange } from '@ant-design/colors';
import { Color } from '@signozhq/design-tokens';
import { LogType } from 'components/Logs/LogStateIndicator/LogStateIndicator';
/** 8-bit alpha from a two-digit hex string (e.g. "40" → 64/255). */
function rgbaFromHexColor(hexColor: string, alphaByteHex: string): string {
const hex = hexColor.replace('#', '');
const r = parseInt(hex.slice(0, 2), 16);
const g = parseInt(hex.slice(2, 4), 16);
const b = parseInt(hex.slice(4, 6), 16);
const a = parseInt(alphaByteHex, 16) / 255;
return `rgba(${r}, ${g}, ${b}, ${a})`;
}
function rgbaFromHexColorOpaque(hexColor: string): string {
return rgbaFromHexColor(hexColor, 'ff');
}
export const getDefaultLogBackground = (
isReadOnly?: boolean,
isDarkMode?: boolean,
@@ -26,38 +40,69 @@ export const getActiveLogBackground = (
}
if (isDarkMode) {
switch (logType) {
case LogType.INFO:
return `background-color: ${Color.BG_ROBIN_500}40 !important;`;
case LogType.WARN:
return `background-color: ${Color.BG_AMBER_500}40 !important;`;
return `background-color: ${rgbaFromHexColor(
Color.BG_AMBER_500,
'20',
)} !important;`;
case LogType.ERROR:
return `background-color: ${Color.BG_CHERRY_500}40 !important;`;
return `background-color: ${rgbaFromHexColor(
Color.BG_CHERRY_500,
'20',
)} !important;`;
case LogType.TRACE:
return `background-color: ${Color.BG_FOREST_400}40 !important;`;
return `background-color: ${rgbaFromHexColor(
Color.BG_FOREST_400,
'20',
)} !important;`;
case LogType.DEBUG:
return `background-color: ${Color.BG_AQUA_500}40 !important;`;
return `background-color: ${rgbaFromHexColor(
Color.BG_AQUA_500,
'20',
)} !important;`;
case LogType.FATAL:
return `background-color: ${Color.BG_SAKURA_500}40 !important;`;
return `background-color: ${rgbaFromHexColor(
Color.BG_SAKURA_500,
'20',
)} !important;`;
case LogType.INFO:
default:
return `background-color: ${Color.BG_ROBIN_500}40 !important;`;
return `background-color: ${rgbaFromHexColor(
Color.BG_ROBIN_500,
'20',
)} !important;`;
}
}
// Light mode - use lighter background colors
switch (logType) {
case LogType.INFO:
return `background-color: ${Color.BG_ROBIN_100} !important;`;
return `background-color: ${rgbaFromHexColorOpaque(
Color.BG_ROBIN_100,
)} !important;`;
case LogType.WARN:
return `background-color: ${Color.BG_AMBER_100} !important;`;
return `background-color: ${rgbaFromHexColorOpaque(
Color.BG_AMBER_100,
)} !important;`;
case LogType.ERROR:
return `background-color: ${Color.BG_CHERRY_100} !important;`;
return `background-color: ${rgbaFromHexColorOpaque(
Color.BG_CHERRY_100,
)} !important;`;
case LogType.TRACE:
return `background-color: ${Color.BG_FOREST_200} !important;`;
return `background-color: ${rgbaFromHexColorOpaque(
Color.BG_FOREST_200,
)} !important;`;
case LogType.DEBUG:
return `background-color: ${Color.BG_AQUA_100} !important;`;
return `background-color: ${rgbaFromHexColorOpaque(
Color.BG_AQUA_100,
)} !important;`;
case LogType.FATAL:
return `background-color: ${Color.BG_SAKURA_100} !important;`;
return `background-color: ${rgbaFromHexColorOpaque(
Color.BG_SAKURA_100,
)} !important;`;
default:
return `background-color: ${Color.BG_VANILLA_300} !important;`;
return `background-color: ${rgbaFromHexColorOpaque(
Color.BG_VANILLA_300,
)} !important;`;
}
};
@@ -75,5 +120,5 @@ export const getCustomHighlightBackground = (isHighlighted = false): string => {
return '';
}
return `background-color: ${Color.BG_ROBIN_500}20;`;
return `background-color: ${rgbaFromHexColor(Color.BG_ROBIN_500, '20')};`;
};

View File

@@ -27,6 +27,11 @@ const regions: Region[] = [
displayName: 'Canada (Central)',
},
{ id: 'ca-west-1', name: 'ca-west-1', displayName: 'Canada (West)' },
{
id: 'mx-central-1',
name: 'mx-central-1',
displayName: 'Mexico (Central)',
},
],
},
{
@@ -45,6 +50,11 @@ const regions: Region[] = [
name: 'ap-east-1',
displayName: 'Asia Pacific (Hong Kong)',
},
{
id: 'ap-east-2',
name: 'ap-east-2',
displayName: 'Asia Pacific (Taipei)',
},
{
id: 'ap-northeast-1',
name: 'ap-northeast-1',
@@ -93,7 +103,17 @@ const regions: Region[] = [
{
id: 'ap-southeast-5',
name: 'ap-southeast-5',
displayName: 'Asia Pacific (Auckland)',
displayName: 'Asia Pacific (Malaysia)',
},
{
id: 'ap-southeast-6',
name: 'ap-southeast-6',
displayName: 'Asia Pacific (New Zealand)',
},
{
id: 'ap-southeast-7',
name: 'ap-southeast-7',
displayName: 'Asia Pacific (Thailand)',
},
],
},

View File

@@ -373,7 +373,13 @@ func (handler *handler) UpdateService(rw http.ResponseWriter, r *http.Request) {
// update or create service
if svc.CloudIntegrationService == nil {
cloudIntegrationService := cloudintegrationtypes.NewCloudIntegrationService(serviceID, cloudIntegrationID, req.Config)
var cloudIntegrationService *cloudintegrationtypes.CloudIntegrationService
cloudIntegrationService, err = cloudintegrationtypes.NewCloudIntegrationService(serviceID, cloudIntegrationID, provider, req.Config)
if err != nil {
render.Error(rw, err)
return
}
err = handler.module.CreateService(ctx, orgID, cloudIntegrationService, provider)
} else {
err = svc.CloudIntegrationService.Update(provider, serviceID, req.Config)

View File

@@ -194,6 +194,7 @@ func NewSQLMigrationProviderFactories(
sqlmigration.NewDeprecateAPIKeyFactory(sqlstore, sqlschema),
sqlmigration.NewServiceAccountAuthzactory(sqlstore),
sqlmigration.NewDropUserDeletedAtFactory(sqlstore, sqlschema),
sqlmigration.NewMigrateAWSAllRegionsFactory(sqlstore),
)
}

View File

@@ -0,0 +1,118 @@
package sqlmigration
import (
"context"
"encoding/json"
"slices"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/sqlstore"
"github.com/SigNoz/signoz/pkg/valuer"
"github.com/uptrace/bun"
"github.com/uptrace/bun/migrate"
)
var awsRegions = []string{
"af-south-1", "ap-east-1", "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", "ap-south-1", "ap-south-2", "ap-southeast-1", "ap-southeast-2", "ap-southeast-3",
"ap-southeast-4", "ap-southeast-5", "ca-central-1", "ca-west-1", "eu-central-1", "eu-central-2", "eu-north-1", "eu-south-1", "eu-south-2", "eu-west-1", "eu-west-2", "eu-west-3",
"il-central-1", "me-central-1", "me-south-1", "sa-east-1", "us-east-1", "us-east-2", "us-west-1", "us-west-2",
}
var awsCloudProvider = valuer.NewString("aws")
type migrateAWSAllRegions struct {
sqlstore sqlstore.SQLStore
}
type cloudIntegrationAWSMigrationRow struct {
bun.BaseModel `bun:"table:cloud_integration"`
ID string `bun:"id"`
Config string `bun:"config"`
}
type awsConfig struct {
Regions []string `json:"regions"`
}
func NewMigrateAWSAllRegionsFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
return factory.NewProviderFactory(
factory.MustNewName("migrate_aws_all_regions"),
func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
return &migrateAWSAllRegions{sqlstore: sqlstore}, nil
},
)
}
func (migration *migrateAWSAllRegions) Register(migrations *migrate.Migrations) error {
if err := migrations.Register(migration.Up, migration.Down); err != nil {
return err
}
return nil
}
func (migration *migrateAWSAllRegions) Up(ctx context.Context, db *bun.DB) error {
tx, err := db.BeginTx(ctx, nil)
if err != nil {
return err
}
defer func() {
_ = tx.Rollback()
}()
accounts := make([]*cloudIntegrationAWSMigrationRow, 0)
err = tx.NewSelect().
Model(&accounts).
Where("provider = ?", awsCloudProvider.StringValue()).
Where("removed_at IS NULL").
Scan(ctx)
if err != nil {
return err
}
idsToUpdate := make([]string, 0)
for _, account := range accounts {
var cfg awsConfig
if err := json.Unmarshal([]byte(account.Config), &cfg); err != nil {
continue
}
if slices.Contains(cfg.Regions, "all") {
idsToUpdate = append(idsToUpdate, account.ID)
}
}
if len(idsToUpdate) == 0 {
return tx.Commit()
}
configBytes, err := migration.getAllRegionsConfig()
if err != nil {
return err
}
_, err = tx.NewUpdate().
TableExpr("cloud_integration").
Set("config = ?", string(configBytes)).
Where("id IN (?)", bun.In(idsToUpdate)).
Exec(ctx)
if err != nil {
return err
}
return tx.Commit()
}
func (migration *migrateAWSAllRegions) Down(context.Context, *bun.DB) error {
return nil
}
func (migration *migrateAWSAllRegions) getAllRegionsConfig() ([]byte, error) {
cfg := awsConfig{Regions: awsRegions}
newBytes, err := json.Marshal(cfg)
if err != nil {
return nil, err
}
return newBytes, nil
}

View File

@@ -29,8 +29,13 @@ type AgentReport struct {
}
type AccountConfig struct {
// required till new providers are added
AWS *AWSAccountConfig `json:"aws" required:"true" nullable:"false"`
AWS *AWSAccountConfig `json:"aws,omitempty" required:"false" nullable:"false"`
Azure *AzureAccountConfig `json:"azure,omitempty" required:"false" nullable:"false"`
}
type UpdatableAccountConfig struct {
AWS *UpdatableAWSAccountConfig `json:"aws,omitempty" required:"false" nullable:"false"`
Azure *UpdatableAzureAccountConfig `json:"azure,omitempty" required:"false" nullable:"false"`
}
type PostableAccount struct {
@@ -41,7 +46,8 @@ type PostableAccount struct {
type PostableAccountConfig struct {
// as agent version is common for all providers, we can keep it at top level of this struct
AgentVersion string
AWS *AWSPostableAccountConfig `json:"aws" required:"true" nullable:"false"`
AWS *AWSPostableAccountConfig `json:"aws,omitempty" required:"false" nullable:"false"`
Azure *AzurePostableAccountConfig `json:"azure,omitempty" required:"false" nullable:"false"`
}
type Credentials struct {
@@ -58,7 +64,8 @@ type GettableAccountWithConnectionArtifact struct {
type ConnectionArtifact struct {
// required till new providers are added
AWS *AWSConnectionArtifact `json:"aws" required:"true" nullable:"false"`
AWS *AWSConnectionArtifact `json:"aws,omitempty" required:"false" nullable:"false"`
Azure *AzureConnectionArtifact `json:"azure,omitempty" required:"false" nullable:"false"`
}
type GetConnectionArtifactRequest = PostableAccount
@@ -68,7 +75,7 @@ type GettableAccounts struct {
}
type UpdatableAccount struct {
Config *AccountConfig `json:"config" required:"true" nullable:"false"`
Config *UpdatableAccountConfig `json:"config" required:"true" nullable:"false"`
}
func NewAccount(orgID valuer.UUID, provider CloudProviderType, config *AccountConfig) *Account {
@@ -119,6 +126,13 @@ func NewAccountFromStorable(storableAccount *StorableCloudIntegration) (*Account
return nil, err
}
account.Config.AWS = awsConfig
case CloudProviderTypeAzure:
azureConfig := new(AzureAccountConfig)
err := json.Unmarshal([]byte(storableAccount.Config), azureConfig)
if err != nil {
return nil, err
}
account.Config.Azure = azureConfig
}
if storableAccount.LastAgentReport != nil {
@@ -179,6 +193,24 @@ func NewAccountConfigFromPostable(provider CloudProviderType, config *PostableAc
}
return &AccountConfig{AWS: &AWSAccountConfig{Regions: config.AWS.Regions}}, nil
case CloudProviderTypeAzure:
if config.Azure == nil {
return nil, errors.NewInvalidInputf(ErrCodeInvalidInput, "Azure config can not be nil for Azure provider")
}
if config.Azure.DeploymentRegion == "" {
return nil, errors.NewInvalidInputf(ErrCodeInvalidInput, "deployment region is required for Azure provider")
}
if err := validateAzureRegion(config.Azure.DeploymentRegion); err != nil {
return nil, err
}
if len(config.Azure.ResourceGroups) == 0 {
return nil, errors.NewInvalidInputf(ErrCodeInvalidInput, "at least one resource group is required for Azure provider")
}
return &AccountConfig{Azure: &AzureAccountConfig{DeploymentRegion: config.Azure.DeploymentRegion, ResourceGroups: config.Azure.ResourceGroups}}, nil
default:
return nil, errors.NewInvalidInputf(ErrCodeCloudProviderInvalidInput, "invalid cloud provider: %s", provider.StringValue())
}
@@ -202,6 +234,16 @@ func NewAccountConfigFromUpdatable(provider CloudProviderType, config *Updatable
}
return &AccountConfig{AWS: &AWSAccountConfig{Regions: config.Config.AWS.Regions}}, nil
case CloudProviderTypeAzure:
if config.Config.Azure == nil {
return nil, errors.NewInvalidInputf(ErrCodeInvalidInput, "Azure config can not be nil for Azure provider")
}
if len(config.Config.Azure.ResourceGroups) == 0 {
return nil, errors.NewInvalidInputf(ErrCodeInvalidInput, "at least one resource group is required for Azure provider")
}
return &AccountConfig{Azure: &AzureAccountConfig{ResourceGroups: config.Config.Azure.ResourceGroups}}, nil
default:
return nil, errors.NewInvalidInputf(ErrCodeCloudProviderInvalidInput, "invalid cloud provider: %s", provider.StringValue())
}
@@ -223,8 +265,14 @@ func GetSigNozAPIURLFromDeployment(deployment *zeustypes.GettableDeployment) (st
}
func (account *Account) Update(provider CloudProviderType, config *AccountConfig) error {
// deployment region can not be updated once set for Azure
if provider == CloudProviderTypeAzure {
config.Azure.DeploymentRegion = account.Config.Azure.DeploymentRegion
}
account.Config = config
account.UpdatedAt = time.Now()
return nil
}
@@ -288,6 +336,10 @@ func (config *AccountConfig) ToJSON() ([]byte, error) {
return json.Marshal(config.AWS)
}
if config.Azure != nil {
return json.Marshal(config.Azure)
}
return nil, errors.NewInternalf(errors.CodeInternal, "no provider account config found")
}

View File

@@ -48,7 +48,8 @@ type IntegrationConfig struct {
}
type ProviderIntegrationConfig struct {
AWS *AWSIntegrationConfig `json:"aws" required:"true" nullable:"false"`
AWS *AWSIntegrationConfig `json:"aws,omitempty" required:"false" nullable:"false"`
Azure *AzureIntegrationConfig `json:"azure,omitempty" required:"false" nullable:"false"`
}
// NewGettableAgentCheckIn constructs a backward-compatible response from an AgentCheckInResponse.

View File

@@ -61,7 +61,8 @@ type StorableCloudIntegrationService struct {
// Following Service config types are only internally used to store service config in DB and use JSON snake case keys for backward compatibility.
type StorableServiceConfig struct {
AWS *StorableAWSServiceConfig
AWS *StorableAWSServiceConfig
Azure *StorableAzureServiceConfig
}
type StorableAWSServiceConfig struct {
@@ -78,6 +79,19 @@ type StorableAWSMetricsServiceConfig struct {
Enabled bool `json:"enabled"`
}
type StorableAzureServiceConfig struct {
Logs *StorableAzureLogsServiceConfig `json:"logs,omitempty"`
Metrics *StorableAzureMetricsServiceConfig `json:"metrics,omitempty"`
}
type StorableAzureLogsServiceConfig struct {
Enabled bool `json:"enabled"`
}
type StorableAzureMetricsServiceConfig struct {
Enabled bool `json:"enabled"`
}
// Scan scans value from DB.
func (r *StorableAgentReport) Scan(src any) error {
var data []byte
@@ -187,6 +201,30 @@ func newStorableServiceConfig(provider CloudProviderType, serviceID ServiceID, s
}
return &StorableServiceConfig{AWS: storableAWSServiceConfig}, nil
case CloudProviderTypeAzure:
storableAzureServiceConfig := new(StorableAzureServiceConfig)
if supportedSignals.Logs {
if serviceConfig.Azure.Logs == nil {
return nil, errors.NewInvalidInputf(ErrCodeCloudIntegrationInvalidConfig, "logs config is required for Azure service: %s", serviceID.StringValue())
}
storableAzureServiceConfig.Logs = &StorableAzureLogsServiceConfig{
Enabled: serviceConfig.Azure.Logs.Enabled,
}
}
if supportedSignals.Metrics {
if serviceConfig.Azure.Metrics == nil {
return nil, errors.NewInvalidInputf(ErrCodeCloudIntegrationInvalidConfig, "metrics config is required for Azure service: %s", serviceID.StringValue())
}
storableAzureServiceConfig.Metrics = &StorableAzureMetricsServiceConfig{
Enabled: serviceConfig.Azure.Metrics.Enabled,
}
}
return &StorableServiceConfig{Azure: storableAzureServiceConfig}, nil
default:
return nil, errors.NewInvalidInputf(ErrCodeCloudProviderInvalidInput, "invalid cloud provider: %s", provider.StringValue())
}
@@ -201,6 +239,13 @@ func newStorableServiceConfigFromJSON(provider CloudProviderType, jsonStr string
return nil, errors.WrapInternalf(err, errors.CodeInternal, "couldn't parse AWS service config JSON")
}
return &StorableServiceConfig{AWS: awsConfig}, nil
case CloudProviderTypeAzure:
azureConfig := new(StorableAzureServiceConfig)
err := json.Unmarshal([]byte(jsonStr), azureConfig)
if err != nil {
return nil, errors.WrapInternalf(err, errors.CodeInternal, "couldn't parse Azure service config JSON")
}
return &StorableServiceConfig{Azure: azureConfig}, nil
default:
return nil, errors.NewInvalidInputf(ErrCodeCloudProviderInvalidInput, "invalid cloud provider: %s", provider.StringValue())
}
@@ -214,6 +259,13 @@ func (config *StorableServiceConfig) toJSON(provider CloudProviderType) ([]byte,
return nil, errors.WrapInternalf(err, errors.CodeInternal, "couldn't serialize AWS service config to JSON")
}
return jsonBytes, nil
case CloudProviderTypeAzure:
jsonBytes, err := json.Marshal(config.Azure)
if err != nil {
return nil, errors.WrapInternalf(err, errors.CodeInternal, "couldn't serialize Azure service config to JSON")
}
return jsonBytes, nil
default:
return nil, errors.NewInvalidInputf(ErrCodeCloudProviderInvalidInput, "invalid cloud provider: %s", provider.StringValue())

View File

@@ -23,6 +23,8 @@ type AWSAccountConfig struct {
Regions []string `json:"regions" required:"true" nullable:"false"`
}
type UpdatableAWSAccountConfig = AWSAccountConfig
// OldAWSCollectionStrategy is the backward-compatible snake_case form of AWSCollectionStrategy,
// used in the legacy integration_config response field for older agents.
type OldAWSCollectionStrategy struct {

View File

@@ -0,0 +1,64 @@
package cloudintegrationtypes
type AzureAccountConfig struct {
DeploymentRegion string `json:"deploymentRegion" required:"true"`
ResourceGroups []string `json:"resourceGroups" required:"true" nullable:"false"`
}
type UpdatableAzureAccountConfig struct {
ResourceGroups []string `json:"resourceGroups" required:"true" nullable:"false"`
}
type AzurePostableAccountConfig = AzureAccountConfig
type AzureConnectionArtifact struct {
CLICommand string `json:"cliCommand" required:"true"`
CloudPowerShellCommand string `json:"cloudPowerShellCommand" required:"true"`
}
type AzureServiceConfig struct {
Logs *AzureServiceLogsConfig `json:"logs" required:"true"`
Metrics *AzureServiceMetricsConfig `json:"metrics" required:"true"`
}
type AzureServiceLogsConfig struct {
Enabled bool `json:"enabled"`
}
type AzureServiceMetricsConfig struct {
Enabled bool `json:"enabled"`
}
type AzureTelemetryCollectionStrategy struct {
//https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/resource-providers-and-types
ResourceProvider string `json:"resourceProvider" required:"true"`
ResourceType string `json:"resourceType" required:"true"`
Metrics *AzureMetricsCollectionStrategy `json:"metrics,omitempty" required:"false" nullable:"false"`
Logs *AzureLogsCollectionStrategy `json:"logs,omitempty" required:"false" nullable:"false"`
}
// AzureMetricsCollectionStrategy no additional config required for metrics, will be added in future as required.
type AzureMetricsCollectionStrategy struct{}
type AzureLogsCollectionStrategy struct {
// List of categories to enable for diagnostic settings, to start with it will have 'allLogs' and no filtering.
CategoryGroups []string `json:"categoryGroups" required:"true" nullable:"false"`
}
type AzureIntegrationConfig struct {
DeploymentRegion string `json:"deploymentRegion" required:"true"`
ResourceGroups []string `json:"resourceGroups" required:"true" nullable:"false"`
TelemetryCollectionStrategy []*AzureTelemetryCollectionStrategy `json:"telemetryCollectionStrategy" required:"true" nullable:"false"`
}
func NewAzureIntegrationConfig(
deploymentRegion string,
resourceGroups []string,
strategies []*AzureTelemetryCollectionStrategy,
) *AzureIntegrationConfig {
return &AzureIntegrationConfig{
DeploymentRegion: deploymentRegion,
ResourceGroups: resourceGroups,
TelemetryCollectionStrategy: strategies,
}
}

View File

@@ -12,6 +12,7 @@ var (
// AWS regions.
AWSRegionAFSouth1 = CloudProviderRegion{valuer.NewString("af-south-1")} // Africa (Cape Town).
AWSRegionAPEast1 = CloudProviderRegion{valuer.NewString("ap-east-1")} // Asia Pacific (Hong Kong).
AWSRegionAPEast2 = CloudProviderRegion{valuer.NewString("ap-east-2")} // Asia Pacific (Taipei).
AWSRegionAPNortheast1 = CloudProviderRegion{valuer.NewString("ap-northeast-1")} // Asia Pacific (Tokyo).
AWSRegionAPNortheast2 = CloudProviderRegion{valuer.NewString("ap-northeast-2")} // Asia Pacific (Seoul).
AWSRegionAPNortheast3 = CloudProviderRegion{valuer.NewString("ap-northeast-3")} // Asia Pacific (Osaka).
@@ -21,6 +22,9 @@ var (
AWSRegionAPSoutheast2 = CloudProviderRegion{valuer.NewString("ap-southeast-2")} // Asia Pacific (Sydney).
AWSRegionAPSoutheast3 = CloudProviderRegion{valuer.NewString("ap-southeast-3")} // Asia Pacific (Jakarta).
AWSRegionAPSoutheast4 = CloudProviderRegion{valuer.NewString("ap-southeast-4")} // Asia Pacific (Melbourne).
AWSRegionAPSoutheast5 = CloudProviderRegion{valuer.NewString("ap-southeast-5")} // Asia Pacific (Malaysia).
AWSRegionAPSoutheast6 = CloudProviderRegion{valuer.NewString("ap-southeast-6")} // Asia Pacific (New Zealand).
AWSRegionAPSoutheast7 = CloudProviderRegion{valuer.NewString("ap-southeast-7")} // Asia Pacific (Thailand).
AWSRegionCACentral1 = CloudProviderRegion{valuer.NewString("ca-central-1")} // Canada (Central).
AWSRegionCAWest1 = CloudProviderRegion{valuer.NewString("ca-west-1")} // Canada West (Calgary).
AWSRegionEUCentral1 = CloudProviderRegion{valuer.NewString("eu-central-1")} // Europe (Frankfurt).
@@ -34,6 +38,7 @@ var (
AWSRegionILCentral1 = CloudProviderRegion{valuer.NewString("il-central-1")} // Israel (Tel Aviv).
AWSRegionMECentral1 = CloudProviderRegion{valuer.NewString("me-central-1")} // Middle East (UAE).
AWSRegionMESouth1 = CloudProviderRegion{valuer.NewString("me-south-1")} // Middle East (Bahrain).
AWSRegionMXCentral1 = CloudProviderRegion{valuer.NewString("mx-central-1")} // Mexico (Central).
AWSRegionSAEast1 = CloudProviderRegion{valuer.NewString("sa-east-1")} // South America (Sao Paulo).
AWSRegionUSEast1 = CloudProviderRegion{valuer.NewString("us-east-1")} // US East (N. Virginia).
AWSRegionUSEast2 = CloudProviderRegion{valuer.NewString("us-east-2")} // US East (Ohio).
@@ -102,11 +107,11 @@ var (
func Enum() []any {
return []any{
// AWS regions.
AWSRegionAFSouth1, AWSRegionAPEast1, AWSRegionAPNortheast1, AWSRegionAPNortheast2, AWSRegionAPNortheast3,
AWSRegionAFSouth1, AWSRegionAPEast1, AWSRegionAPEast2, AWSRegionAPNortheast1, AWSRegionAPNortheast2, AWSRegionAPNortheast3,
AWSRegionAPSouth1, AWSRegionAPSouth2, AWSRegionAPSoutheast1, AWSRegionAPSoutheast2, AWSRegionAPSoutheast3,
AWSRegionAPSoutheast4, AWSRegionCACentral1, AWSRegionCAWest1, AWSRegionEUCentral1, AWSRegionEUCentral2, AWSRegionEUNorth1,
AWSRegionAPSoutheast4, AWSRegionAPSoutheast5, AWSRegionAPSoutheast6, AWSRegionAPSoutheast7, AWSRegionCACentral1, AWSRegionCAWest1, AWSRegionEUCentral1, AWSRegionEUCentral2, AWSRegionEUNorth1,
AWSRegionEUSouth1, AWSRegionEUSouth2, AWSRegionEUWest1, AWSRegionEUWest2, AWSRegionEUWest3,
AWSRegionILCentral1, AWSRegionMECentral1, AWSRegionMESouth1, AWSRegionSAEast1, AWSRegionUSEast1, AWSRegionUSEast2,
AWSRegionILCentral1, AWSRegionMECentral1, AWSRegionMESouth1, AWSRegionMXCentral1, AWSRegionSAEast1, AWSRegionUSEast1, AWSRegionUSEast2,
AWSRegionUSWest1, AWSRegionUSWest2,
// Azure regions.
AzureRegionAustraliaCentral, AzureRegionAustraliaCentral2, AzureRegionAustraliaEast, AzureRegionAustraliaSoutheast,
@@ -127,11 +132,11 @@ func Enum() []any {
var SupportedRegions = map[CloudProviderType][]CloudProviderRegion{
CloudProviderTypeAWS: {
AWSRegionAFSouth1, AWSRegionAPEast1, AWSRegionAPNortheast1, AWSRegionAPNortheast2, AWSRegionAPNortheast3,
AWSRegionAFSouth1, AWSRegionAPEast1, AWSRegionAPEast2, AWSRegionAPNortheast1, AWSRegionAPNortheast2, AWSRegionAPNortheast3,
AWSRegionAPSouth1, AWSRegionAPSouth2, AWSRegionAPSoutheast1, AWSRegionAPSoutheast2, AWSRegionAPSoutheast3,
AWSRegionAPSoutheast4, AWSRegionCACentral1, AWSRegionCAWest1, AWSRegionEUCentral1, AWSRegionEUCentral2, AWSRegionEUNorth1,
AWSRegionAPSoutheast4, AWSRegionAPSoutheast5, AWSRegionAPSoutheast6, AWSRegionAPSoutheast7, AWSRegionCACentral1, AWSRegionCAWest1, AWSRegionEUCentral1, AWSRegionEUCentral2, AWSRegionEUNorth1,
AWSRegionEUSouth1, AWSRegionEUSouth2, AWSRegionEUWest1, AWSRegionEUWest2, AWSRegionEUWest3,
AWSRegionILCentral1, AWSRegionMECentral1, AWSRegionMESouth1, AWSRegionSAEast1, AWSRegionUSEast1, AWSRegionUSEast2,
AWSRegionILCentral1, AWSRegionMECentral1, AWSRegionMESouth1, AWSRegionMXCentral1, AWSRegionSAEast1, AWSRegionUSEast1, AWSRegionUSEast2,
AWSRegionUSWest1, AWSRegionUSWest2,
},
CloudProviderTypeAzure: {
@@ -160,3 +165,13 @@ func validateAWSRegion(region string) error {
return errors.NewInvalidInputf(ErrCodeInvalidCloudRegion, "invalid AWS region: %s", region)
}
func validateAzureRegion(region string) error {
for _, r := range SupportedRegions[CloudProviderTypeAzure] {
if r.StringValue() == region {
return nil
}
}
return errors.NewInvalidInputf(ErrCodeInvalidCloudRegion, "invalid Azure region: %s", region)
}

View File

@@ -21,8 +21,8 @@ type CloudIntegrationService struct {
}
type ServiceConfig struct {
// required till new providers are added
AWS *AWSServiceConfig `json:"aws" required:"true" nullable:"false"`
AWS *AWSServiceConfig `json:"aws,omitempty" required:"false" nullable:"false"`
Azure *AzureServiceConfig `json:"azure,omitempty" required:"false" nullable:"false"`
}
// ServiceMetadata helps to quickly list available services and whether it is enabled or not.
@@ -88,7 +88,8 @@ type DataCollected struct {
// TelemetryCollectionStrategy is cloud provider specific configuration for signal collection,
// this is used by agent to understand the nitty-gritty for collecting telemetry for the cloud provider.
type TelemetryCollectionStrategy struct {
AWS *AWSTelemetryCollectionStrategy `json:"aws" required:"true" nullable:"false"`
AWS *AWSTelemetryCollectionStrategy `json:"aws,omitempty" required:"false" nullable:"false"`
Azure *AzureTelemetryCollectionStrategy `json:"azure,omitempty" required:"false" nullable:"false"`
}
// Assets represents the collection of dashboards.
@@ -122,7 +123,18 @@ type Dashboard struct {
Definition dashboardtypes.StorableDashboardData `json:"definition,omitempty"`
}
func NewCloudIntegrationService(serviceID ServiceID, cloudIntegrationID valuer.UUID, config *ServiceConfig) *CloudIntegrationService {
func NewCloudIntegrationService(serviceID ServiceID, cloudIntegrationID valuer.UUID, provider CloudProviderType, config *ServiceConfig) (*CloudIntegrationService, error) {
switch provider {
case CloudProviderTypeAWS:
if config.AWS == nil {
return nil, errors.NewInvalidInputf(ErrCodeInvalidInput, "AWS config is required for AWS service")
}
case CloudProviderTypeAzure:
if config.Azure == nil {
return nil, errors.NewInvalidInputf(ErrCodeInvalidInput, "Azure config is required for Azure service")
}
}
return &CloudIntegrationService{
Identifiable: types.Identifiable{
ID: valuer.GenerateUUID(),
@@ -134,7 +146,7 @@ func NewCloudIntegrationService(serviceID ServiceID, cloudIntegrationID valuer.U
Type: serviceID,
Config: config,
CloudIntegrationID: cloudIntegrationID,
}
}, nil
}
func NewCloudIntegrationServiceFromStorable(stored *StorableCloudIntegrationService, config *ServiceConfig) *CloudIntegrationService {
@@ -191,6 +203,22 @@ func NewServiceConfigFromJSON(provider CloudProviderType, jsonString string) (*S
}
return &ServiceConfig{AWS: awsServiceConfig}, nil
case CloudProviderTypeAzure:
azureServiceConfig := new(AzureServiceConfig)
if storableServiceConfig.Azure.Logs != nil {
azureServiceConfig.Logs = &AzureServiceLogsConfig{
Enabled: storableServiceConfig.Azure.Logs.Enabled,
}
}
if storableServiceConfig.Azure.Metrics != nil {
azureServiceConfig.Metrics = &AzureServiceMetricsConfig{
Enabled: storableServiceConfig.Azure.Metrics.Enabled,
}
}
return &ServiceConfig{Azure: azureServiceConfig}, nil
default:
return nil, errors.NewInvalidInputf(ErrCodeCloudProviderInvalidInput, "invalid cloud provider: %s", provider.StringValue())
}
@@ -228,6 +256,10 @@ func (config *ServiceConfig) IsServiceEnabled(provider CloudProviderType) bool {
logsEnabled := config.AWS.Logs != nil && config.AWS.Logs.Enabled
metricsEnabled := config.AWS.Metrics != nil && config.AWS.Metrics.Enabled
return logsEnabled || metricsEnabled
case CloudProviderTypeAzure:
logsEnabled := config.Azure.Logs != nil && config.Azure.Logs.Enabled
metricsEnabled := config.Azure.Metrics != nil && config.Azure.Metrics.Enabled
return logsEnabled || metricsEnabled
default:
return false
}
@@ -239,6 +271,8 @@ func (config *ServiceConfig) IsMetricsEnabled(provider CloudProviderType) bool {
switch provider {
case CloudProviderTypeAWS:
return config.AWS.Metrics != nil && config.AWS.Metrics.Enabled
case CloudProviderTypeAzure:
return config.Azure.Metrics != nil && config.Azure.Metrics.Enabled
default:
return false
}
@@ -249,6 +283,8 @@ func (config *ServiceConfig) IsLogsEnabled(provider CloudProviderType) bool {
switch provider {
case CloudProviderTypeAWS:
return config.AWS.Logs != nil && config.AWS.Logs.Enabled
case CloudProviderTypeAzure:
return config.Azure.Logs != nil && config.Azure.Logs.Enabled
default:
return false
}
@@ -331,4 +367,3 @@ func GetDashboardsFromAssets(
return dashboards
}

View File

@@ -23,6 +23,10 @@ var (
AWSServiceS3Sync = ServiceID{valuer.NewString("s3sync")}
AWSServiceSNS = ServiceID{valuer.NewString("sns")}
AWSServiceSQS = ServiceID{valuer.NewString("sqs")}
// Azure services.
AzureServiceStorageAccountsBlob = ServiceID{valuer.NewString("storageaccountsblob")}
AzureServiceCDNProfile = ServiceID{valuer.NewString("cdnprofile")}
)
func (ServiceID) Enum() []any {
@@ -40,6 +44,8 @@ func (ServiceID) Enum() []any {
AWSServiceS3Sync,
AWSServiceSNS,
AWSServiceSQS,
AzureServiceStorageAccountsBlob,
AzureServiceCDNProfile,
}
}
@@ -60,6 +66,10 @@ var SupportedServices = map[CloudProviderType][]ServiceID{
AWSServiceSNS,
AWSServiceSQS,
},
CloudProviderTypeAzure: {
AzureServiceStorageAccountsBlob,
AzureServiceCDNProfile,
},
}
func NewServiceID(provider CloudProviderType, service string) (ServiceID, error) {