Files
signoz/frontend/src/container/QueryBuilder/components/QueryFunctions/QueryFunctions.tsx
Shivam Gupta 526a7d1c46
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: update stale docs links in frontend (#11319)
* fix: update 47 stale docs links in frontend to current URLs

Update documentation links across 19 frontend files to match
current signoz.io docs structure after product module restructures.

Key changes:
- Instrumentation links updated to new OpenTelemetry-prefixed paths
- product-features/* links replaced with current locations
- Query builder links point to new querying module pages
- Alert notification channel links point to setup-alerts-notification
- SSO, infra monitoring, and version upgrade links corrected

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update 278 more stale docs links and broken anchors in frontend

- Onboarding md-docs: update instrumentation URLs to canonical paths
  (django/flask/fastapi/falcon → opentelemetry-python, express/nestjs →
  javascript/opentelemetry-nodejs, springboot → java/opentelemetry-java,
  tomcat → java/opentelemetry-tomcat, jboss → java/opentelemetry-jboss,
  golang → opentelemetry-golang, elixir → opentelemetry-elixir,
  reactjs → frontend-monitoring/sending-traces-with-opentelemetry)
- Onboarding md-docs: update tutorial/* → opentelemetry-collection-agents/*,
  userguide/hostmetrics → infrastructure-monitoring/hostmetrics,
  userguide/logs# → userguide/logs_query_builder#
- Query builder UI: fix broken anchors after query-builder-v5 page
  restructure (Having → result-manipulation, Order By → result-manipulation,
  Limit → result-manipulation, Legend → aggregation-grouping, Group By →
  aggregation-grouping, Formula → multi-query-analysis, Trace Matching →
  multi-query-analysis, Reduce → result-manipulation, Aggregation functions
  → aggregation-grouping, Time aggregation → temporal-aggregation)
- Fix Apdex link → alerts-management/apdex-alerts
- Fix missing spans link → traces-management/troubleshooting/faqs
- Fix cost meter, ClickHouse traces, k8s pod logs anchors
- Drop broken anchors where sections were removed from docs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: format CreateAlertRule files after anchor removal

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: revert OnboardingContainer changes (deprecated module)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
Co-authored-by: Ubuntu <ubuntu@ip-172-31-24-8.eu-central-1.compute.internal>
2026-07-06 04:47:31 +00:00

242 lines
5.9 KiB
TypeScript

import { useState } from 'react';
import { Button, Tooltip } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import cx from 'classnames';
import { cloneDeep, pullAt } from 'lodash-es';
import { Plus } from '@signozhq/icons';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import { QueryFunction } from 'types/api/v5/queryRange';
import { DataSource, QueryFunctionsTypes } from 'types/common/queryBuilder';
import { normalizeFunctionName } from 'utils/functionNameNormalizer';
import Function from './Function';
import { toFloat64 } from './utils';
import './QueryFunctions.styles.scss';
const defaultMetricFunctionStruct: QueryFunction = {
name: QueryFunctionsTypes.CUTOFF_MIN as any,
args: [],
};
const defaultLogFunctionStruct: QueryFunction = {
name: QueryFunctionsTypes.TIME_SHIFT as any,
args: [],
};
interface QueryFunctionsProps {
query: IBuilderQuery;
queryFunctions: QueryFunction[];
onChange: (functions: QueryFunction[]) => void;
maxFunctions: number;
}
// SVG component
function FunctionIcon({
fillColor = 'white',
className,
}: {
fillColor: string;
className: string;
}): JSX.Element {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={className}
>
<path
d="M3 18.13C5.71436 18.13 6.8001 16.7728 6.8001 14.3299V8.62978C6.8001 5.91542 8.15728 4.15109 11.1431 4.55824"
stroke={fillColor}
strokeWidth="1.995"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M3 10.2583H10.7359"
stroke={fillColor}
strokeWidth="1.995"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M22.0005 11.344L15.2146 18.1299"
stroke={fillColor}
strokeWidth="1.995"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M15.2146 11.344L22.0005 18.1299"
stroke={fillColor}
strokeWidth="1.995"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}
export default function QueryFunctions({
query,
queryFunctions,
onChange,
maxFunctions = 3,
}: QueryFunctionsProps): JSX.Element {
const [functions, setFunctions] = useState<QueryFunction[]>(
queryFunctions.map((func) => ({
...func,
name: normalizeFunctionName(func.name) as any,
})),
);
const hasAnomalyFunction = functions.some((func) => func.name === 'anomaly');
const hasFunctions = functions.length > 0;
const handleAddNewFunction = (): void => {
const defaultFunctionStruct =
query.dataSource === DataSource.LOGS
? defaultLogFunctionStruct
: defaultMetricFunctionStruct;
const updatedFunctionsArr = [
...functions,
{
...defaultFunctionStruct,
},
];
const functionsCopy = cloneDeep(updatedFunctionsArr);
const anomalyFuncIndex = functionsCopy.findIndex(
(func) => func.name === 'anomaly',
);
if (anomalyFuncIndex !== -1) {
const anomalyFunc = functionsCopy[anomalyFuncIndex];
functionsCopy.splice(anomalyFuncIndex, 1);
functionsCopy.push(anomalyFunc);
}
setFunctions(functionsCopy);
onChange(functionsCopy);
};
const handleDeleteFunction = (
queryFunction: QueryFunction,
index: number,
): void => {
const clonedFunctions = cloneDeep(functions);
pullAt(clonedFunctions, index);
setFunctions(clonedFunctions);
onChange(clonedFunctions);
};
const handleUpdateFunctionName = (
func: QueryFunction,
index: number,
value: string,
): void => {
const updateFunctions = cloneDeep(functions);
if (updateFunctions && updateFunctions.length > 0 && updateFunctions[index]) {
// Normalize function name from backend response to match frontend expectations
const normalizedValue = normalizeFunctionName(value);
updateFunctions[index].name = normalizedValue as any;
setFunctions(updateFunctions);
onChange(updateFunctions);
}
};
const handleUpdateFunctionArgs = (
func: QueryFunction,
index: number,
value: string,
): void => {
const updateFunctions = cloneDeep(functions);
if (updateFunctions && updateFunctions.length > 0 && updateFunctions[index]) {
updateFunctions[index].args = [
{
value:
updateFunctions[index].name === QueryFunctionsTypes.TIME_SHIFT
? toFloat64(value)
: value,
},
];
setFunctions(updateFunctions);
onChange(updateFunctions);
}
};
return (
<div
className={cx(
'query-functions-container',
hasFunctions ? 'hasFunctions' : '',
)}
>
<Button
className="periscope-btn function-btn"
disabled={hasFunctions}
onClick={handleAddNewFunction}
>
<FunctionIcon className="function-icon" fillColor="var(--l1-foreground)" />
</Button>
<div className="query-functions-list">
{functions.map((func, index) => (
<Function
query={query}
funcData={func}
index={index}
// eslint-disable-next-line react/no-array-index-key
key={index}
handleUpdateFunctionArgs={handleUpdateFunctionArgs}
handleUpdateFunctionName={handleUpdateFunctionName}
handleDeleteFunction={handleDeleteFunction}
/>
))}
</div>
<Tooltip
title={
functions && functions.length >= 3 ? (
`Functions are in early access. You can add a maximum of ${
hasAnomalyFunction ? 2 : 3
} function as of now.`
) : (
<div style={{ textAlign: 'center' }}>
Add new function
<Typography.Link
style={{ textDecoration: 'underline' }}
href="https://signoz.io/docs/querying/functions-extended-analysis/?utm_source=product&utm_medium=query-builder"
target="_blank"
>
{' '}
<br />
Learn more
</Typography.Link>
</div>
)
}
placement="right"
>
<Button
className="periscope-btn add-function-btn"
disabled={functions && functions.length >= maxFunctions}
onClick={handleAddNewFunction}
>
<Plus size={14} color="var(--l1-foreground)" />
</Button>
</Tooltip>
</div>
);
}