mirror of
https://github.com/SigNoz/signoz.git
synced 2025-12-29 16:14:42 +00:00
feat: added support for multiaggregation in columnUnit and thresholds
This commit is contained in:
parent
b3488e73a8
commit
8a1407c9f4
@ -1,6 +1,8 @@
|
||||
import { createAggregation } from 'api/v5/queryRange/prepareQueryRangePayloadV5';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import {
|
||||
Having,
|
||||
IBuilderQuery,
|
||||
Query,
|
||||
TagFilter,
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
@ -220,3 +222,49 @@ export const getQueryTitles = (currentQuery: Query): string[] => {
|
||||
|
||||
return currentQuery.promql.map((q) => q.name);
|
||||
};
|
||||
|
||||
// function to give you label value for query name taking multiaggregation into account
|
||||
export function getQueryLabelWithAggregation(
|
||||
queryData: IBuilderQuery[],
|
||||
legendMap: Record<string, string> = {},
|
||||
): { label: string; value: string }[] {
|
||||
const labels: { label: string; value: string }[] = [];
|
||||
|
||||
const aggregationPerQuery =
|
||||
queryData.reduce((acc, query) => {
|
||||
if (query.queryName && query.aggregations?.length) {
|
||||
acc[query.queryName] = createAggregation(query).map((a: any) => ({
|
||||
alias: a.alias,
|
||||
expression: a.expression,
|
||||
}));
|
||||
}
|
||||
return acc;
|
||||
}, {} as Record<string, any>) || {};
|
||||
|
||||
Object.entries(aggregationPerQuery).forEach(([queryName, aggregations]) => {
|
||||
const legend = legendMap[queryName];
|
||||
|
||||
if (aggregations.length > 1) {
|
||||
aggregations.forEach((agg: any, index: number) => {
|
||||
const aggregationName = agg.alias || agg.expression || '';
|
||||
const label = `${queryName}.${index}`;
|
||||
const value = legend
|
||||
? `${aggregationName}-${legend}`
|
||||
: `${queryName}.${aggregationName}`;
|
||||
labels.push({
|
||||
label,
|
||||
value,
|
||||
});
|
||||
});
|
||||
} else if (aggregations.length === 1) {
|
||||
const label = legend || queryName;
|
||||
const value = legend || queryName;
|
||||
labels.push({
|
||||
label,
|
||||
value,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return labels;
|
||||
}
|
||||
|
||||
@ -84,11 +84,12 @@ function GridTableComponent({
|
||||
const newValue = { ...val };
|
||||
Object.keys(val).forEach((k) => {
|
||||
if (columnUnits[k]) {
|
||||
// the check below takes care of not adding units for rows that have n/a values
|
||||
newValue[k] =
|
||||
val[k] !== 'n/a'
|
||||
? getYAxisFormattedValue(String(val[k]), columnUnits[k])
|
||||
: val[k];
|
||||
// the check below takes care of not adding units for rows that have n/a or null values
|
||||
if (val[k] !== 'n/a' && val[k] !== null) {
|
||||
newValue[k] = getYAxisFormattedValue(String(val[k]), columnUnits[k]);
|
||||
} else if (val[k] === null) {
|
||||
newValue[k] = 'n/a';
|
||||
}
|
||||
newValue[`${k}_without_unit`] = val[k];
|
||||
}
|
||||
});
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
align-items: center;
|
||||
|
||||
.heading {
|
||||
width: 20px;
|
||||
width: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,9 +2,9 @@ import './ColumnUnitSelector.styles.scss';
|
||||
|
||||
import { Typography } from 'antd';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { Dispatch, SetStateAction } from 'react';
|
||||
import { useGetQueryLabels } from 'hooks/useGetQueryLabels';
|
||||
import { Dispatch, SetStateAction, useCallback } from 'react';
|
||||
import { ColumnUnit } from 'types/api/dashboard/getAll';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
|
||||
import YAxisUnitSelector from '../YAxisUnitSelector';
|
||||
|
||||
@ -17,40 +17,33 @@ export function ColumnUnitSelector(
|
||||
props: ColumnUnitSelectorProps,
|
||||
): JSX.Element {
|
||||
const { currentQuery } = useQueryBuilder();
|
||||
|
||||
function getAggregateColumnsNamesAndLabels(): string[] {
|
||||
if (currentQuery.queryType === EQueryType.QUERY_BUILDER) {
|
||||
const queries = currentQuery.builder.queryData.map((q) => q.queryName);
|
||||
console.log(currentQuery.builder.queryData, queries);
|
||||
const formulas = currentQuery.builder.queryFormulas.map((q) => q.queryName);
|
||||
return [...queries, ...formulas];
|
||||
}
|
||||
if (currentQuery.queryType === EQueryType.CLICKHOUSE) {
|
||||
return currentQuery.clickhouse_sql.map((q) => q.name);
|
||||
}
|
||||
return currentQuery.promql.map((q) => q.name);
|
||||
}
|
||||
|
||||
const { columnUnits, setColumnUnits } = props;
|
||||
const aggregationQueries = getAggregateColumnsNamesAndLabels();
|
||||
|
||||
function handleColumnUnitSelect(queryName: string, value: string): void {
|
||||
setColumnUnits((prev) => ({
|
||||
...prev,
|
||||
[queryName]: value,
|
||||
}));
|
||||
}
|
||||
const aggregationQueries = useGetQueryLabels(currentQuery);
|
||||
|
||||
const handleColumnUnitSelect = useCallback(
|
||||
(queryName: string, value: string): void => {
|
||||
setColumnUnits((prev) => ({
|
||||
...prev,
|
||||
[queryName]: value,
|
||||
}));
|
||||
},
|
||||
[setColumnUnits],
|
||||
);
|
||||
|
||||
return (
|
||||
<section className="column-unit-selector">
|
||||
<Typography.Text className="heading">Column Units</Typography.Text>
|
||||
{aggregationQueries.map((query) => (
|
||||
{aggregationQueries.map(({ value, label }) => (
|
||||
<YAxisUnitSelector
|
||||
defaultValue={columnUnits[query]}
|
||||
onSelect={(value: string): void => handleColumnUnitSelect(query, value)}
|
||||
fieldLabel={query}
|
||||
key={query}
|
||||
defaultValue={columnUnits[value]}
|
||||
onSelect={(unitValue: string): void =>
|
||||
handleColumnUnitSelect(value, unitValue)
|
||||
}
|
||||
fieldLabel={label}
|
||||
key={value}
|
||||
handleClear={(): void => {
|
||||
handleColumnUnitSelect(query, '');
|
||||
handleColumnUnitSelect(value, '');
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
@ -4,11 +4,11 @@ import './ThresholdSelector.styles.scss';
|
||||
|
||||
import { Typography } from 'antd';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useGetQueryLabels } from 'hooks/useGetQueryLabels';
|
||||
import { Antenna, Plus } from 'lucide-react';
|
||||
import { useCallback } from 'react';
|
||||
import { DndProvider } from 'react-dnd';
|
||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import Threshold from './Threshold';
|
||||
@ -23,19 +23,7 @@ function ThresholdSelector({
|
||||
}: ThresholdSelectorProps): JSX.Element {
|
||||
const { currentQuery } = useQueryBuilder();
|
||||
|
||||
function getAggregateColumnsNamesAndLabels(): string[] {
|
||||
if (currentQuery.queryType === EQueryType.QUERY_BUILDER) {
|
||||
const queries = currentQuery.builder.queryData.map((q) => q.queryName);
|
||||
const formulas = currentQuery.builder.queryFormulas.map((q) => q.queryName);
|
||||
return [...queries, ...formulas];
|
||||
}
|
||||
if (currentQuery.queryType === EQueryType.CLICKHOUSE) {
|
||||
return currentQuery.clickhouse_sql.map((q) => q.name);
|
||||
}
|
||||
return currentQuery.promql.map((q) => q.name);
|
||||
}
|
||||
|
||||
const aggregationQueries = getAggregateColumnsNamesAndLabels();
|
||||
const aggregationQueries = useGetQueryLabels(currentQuery);
|
||||
|
||||
const moveThreshold = useCallback(
|
||||
(dragIndex: number, hoverIndex: number) => {
|
||||
@ -65,7 +53,7 @@ function ThresholdSelector({
|
||||
moveThreshold,
|
||||
keyIndex: thresholds.length,
|
||||
selectedGraph,
|
||||
thresholdTableOptions: aggregationQueries[0] || '',
|
||||
thresholdTableOptions: aggregationQueries[0]?.value || '',
|
||||
},
|
||||
...thresholds,
|
||||
]);
|
||||
@ -104,10 +92,7 @@ function ThresholdSelector({
|
||||
moveThreshold={moveThreshold}
|
||||
selectedGraph={selectedGraph}
|
||||
thresholdLabel={threshold.thresholdLabel}
|
||||
tableOptions={aggregationQueries.map((query) => ({
|
||||
value: query,
|
||||
label: query,
|
||||
}))}
|
||||
tableOptions={aggregationQueries}
|
||||
thresholdTableOptions={threshold.thresholdTableOptions}
|
||||
columnUnits={columnUnits}
|
||||
/>
|
||||
|
||||
48
frontend/src/hooks/useGetQueryLabels.ts
Normal file
48
frontend/src/hooks/useGetQueryLabels.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import { getQueryLabelWithAggregation } from 'components/QueryBuilderV2/utils';
|
||||
import { useMemo } from 'react';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
|
||||
export const useGetQueryLabels = (
|
||||
currentQuery: Query,
|
||||
): { label: string; value: string }[] => {
|
||||
const legendMap = useMemo(() => {
|
||||
const newLegendMap: Record<string, string> = {};
|
||||
if (currentQuery?.queryType === EQueryType.QUERY_BUILDER) {
|
||||
currentQuery?.builder?.queryData?.forEach((q) => {
|
||||
if (q.legend) {
|
||||
newLegendMap[q.queryName] = q.legend;
|
||||
}
|
||||
});
|
||||
currentQuery?.builder?.queryFormulas?.forEach((f) => {
|
||||
if (f.legend) {
|
||||
newLegendMap[f.queryName] = f.legend;
|
||||
}
|
||||
});
|
||||
}
|
||||
return newLegendMap;
|
||||
}, [currentQuery]);
|
||||
|
||||
return useMemo(() => {
|
||||
if (currentQuery?.queryType === EQueryType.QUERY_BUILDER) {
|
||||
const queryLabels = getQueryLabelWithAggregation(
|
||||
currentQuery?.builder?.queryData || [],
|
||||
legendMap,
|
||||
);
|
||||
const formulaLabels = currentQuery?.builder?.queryFormulas?.map(
|
||||
(formula) => ({
|
||||
label: formula.queryName,
|
||||
value: formula.queryName,
|
||||
}),
|
||||
);
|
||||
return [...queryLabels, ...formulaLabels];
|
||||
}
|
||||
if (currentQuery?.queryType === EQueryType.CLICKHOUSE) {
|
||||
return currentQuery?.clickhouse_sql?.map((q) => ({
|
||||
label: q.name,
|
||||
value: q.name,
|
||||
}));
|
||||
}
|
||||
return currentQuery?.promql?.map((q) => ({ label: q.name, value: q.name }));
|
||||
}, [currentQuery, legendMap]);
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user