diff --git a/frontend/src/lib/query/createTableColumnsFromQuery.ts b/frontend/src/lib/query/createTableColumnsFromQuery.ts index 0637917efd..7fbbfbe3c7 100644 --- a/frontend/src/lib/query/createTableColumnsFromQuery.ts +++ b/frontend/src/lib/query/createTableColumnsFromQuery.ts @@ -4,8 +4,13 @@ import { FORMULA_REGEXP } from 'constants/regExp'; import { QueryTableProps } from 'container/QueryTable/QueryTable.intefaces'; import { toCapitalize } from 'lib/toCapitalize'; 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 { QueryBuilderData } from 'types/common/queryBuilder'; import { v4 as uuid } from 'uuid'; type CreateTableDataFromQueryParams = Pick< @@ -21,8 +26,10 @@ export type RowData = { type DynamicColumn = { key: keyof RowData; + title: string; + sourceLabel: string; data: (string | number)[]; - type: 'field' | 'operator'; + type: 'field' | 'operator' | 'formula'; // sortable: boolean; }; @@ -39,7 +46,6 @@ type CreateTableDataFromQuery = ( type FillColumnData = ( queryTableData: QueryDataV3[], dynamicColumns: DynamicColumns, - query: Query, ) => { filledDynamicColumns: DynamicColumns; rowsLength: number }; type GetDynamicColumns = ( @@ -54,43 +60,37 @@ type SeriesItemLabels = SeriesItem['labels']; const isFormula = (queryName: string): boolean => FORMULA_REGEXP.test(queryName); -const isColumnExist = ( - columnName: string, +const isValueExist = ( + field: keyof DynamicColumn, + value: string, columns: DynamicColumns, ): 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 haveUnderscore = title.includes('_'); - - if (haveUnderscore) { - return title - .split('_') - .map((str) => toCapitalize(str)) - .join(' '); - } - - return toCapitalize(title); -}; - -const getQueryOperator = ( - queryData: IBuilderQuery[], +const getQueryByName = ( + builder: QueryBuilderData, currentQueryName: string, -): string => { - const builderQuery = queryData.find((q) => q.queryName === currentQueryName); + type: T, +): (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 = ( - labels: T, + // labels: T, label: keyof T, dynamicColumns: DynamicColumns, ): void => { - if (isColumnExist(label as string, dynamicColumns)) return; + if (isValueExist('key', label as string, dynamicColumns)) return; // const labelValue = labels[label]; @@ -98,6 +98,8 @@ const createLabels = ( const fieldObj: DynamicColumn = { key: label as string, + title: label as string, + sourceLabel: label as string, data: [], type: 'field', // sortable: isNumber, @@ -106,6 +108,68 @@ const createLabels = ( 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 dynamicColumns: DynamicColumns = []; @@ -113,49 +177,52 @@ const getDynamicColumns: GetDynamicColumns = (queryTableData, query) => { if (currentQuery.list) { currentQuery.list.forEach((listItem) => { Object.keys(listItem.data).forEach((label) => { - createLabels( - listItem.data, - label as ListItemKey, - dynamicColumns, - ); + createLabels(label as ListItemKey, dynamicColumns); }); }); } if (currentQuery.series) { - if (!isColumnExist('timestamp', dynamicColumns)) { + if (!isValueExist('key', 'timestamp', dynamicColumns)) { dynamicColumns.push({ key: 'timestamp', + title: 'Timestamp', + sourceLabel: 'Timestamp', data: [], type: 'field', // sortable: true, }); } - currentQuery.series.forEach((seria) => { - Object.keys(seria.labels).forEach((label) => { - createLabels(seria.labels, label, dynamicColumns); - }); - }); - - const operator = getQueryOperator( - query.builder.queryData, + appendOperatorFormulaColumns( + query.builder, currentQuery.queryName, + dynamicColumns, ); - if (operator === '' || isColumnExist(operator, dynamicColumns)) return; - - const operatorColumn: DynamicColumn = { - key: operator, - data: [], - type: 'operator', - // sortable: true, - }; - dynamicColumns.push(operatorColumn); + currentQuery.series.forEach((seria) => { + Object.keys(seria.labels).forEach((label) => { + createLabels(label, dynamicColumns); + }); + }); } }); - 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 = ( @@ -179,7 +246,6 @@ const fillDataFromSeria = ( seria: SeriesItem, columns: DynamicColumns, queryName: string, - operator: string, ): void => { const labelEntries = Object.entries(seria.labels); @@ -195,13 +261,7 @@ const fillDataFromSeria = ( return; } - if (isFormula(queryName) && queryName === column.key) { - column.data.push(parseFloat(value.value).toFixed(2)); - unusedColumnsKeys.delete(column.key); - return; - } - - if (!isFormula(queryName) && operator === column.key) { + if (queryName === column.key) { column.data.push(parseFloat(value.value).toFixed(2)); unusedColumnsKeys.delete(column.key); 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 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) => { if (currentQuery.series) { currentQuery.series.forEach((seria) => { - const currentOperator = getQueryOperator( - query.builder.queryData, - currentQuery.queryName, - ); - - fillDataFromSeria( - seria, - resultColumns, - currentQuery.queryName, - currentOperator, - ); + fillDataFromSeria(seria, resultColumns, currentQuery.queryName); }); } @@ -303,7 +354,7 @@ const generateTableColumns = ( const column: ColumnType = { dataIndex: item.key, key: item.key, - title: prepareColumnTitle(item.key as string), + title: item.title, // sorter: item.sortable // ? (a: RowData, b: RowData): number => // (a[item.key] as number) - (b[item.key] as number) @@ -326,7 +377,6 @@ export const createTableColumnsFromQuery: CreateTableDataFromQuery = ({ const { filledDynamicColumns, rowsLength } = fillColumnsData( queryTableData, dynamicColumns, - query, ); const dataSource = generateData(filledDynamicColumns, rowsLength);