Compare commits

...

4 Commits

Author SHA1 Message Date
Vinícius Lourenço
d694d903a7 fix(get-upload-chart-data): render as empty instead of skip series to be more safer 2026-04-21 18:39:51 -03:00
Vinícius Lourenço
f1cf60c9ef fix(getUploadChartData): ensure there's no way to crash due to bad sync state 2026-04-21 18:36:54 -03:00
Vinícius Lourenço
93f57a9670 fix(query-section): try fix issue with timing/useEffect delay 2026-04-21 18:28:53 -03:00
Vinícius Lourenço
51a8a3564b refactor(alert-rules): disable clickhouse/prompql for anomaly detection 2026-04-21 10:41:20 -03:00
3 changed files with 84 additions and 24 deletions

View File

@@ -24,6 +24,12 @@ import { FormContainer, StepHeading } from './styles';
import './QuerySection.styles.scss';
const ANOMALY_QUERY_SUPPORT_CLICKHOUSE_ISSUE =
'https://github.com/SigNoz/signoz/issues/11034';
const ANOMALY_QUERY_SUPPORT_PROMQL_ISSUE =
'https://github.com/SigNoz/signoz/issues/11036';
function QuerySection({
queryCategory,
setQueryCategory,
@@ -33,6 +39,7 @@ function QuerySection({
panelType,
ruleId,
hideTitle,
isAnomalyDetection,
}: QuerySectionProps): JSX.Element {
// init namespace for translations
const { t } = useTranslation('alerts');
@@ -74,6 +81,21 @@ function QuerySection({
/>
);
const anomalyDisabledTooltip = (url: string): JSX.Element => (
<span>
Coming soon for anomaly detection.{' '}
<Typography.Link
href={url}
target="_blank"
rel="noopener noreferrer"
style={{ color: 'inherit', textDecoration: 'underline' }}
>
Leave a thumbs-up
</Typography.Link>{' '}
to help us prioritize!
</span>
);
const tabs = [
{
label: (
@@ -88,17 +110,31 @@ function QuerySection({
},
{
label: (
<Tooltip title="ClickHouse">
<Button className="nav-btns">
<Tooltip
title={
isAnomalyDetection
? anomalyDisabledTooltip(ANOMALY_QUERY_SUPPORT_CLICKHOUSE_ISSUE)
: 'ClickHouse'
}
>
<Button className="nav-btns" disabled={isAnomalyDetection}>
<Terminal size={14} />
<Typography.Text>ClickHouse Query</Typography.Text>
</Button>
</Tooltip>
),
key: EQueryType.CLICKHOUSE,
disabled: isAnomalyDetection,
},
];
useEffect(() => {
if (isAnomalyDetection && queryCategory !== EQueryType.QUERY_BUILDER) {
setQueryCategory(EQueryType.QUERY_BUILDER);
setCurrentTab(EQueryType.QUERY_BUILDER);
}
}, [isAnomalyDetection, queryCategory, setQueryCategory]);
const items = useMemo(
() => [
{
@@ -114,19 +150,32 @@ function QuerySection({
},
{
label: (
<Tooltip title="ClickHouse">
<Button className="nav-btns">
<Tooltip
title={
isAnomalyDetection
? anomalyDisabledTooltip(ANOMALY_QUERY_SUPPORT_CLICKHOUSE_ISSUE)
: 'ClickHouse'
}
>
<Button className="nav-btns" disabled={isAnomalyDetection}>
<Terminal size={14} />
<Typography.Text>ClickHouse Query</Typography.Text>
</Button>
</Tooltip>
),
key: EQueryType.CLICKHOUSE,
disabled: isAnomalyDetection,
},
{
label: (
<Tooltip title="PromQL">
<Button className="nav-btns">
<Tooltip
title={
isAnomalyDetection
? anomalyDisabledTooltip(ANOMALY_QUERY_SUPPORT_PROMQL_ISSUE)
: 'PromQL'
}
>
<Button className="nav-btns" disabled={isAnomalyDetection}>
<PromQLIcon
fillColor={isDarkMode ? Color.BG_VANILLA_200 : Color.BG_INK_300}
/>
@@ -135,9 +184,10 @@ function QuerySection({
</Tooltip>
),
key: EQueryType.PROM,
disabled: isAnomalyDetection,
},
],
[isDarkMode],
[isDarkMode, isAnomalyDetection, anomalyDisabledTooltip],
);
const { registerShortcut, deregisterShortcut } = useKeyboardHotkeys();
@@ -205,16 +255,16 @@ function QuerySection({
}
};
const renderQuerySection = (c: EQueryType): JSX.Element | null => {
switch (c) {
case EQueryType.PROM:
return renderPromqlUI();
case EQueryType.CLICKHOUSE:
return renderChQueryUI();
case EQueryType.QUERY_BUILDER:
return renderMetricUI();
default:
return null;
if (c === EQueryType.PROM && !isAnomalyDetection) {
return renderPromqlUI();
}
if (c === EQueryType.CLICKHOUSE && !isAnomalyDetection) {
return renderChQueryUI();
}
if (c === EQueryType.QUERY_BUILDER) {
return renderMetricUI();
}
return null;
};
const step2Label = alertDef.alertType === 'METRIC_BASED_ALERT' ? '2' : '1';
@@ -241,10 +291,12 @@ interface QuerySectionProps {
panelType: PANEL_TYPES;
ruleId: string;
hideTitle?: boolean;
isAnomalyDetection?: boolean;
}
QuerySection.defaultProps = {
hideTitle: false,
isAnomalyDetection: false,
};
export default QuerySection;

View File

@@ -918,6 +918,9 @@ function FormAlertRules({
panelType={panelType || PANEL_TYPES.TIME_SERIES}
key={currentQuery.queryType}
ruleId={ruleId}
isAnomalyDetection={
alertDef.ruleType === AlertDetectionTypes.ANOMALY_DETECTION_ALERT
}
/>
<RuleOptions

View File

@@ -112,6 +112,7 @@ export const getUPlotChartData = (
const processAnomalyDetectionData = (
anomalyDetectionData: any,
isDarkMode: boolean,
// eslint-disable-next-line sonarjs/cognitive-complexity
): Record<string, { data: number[][]; color: string }> => {
if (!anomalyDetectionData) {
return {};
@@ -148,10 +149,14 @@ const processAnomalyDetectionData = (
anomalyDetectionData.length > 1 ? `${queryName}-${label}` : label;
// Single iteration instead of 5 separate map operations
const { values: seriesValues } = series[index];
const { values: predictedValues } = predictedSeries[index];
const { values: upperBoundValues } = upperBoundSeries[index];
const { values: lowerBoundValues } = lowerBoundSeries[index];
const { values: seriesValues } = series[index] || { values: [] };
const { values: predictedValues } = predictedSeries[index] || { values: [] };
const { values: upperBoundValues } = upperBoundSeries[index] || {
values: [],
};
const { values: lowerBoundValues } = lowerBoundSeries[index] || {
values: [],
};
const length = seriesValues.length;
const timestamps: number[] = new Array(length);
@@ -162,10 +167,10 @@ const processAnomalyDetectionData = (
for (let i = 0; i < length; i++) {
timestamps[i] = seriesValues[i].timestamp / 1000;
values[i] = seriesValues[i].value;
predicted[i] = predictedValues[i].value;
upperBound[i] = upperBoundValues[i].value;
lowerBound[i] = lowerBoundValues[i].value;
values[i] = seriesValues[i]?.value ?? null;
predicted[i] = predictedValues[i]?.value ?? null;
upperBound[i] = upperBoundValues[i]?.value ?? null;
lowerBound[i] = lowerBoundValues[i]?.value ?? null;
}
processedData[objKey] = {