mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-15 22:35:55 +08:00
fix: table column names with attribute and legend (#3142)
Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
This commit is contained in:
parent
c68b611ad9
commit
6efa1011aa
@ -4,8 +4,13 @@ import { FORMULA_REGEXP } from 'constants/regExp';
|
|||||||
import { QueryTableProps } from 'container/QueryTable/QueryTable.intefaces';
|
import { QueryTableProps } from 'container/QueryTable/QueryTable.intefaces';
|
||||||
import { toCapitalize } from 'lib/toCapitalize';
|
import { toCapitalize } from 'lib/toCapitalize';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
import { IBuilderQuery, Query } from 'types/api/queryBuilder/queryBuilderData';
|
import {
|
||||||
|
IBuilderFormula,
|
||||||
|
IBuilderQuery,
|
||||||
|
Query,
|
||||||
|
} from 'types/api/queryBuilder/queryBuilderData';
|
||||||
import { ListItem, QueryDataV3, SeriesItem } from 'types/api/widgets/getQuery';
|
import { ListItem, QueryDataV3, SeriesItem } from 'types/api/widgets/getQuery';
|
||||||
|
import { QueryBuilderData } from 'types/common/queryBuilder';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
type CreateTableDataFromQueryParams = Pick<
|
type CreateTableDataFromQueryParams = Pick<
|
||||||
@ -21,8 +26,10 @@ export type RowData = {
|
|||||||
|
|
||||||
type DynamicColumn = {
|
type DynamicColumn = {
|
||||||
key: keyof RowData;
|
key: keyof RowData;
|
||||||
|
title: string;
|
||||||
|
sourceLabel: string;
|
||||||
data: (string | number)[];
|
data: (string | number)[];
|
||||||
type: 'field' | 'operator';
|
type: 'field' | 'operator' | 'formula';
|
||||||
// sortable: boolean;
|
// sortable: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -39,7 +46,6 @@ type CreateTableDataFromQuery = (
|
|||||||
type FillColumnData = (
|
type FillColumnData = (
|
||||||
queryTableData: QueryDataV3[],
|
queryTableData: QueryDataV3[],
|
||||||
dynamicColumns: DynamicColumns,
|
dynamicColumns: DynamicColumns,
|
||||||
query: Query,
|
|
||||||
) => { filledDynamicColumns: DynamicColumns; rowsLength: number };
|
) => { filledDynamicColumns: DynamicColumns; rowsLength: number };
|
||||||
|
|
||||||
type GetDynamicColumns = (
|
type GetDynamicColumns = (
|
||||||
@ -54,43 +60,37 @@ type SeriesItemLabels = SeriesItem['labels'];
|
|||||||
const isFormula = (queryName: string): boolean =>
|
const isFormula = (queryName: string): boolean =>
|
||||||
FORMULA_REGEXP.test(queryName);
|
FORMULA_REGEXP.test(queryName);
|
||||||
|
|
||||||
const isColumnExist = (
|
const isValueExist = (
|
||||||
columnName: string,
|
field: keyof DynamicColumn,
|
||||||
|
value: string,
|
||||||
columns: DynamicColumns,
|
columns: DynamicColumns,
|
||||||
): boolean => {
|
): boolean => {
|
||||||
const columnKeys = columns.map((item) => item.key);
|
const existColumns = columns.find((item) => item[field] === value);
|
||||||
|
|
||||||
return columnKeys.includes(columnName);
|
return !!existColumns;
|
||||||
};
|
};
|
||||||
|
|
||||||
const prepareColumnTitle = (title: string): string => {
|
const getQueryByName = <T extends keyof QueryBuilderData>(
|
||||||
const haveUnderscore = title.includes('_');
|
builder: QueryBuilderData,
|
||||||
|
|
||||||
if (haveUnderscore) {
|
|
||||||
return title
|
|
||||||
.split('_')
|
|
||||||
.map((str) => toCapitalize(str))
|
|
||||||
.join(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
return toCapitalize(title);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getQueryOperator = (
|
|
||||||
queryData: IBuilderQuery[],
|
|
||||||
currentQueryName: string,
|
currentQueryName: string,
|
||||||
): string => {
|
type: T,
|
||||||
const builderQuery = queryData.find((q) => q.queryName === currentQueryName);
|
): (T extends 'queryData' ? IBuilderQuery : IBuilderFormula) | null => {
|
||||||
|
const queryArray = builder[type];
|
||||||
|
|
||||||
return builderQuery ? builderQuery.aggregateOperator : '';
|
const currentQuery =
|
||||||
|
queryArray.find((q) => q.queryName === currentQueryName) || null;
|
||||||
|
|
||||||
|
if (!currentQuery) return null;
|
||||||
|
|
||||||
|
return currentQuery as T extends 'queryData' ? IBuilderQuery : IBuilderFormula;
|
||||||
};
|
};
|
||||||
|
|
||||||
const createLabels = <T extends ListItemData | SeriesItemLabels>(
|
const createLabels = <T extends ListItemData | SeriesItemLabels>(
|
||||||
labels: T,
|
// labels: T,
|
||||||
label: keyof T,
|
label: keyof T,
|
||||||
dynamicColumns: DynamicColumns,
|
dynamicColumns: DynamicColumns,
|
||||||
): void => {
|
): void => {
|
||||||
if (isColumnExist(label as string, dynamicColumns)) return;
|
if (isValueExist('key', label as string, dynamicColumns)) return;
|
||||||
|
|
||||||
// const labelValue = labels[label];
|
// const labelValue = labels[label];
|
||||||
|
|
||||||
@ -98,6 +98,8 @@ const createLabels = <T extends ListItemData | SeriesItemLabels>(
|
|||||||
|
|
||||||
const fieldObj: DynamicColumn = {
|
const fieldObj: DynamicColumn = {
|
||||||
key: label as string,
|
key: label as string,
|
||||||
|
title: label as string,
|
||||||
|
sourceLabel: label as string,
|
||||||
data: [],
|
data: [],
|
||||||
type: 'field',
|
type: 'field',
|
||||||
// sortable: isNumber,
|
// sortable: isNumber,
|
||||||
@ -106,6 +108,68 @@ const createLabels = <T extends ListItemData | SeriesItemLabels>(
|
|||||||
dynamicColumns.push(fieldObj);
|
dynamicColumns.push(fieldObj);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const appendOperatorFormulaColumns = (
|
||||||
|
builder: QueryBuilderData,
|
||||||
|
currentQueryName: string,
|
||||||
|
dynamicColumns: DynamicColumns,
|
||||||
|
): void => {
|
||||||
|
const currentFormula = getQueryByName(
|
||||||
|
builder,
|
||||||
|
currentQueryName,
|
||||||
|
'queryFormulas',
|
||||||
|
);
|
||||||
|
if (currentFormula) {
|
||||||
|
let formulaLabel = `${currentFormula.queryName}(${currentFormula.expression})`;
|
||||||
|
|
||||||
|
if (currentFormula.legend) {
|
||||||
|
formulaLabel += ` - ${currentFormula.legend}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formulaColumn: DynamicColumn = {
|
||||||
|
key: currentQueryName,
|
||||||
|
title: formulaLabel,
|
||||||
|
sourceLabel: formulaLabel,
|
||||||
|
data: [],
|
||||||
|
type: 'formula',
|
||||||
|
// sortable: isNumber,
|
||||||
|
};
|
||||||
|
|
||||||
|
dynamicColumns.push(formulaColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentQueryData = getQueryByName(
|
||||||
|
builder,
|
||||||
|
currentQueryName,
|
||||||
|
'queryData',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!currentQueryData) return;
|
||||||
|
|
||||||
|
let operatorLabel = `${currentQueryData.aggregateOperator}`;
|
||||||
|
if (currentQueryData.aggregateAttribute.key) {
|
||||||
|
operatorLabel += `(${currentQueryData.aggregateAttribute.key})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentQueryData.legend) {
|
||||||
|
operatorLabel += ` - ${currentQueryData.legend}`;
|
||||||
|
} else {
|
||||||
|
operatorLabel += ` - ${currentQueryData.queryName}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const resultValue = `${toCapitalize(operatorLabel)}`;
|
||||||
|
|
||||||
|
const operatorColumn: DynamicColumn = {
|
||||||
|
key: currentQueryName,
|
||||||
|
title: resultValue,
|
||||||
|
sourceLabel: resultValue,
|
||||||
|
data: [],
|
||||||
|
type: 'operator',
|
||||||
|
// sortable: isNumber,
|
||||||
|
};
|
||||||
|
|
||||||
|
dynamicColumns.push(operatorColumn);
|
||||||
|
};
|
||||||
|
|
||||||
const getDynamicColumns: GetDynamicColumns = (queryTableData, query) => {
|
const getDynamicColumns: GetDynamicColumns = (queryTableData, query) => {
|
||||||
const dynamicColumns: DynamicColumns = [];
|
const dynamicColumns: DynamicColumns = [];
|
||||||
|
|
||||||
@ -113,49 +177,52 @@ const getDynamicColumns: GetDynamicColumns = (queryTableData, query) => {
|
|||||||
if (currentQuery.list) {
|
if (currentQuery.list) {
|
||||||
currentQuery.list.forEach((listItem) => {
|
currentQuery.list.forEach((listItem) => {
|
||||||
Object.keys(listItem.data).forEach((label) => {
|
Object.keys(listItem.data).forEach((label) => {
|
||||||
createLabels<ListItemData>(
|
createLabels<ListItemData>(label as ListItemKey, dynamicColumns);
|
||||||
listItem.data,
|
|
||||||
label as ListItemKey,
|
|
||||||
dynamicColumns,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentQuery.series) {
|
if (currentQuery.series) {
|
||||||
if (!isColumnExist('timestamp', dynamicColumns)) {
|
if (!isValueExist('key', 'timestamp', dynamicColumns)) {
|
||||||
dynamicColumns.push({
|
dynamicColumns.push({
|
||||||
key: 'timestamp',
|
key: 'timestamp',
|
||||||
|
title: 'Timestamp',
|
||||||
|
sourceLabel: 'Timestamp',
|
||||||
data: [],
|
data: [],
|
||||||
type: 'field',
|
type: 'field',
|
||||||
// sortable: true,
|
// sortable: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
currentQuery.series.forEach((seria) => {
|
appendOperatorFormulaColumns(
|
||||||
Object.keys(seria.labels).forEach((label) => {
|
query.builder,
|
||||||
createLabels<SeriesItemLabels>(seria.labels, label, dynamicColumns);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const operator = getQueryOperator(
|
|
||||||
query.builder.queryData,
|
|
||||||
currentQuery.queryName,
|
currentQuery.queryName,
|
||||||
|
dynamicColumns,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (operator === '' || isColumnExist(operator, dynamicColumns)) return;
|
currentQuery.series.forEach((seria) => {
|
||||||
|
Object.keys(seria.labels).forEach((label) => {
|
||||||
const operatorColumn: DynamicColumn = {
|
createLabels<SeriesItemLabels>(label, dynamicColumns);
|
||||||
key: operator,
|
});
|
||||||
data: [],
|
});
|
||||||
type: 'operator',
|
|
||||||
// sortable: true,
|
|
||||||
};
|
|
||||||
dynamicColumns.push(operatorColumn);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return dynamicColumns;
|
return dynamicColumns.map((item) => {
|
||||||
|
if (isFormula(item.key as string)) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sameValues = dynamicColumns.filter(
|
||||||
|
(column) => column.sourceLabel === item.sourceLabel,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (sameValues.length > 1) {
|
||||||
|
return { ...item, title: `${item.title} - ${item.key}` };
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const fillEmptyRowCells = (
|
const fillEmptyRowCells = (
|
||||||
@ -179,7 +246,6 @@ const fillDataFromSeria = (
|
|||||||
seria: SeriesItem,
|
seria: SeriesItem,
|
||||||
columns: DynamicColumns,
|
columns: DynamicColumns,
|
||||||
queryName: string,
|
queryName: string,
|
||||||
operator: string,
|
|
||||||
): void => {
|
): void => {
|
||||||
const labelEntries = Object.entries(seria.labels);
|
const labelEntries = Object.entries(seria.labels);
|
||||||
|
|
||||||
@ -195,13 +261,7 @@ const fillDataFromSeria = (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFormula(queryName) && queryName === column.key) {
|
if (queryName === column.key) {
|
||||||
column.data.push(parseFloat(value.value).toFixed(2));
|
|
||||||
unusedColumnsKeys.delete(column.key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isFormula(queryName) && operator === column.key) {
|
|
||||||
column.data.push(parseFloat(value.value).toFixed(2));
|
column.data.push(parseFloat(value.value).toFixed(2));
|
||||||
unusedColumnsKeys.delete(column.key);
|
unusedColumnsKeys.delete(column.key);
|
||||||
return;
|
return;
|
||||||
@ -238,25 +298,16 @@ const fillDataFromList = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const fillColumnsData: FillColumnData = (queryTableData, cols, query) => {
|
const fillColumnsData: FillColumnData = (queryTableData, cols) => {
|
||||||
const fields = cols.filter((item) => item.type === 'field');
|
const fields = cols.filter((item) => item.type === 'field');
|
||||||
const operators = cols.filter((item) => item.type === 'operator');
|
const operators = cols.filter((item) => item.type === 'operator');
|
||||||
const resultColumns = [...fields, ...operators];
|
const formulas = cols.filter((item) => item.type === 'formula');
|
||||||
|
const resultColumns = [...fields, ...operators, ...formulas];
|
||||||
|
|
||||||
queryTableData.forEach((currentQuery) => {
|
queryTableData.forEach((currentQuery) => {
|
||||||
if (currentQuery.series) {
|
if (currentQuery.series) {
|
||||||
currentQuery.series.forEach((seria) => {
|
currentQuery.series.forEach((seria) => {
|
||||||
const currentOperator = getQueryOperator(
|
fillDataFromSeria(seria, resultColumns, currentQuery.queryName);
|
||||||
query.builder.queryData,
|
|
||||||
currentQuery.queryName,
|
|
||||||
);
|
|
||||||
|
|
||||||
fillDataFromSeria(
|
|
||||||
seria,
|
|
||||||
resultColumns,
|
|
||||||
currentQuery.queryName,
|
|
||||||
currentOperator,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,7 +354,7 @@ const generateTableColumns = (
|
|||||||
const column: ColumnType<RowData> = {
|
const column: ColumnType<RowData> = {
|
||||||
dataIndex: item.key,
|
dataIndex: item.key,
|
||||||
key: item.key,
|
key: item.key,
|
||||||
title: prepareColumnTitle(item.key as string),
|
title: item.title,
|
||||||
// sorter: item.sortable
|
// sorter: item.sortable
|
||||||
// ? (a: RowData, b: RowData): number =>
|
// ? (a: RowData, b: RowData): number =>
|
||||||
// (a[item.key] as number) - (b[item.key] as number)
|
// (a[item.key] as number) - (b[item.key] as number)
|
||||||
@ -326,7 +377,6 @@ export const createTableColumnsFromQuery: CreateTableDataFromQuery = ({
|
|||||||
const { filledDynamicColumns, rowsLength } = fillColumnsData(
|
const { filledDynamicColumns, rowsLength } = fillColumnsData(
|
||||||
queryTableData,
|
queryTableData,
|
||||||
dynamicColumns,
|
dynamicColumns,
|
||||||
query,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const dataSource = generateData(filledDynamicColumns, rowsLength);
|
const dataSource = generateData(filledDynamicColumns, rowsLength);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user