From 85d7752350aae6aadb065ecc583187a047cbbdff Mon Sep 17 00:00:00 2001 From: Rajat Dabade Date: Thu, 14 Sep 2023 17:12:49 +0530 Subject: [PATCH 1/5] [Refactor]: added tag for data type and type of logs (#3554) --- .../LogDetailedView/FieldRenderer.tsx | 25 +++++++++++++++++++ .../LogDetailedView/LogDetailedView.types.ts | 11 ++++++++ .../container/LogDetailedView/TableView.tsx | 11 ++++---- .../src/container/LogDetailedView/utils.ts | 24 ++++++++++++++++++ 4 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 frontend/src/container/LogDetailedView/FieldRenderer.tsx create mode 100644 frontend/src/container/LogDetailedView/LogDetailedView.types.ts diff --git a/frontend/src/container/LogDetailedView/FieldRenderer.tsx b/frontend/src/container/LogDetailedView/FieldRenderer.tsx new file mode 100644 index 0000000000..3df11cb8b5 --- /dev/null +++ b/frontend/src/container/LogDetailedView/FieldRenderer.tsx @@ -0,0 +1,25 @@ +import { blue } from '@ant-design/colors'; +import { Tag } from 'antd'; + +import { FieldRendererProps } from './LogDetailedView.types'; +import { getFieldAttributes } from './utils'; + +function FieldRenderer({ field }: FieldRendererProps): JSX.Element { + const { dataType, newField, logType } = getFieldAttributes(field); + + return ( + + {dataType && newField && logType ? ( + <> + {newField} + Type: {logType} + Data type: {dataType} + + ) : ( + {field} + )} + + ); +} + +export default FieldRenderer; diff --git a/frontend/src/container/LogDetailedView/LogDetailedView.types.ts b/frontend/src/container/LogDetailedView/LogDetailedView.types.ts new file mode 100644 index 0000000000..0360ae11c3 --- /dev/null +++ b/frontend/src/container/LogDetailedView/LogDetailedView.types.ts @@ -0,0 +1,11 @@ +import { MetricsType } from 'container/MetricsApplication/constant'; + +export interface FieldRendererProps { + field: string; +} + +export interface IFieldAttributes { + dataType?: string; + newField?: string; + logType?: MetricsType; +} diff --git a/frontend/src/container/LogDetailedView/TableView.tsx b/frontend/src/container/LogDetailedView/TableView.tsx index a7b0391ff7..736e1a5da2 100644 --- a/frontend/src/container/LogDetailedView/TableView.tsx +++ b/frontend/src/container/LogDetailedView/TableView.tsx @@ -1,4 +1,4 @@ -import { blue, orange } from '@ant-design/colors'; +import { orange } from '@ant-design/colors'; import { LinkOutlined } from '@ant-design/icons'; import { Input, Space, Tooltip } from 'antd'; import { ColumnsType } from 'antd/es/table'; @@ -21,6 +21,7 @@ import { SET_DETAILED_LOG_DATA } from 'types/actions/logs'; import { ILog } from 'types/api/logs/log'; import ActionItem, { ActionItemProps } from './ActionItem'; +import FieldRenderer from './FieldRenderer'; import { flattenObject, recursiveParseJSON } from './utils'; // Fields which should be restricted from adding it to query @@ -91,7 +92,7 @@ function TableView({ const columns: ColumnsType = [ { title: 'Action', - width: 30, + width: 11, render: (fieldData: Record): JSX.Element | null => { const fieldKey = fieldData.field.split('.').slice(-1); if (!RESTRICTED_FIELDS.includes(fieldKey[0])) { @@ -110,12 +111,12 @@ function TableView({ title: 'Field', dataIndex: 'field', key: 'field', - width: 30, + width: 50, align: 'left', ellipsis: true, render: (field: string, record): JSX.Element => { const fieldKey = field.split('.').slice(-1); - const renderedField = {field}; + const renderedField = ; if (record.field === 'trace_id') { const traceId = flattenLogData[record.field]; @@ -161,7 +162,7 @@ function TableView({ title: 'Value', dataIndex: 'value', key: 'value', - width: 80, + width: 70, ellipsis: false, render: (field, record): JSX.Element => { if (record.field === 'body') { diff --git a/frontend/src/container/LogDetailedView/utils.ts b/frontend/src/container/LogDetailedView/utils.ts index 4a73c61933..b87a6a4ed0 100644 --- a/frontend/src/container/LogDetailedView/utils.ts +++ b/frontend/src/container/LogDetailedView/utils.ts @@ -1,3 +1,7 @@ +import { MetricsType } from 'container/MetricsApplication/constant'; + +import { IFieldAttributes } from './LogDetailedView.types'; + export const recursiveParseJSON = (obj: string): Record => { try { const value = JSON.parse(obj); @@ -32,3 +36,23 @@ export function flattenObject(obj: AnyObject, prefix = ''): AnyObject { return acc; }, {}); } + +export const getFieldAttributes = (field: string): IFieldAttributes => { + let dataType; + let newField; + let logType; + + if (field.startsWith('attributes_')) { + logType = MetricsType.Tag; + const stringWithoutPrefix = field.slice('attributes_'.length); + const parts = stringWithoutPrefix.split('.'); + [dataType, newField] = parts; + } else if (field.startsWith('resources_')) { + logType = MetricsType.Resource; + const stringWithoutPrefix = field.slice('resources_'.length); + const parts = stringWithoutPrefix.split('.'); + [dataType, newField] = parts; + } + + return { dataType, newField, logType }; +}; From 56f1f714613dc54f801319cf6a50426d771ec827 Mon Sep 17 00:00:00 2001 From: Palash Gupta Date: Fri, 15 Sep 2023 10:21:42 +0530 Subject: [PATCH 2/5] feat: tree is updated to show different node values instead of editor (#2696) * feat: tree is updated to show different node values instead of editor * chore: table view is updated * [Refactoring]: Seperate title and menu to another component (#3531) * refactor: separated the title renderer * refactor: separated styles * refactor: seperate types * refactor: instead of key showing value if array (#3532) * refactor: instead of key showing value if array * feat: added filter for array and also nodekey * refactor: made common check for value is array * refactor: changed the key to value for arrays * chore: getData types is updated * chore: getDataTypes function types is updated * refactor: connection to querybuilder (#3535) Co-authored-by: Palash Gupta * chore: operator is updated * fix: build is fixed * fix: build is fixed * chore: operator is updated * chore: operator is updated * chore: parsing is updated * chore: key is updated * Refactor: Log parsing updates (#3542) * refactor: updated nodekey * refactor: removed pasred data * refactor: parentIsArray check * chore: added the support for the bool * [Refactor]: handle nested object case (#3545) * refactor: updated nodekey * refactor: removed pasred data * refactor: parentIsArray check * refactor: handled nested array inside object case * fix: float issue parsing * chore: operator is updated * chore: title is updated * chore: title is updated * fix: update tagRegexp * fix: maintain single source of DataTypes * chore: operator is updated * fix: fixed due to merge conflicts --------- Co-authored-by: Rajat Dabade Co-authored-by: Yunus A M --- frontend/src/constants/queryBuilder.ts | 8 +- .../src/container/ExplorerOrderBy/index.tsx | 3 +- frontend/src/container/LiveLogs/constants.ts | 7 +- .../BodyTitleRenderer.styles.ts | 11 ++ .../LogDetailedView/BodyTitleRenderer.tsx | 89 +++++++++ .../LogDetailedView/LogDetailedView.types.ts | 9 + .../container/LogDetailedView/TableView.tsx | 18 +- .../src/container/LogDetailedView/constant.ts | 4 + .../container/LogDetailedView/util.test.ts | 41 +++- .../src/container/LogDetailedView/utils.ts | 58 ------ .../src/container/LogDetailedView/utils.tsx | 176 ++++++++++++++++++ .../container/LogsExplorerContext/utils.ts | 3 +- .../MetricsPageQueries/DBCallQueries.ts | 26 ++- .../MetricsPageQueries/ExternalQueries.ts | 43 +++-- .../MetricsPageQueries/OverviewQueries.ts | 84 +++++---- .../MetricsPageQueries/TopOperationQueries.ts | 20 +- .../container/MetricsApplication/constant.ts | 7 - .../LogsConnectionStatus.tsx | 3 +- .../HavingFilter/__tests__/utils.test.tsx | 3 +- .../filters/QueryBuilderSearch/index.tsx | 47 ++++- .../filters/QueryBuilderSearch/utils.ts | 11 +- .../ServiceMetrics/ServiceMetricsQuery.ts | 32 ++-- frontend/src/hooks/logs/types.ts | 9 +- frontend/src/hooks/logs/useActiveLog.ts | 21 ++- .../queryBuilder/useFetchKeysAndValues.ts | 7 +- .../src/hooks/queryBuilder/useOperatorType.ts | 2 + .../src/hooks/queryBuilder/useOperators.ts | 4 +- .../src/hooks/useResourceAttribute/utils.ts | 12 +- .../chooseAutocompleteFromCustomValue.ts | 14 +- .../newQueryBuilder/getPaginationQueryData.ts | 3 +- .../queryBuilder/queryAutocompleteResponse.ts | 17 +- 31 files changed, 577 insertions(+), 215 deletions(-) create mode 100644 frontend/src/container/LogDetailedView/BodyTitleRenderer.styles.ts create mode 100644 frontend/src/container/LogDetailedView/BodyTitleRenderer.tsx create mode 100644 frontend/src/container/LogDetailedView/constant.ts delete mode 100644 frontend/src/container/LogDetailedView/utils.ts create mode 100644 frontend/src/container/LogDetailedView/utils.tsx diff --git a/frontend/src/constants/queryBuilder.ts b/frontend/src/constants/queryBuilder.ts index ed0fe0c09b..c04005afa6 100644 --- a/frontend/src/constants/queryBuilder.ts +++ b/frontend/src/constants/queryBuilder.ts @@ -4,6 +4,7 @@ import { createNewBuilderItemName } from 'lib/newQueryBuilder/createNewBuilderIt import { AutocompleteType, BaseAutocompleteData, + DataTypes, LocalDataType, } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { @@ -46,7 +47,7 @@ export const selectValueDivider = '__'; export const baseAutoCompleteIdKeysOrder: (keyof Omit< BaseAutocompleteData, - 'id' + 'id' | 'isJSON' >)[] = ['key', 'dataType', 'type', 'isColumn']; export const autocompleteType: Record = { @@ -112,10 +113,11 @@ export const initialAutocompleteData: BaseAutocompleteData = { { dataType: null, key: '', isColumn: null, type: null }, baseAutoCompleteIdKeysOrder, ), - dataType: '', + dataType: DataTypes.EMPTY, key: '', isColumn: false, type: '', + isJSON: false, }; export const initialFilters: TagFilter = { @@ -273,6 +275,8 @@ export const OPERATORS = { '>': '>', '<=': '<=', '<': '<', + HAS: 'HAS', + NHAS: 'NHAS', }; export const QUERY_BUILDER_OPERATORS_BY_TYPES = { diff --git a/frontend/src/container/ExplorerOrderBy/index.tsx b/frontend/src/container/ExplorerOrderBy/index.tsx index 69f3b29580..54747f5be8 100644 --- a/frontend/src/container/ExplorerOrderBy/index.tsx +++ b/frontend/src/container/ExplorerOrderBy/index.tsx @@ -4,6 +4,7 @@ import { useOrderByFilter } from 'container/QueryBuilder/filters/OrderByFilter/u import { selectStyle } from 'container/QueryBuilder/filters/QueryBuilderSearch/config'; import { useGetAggregateKeys } from 'hooks/queryBuilder/useGetAggregateKeys'; import { memo, useMemo } from 'react'; +import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { StringOperators } from 'types/common/queryBuilder'; function ExplorerOrderBy({ query, onChange }: OrderByFilterProps): JSX.Element { @@ -33,7 +34,7 @@ function ExplorerOrderBy({ query, onChange }: OrderByFilterProps): JSX.Element { const keysOptions = createOptions(data?.payload?.attributeKeys || []); const customOptions = createOptions([ - { key: 'timestamp', isColumn: true, type: '', dataType: '' }, + { key: 'timestamp', isColumn: true, type: '', dataType: DataTypes.EMPTY }, ]); const baseOptions = [ diff --git a/frontend/src/container/LiveLogs/constants.ts b/frontend/src/container/LiveLogs/constants.ts index 826772900f..f2c5ca1c97 100644 --- a/frontend/src/container/LiveLogs/constants.ts +++ b/frontend/src/container/LiveLogs/constants.ts @@ -3,7 +3,10 @@ import { initialQueryBuilderFormValuesMap, } from 'constants/queryBuilder'; import { FILTERS } from 'container/QueryBuilder/filters/OrderByFilter/config'; -import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; +import { + BaseAutocompleteData, + DataTypes, +} from 'types/api/queryBuilder/queryAutocompleteResponse'; import { IBuilderQuery, Query } from 'types/api/queryBuilder/queryBuilderData'; import { LogsAggregatorOperator } from 'types/common/queryBuilder'; @@ -45,6 +48,6 @@ export const liveLogsCompositeQuery = constructCompositeQuery({ export const idObject: BaseAutocompleteData = { key: 'id', type: '', - dataType: 'string', + dataType: DataTypes.String, isColumn: true, }; diff --git a/frontend/src/container/LogDetailedView/BodyTitleRenderer.styles.ts b/frontend/src/container/LogDetailedView/BodyTitleRenderer.styles.ts new file mode 100644 index 0000000000..f5d157ee2e --- /dev/null +++ b/frontend/src/container/LogDetailedView/BodyTitleRenderer.styles.ts @@ -0,0 +1,11 @@ +import styled from 'styled-components'; + +export const TitleWrapper = styled.span` + .hover-reveal { + visibility: hidden; + } + + &:hover .hover-reveal { + visibility: visible; + } +`; diff --git a/frontend/src/container/LogDetailedView/BodyTitleRenderer.tsx b/frontend/src/container/LogDetailedView/BodyTitleRenderer.tsx new file mode 100644 index 0000000000..856c2b01dc --- /dev/null +++ b/frontend/src/container/LogDetailedView/BodyTitleRenderer.tsx @@ -0,0 +1,89 @@ +import { orange } from '@ant-design/colors'; +import { SettingOutlined } from '@ant-design/icons'; +import { Dropdown, MenuProps } from 'antd'; +import { OPERATORS } from 'constants/queryBuilder'; +import { useActiveLog } from 'hooks/logs/useActiveLog'; + +import { TitleWrapper } from './BodyTitleRenderer.styles'; +import { DROPDOWN_KEY } from './constant'; +import { BodyTitleRendererProps } from './LogDetailedView.types'; +import { + generateFieldKeyForArray, + getDataTypes, + removeObjectFromString, +} from './utils'; + +function BodyTitleRenderer({ + title, + parentIsArray = false, + nodeKey, + value, +}: BodyTitleRendererProps): JSX.Element { + const { onAddToQuery } = useActiveLog(); + + const filterHandler = (isFilterIn: boolean) => (): void => { + if (parentIsArray) { + onAddToQuery( + generateFieldKeyForArray( + removeObjectFromString(nodeKey), + getDataTypes(value), + ), + `${value}`, + isFilterIn ? OPERATORS.HAS : OPERATORS.NHAS, + true, + parentIsArray ? getDataTypes([value]) : getDataTypes(value), + ); + } else { + onAddToQuery( + `body.${removeObjectFromString(nodeKey)}`, + `${value}`, + isFilterIn ? OPERATORS['='] : OPERATORS['!='], + true, + getDataTypes(value), + ); + } + }; + + const onClickHandler: MenuProps['onClick'] = (props): void => { + const mapper = { + [DROPDOWN_KEY.FILTER_IN]: filterHandler(true), + [DROPDOWN_KEY.FILTER_OUT]: filterHandler(false), + }; + + const handler = mapper[props.key]; + + if (handler) { + handler(); + } + }; + + const menu: MenuProps = { + items: [ + { + key: DROPDOWN_KEY.FILTER_IN, + label: `Filter for ${value}`, + }, + { + key: DROPDOWN_KEY.FILTER_OUT, + label: `Filter out ${value}`, + }, + ], + onClick: onClickHandler, + }; + + return ( + + + + + {title.toString()}{' '} + {!parentIsArray && ( + + : {`${value}`} + + )} + + ); +} + +export default BodyTitleRenderer; diff --git a/frontend/src/container/LogDetailedView/LogDetailedView.types.ts b/frontend/src/container/LogDetailedView/LogDetailedView.types.ts index 0360ae11c3..730bab15c2 100644 --- a/frontend/src/container/LogDetailedView/LogDetailedView.types.ts +++ b/frontend/src/container/LogDetailedView/LogDetailedView.types.ts @@ -1,5 +1,14 @@ import { MetricsType } from 'container/MetricsApplication/constant'; +export interface BodyTitleRendererProps { + title: string; + nodeKey: string; + value: unknown; + parentIsArray?: boolean; +} + +export type AnyObject = { [key: string]: any }; + export interface FieldRendererProps { field: string; } diff --git a/frontend/src/container/LogDetailedView/TableView.tsx b/frontend/src/container/LogDetailedView/TableView.tsx index 736e1a5da2..5c76fa506e 100644 --- a/frontend/src/container/LogDetailedView/TableView.tsx +++ b/frontend/src/container/LogDetailedView/TableView.tsx @@ -1,8 +1,7 @@ import { orange } from '@ant-design/colors'; import { LinkOutlined } from '@ant-design/icons'; -import { Input, Space, Tooltip } from 'antd'; +import { Input, Space, Tooltip, Tree } from 'antd'; import { ColumnsType } from 'antd/es/table'; -import Editor from 'components/Editor'; import AddToQueryHOC, { AddToQueryHOCProps, } from 'components/Logs/AddToQueryHOC'; @@ -22,7 +21,7 @@ import { ILog } from 'types/api/logs/log'; import ActionItem, { ActionItemProps } from './ActionItem'; import FieldRenderer from './FieldRenderer'; -import { flattenObject, recursiveParseJSON } from './utils'; +import { flattenObject, jsonToDataNodes, recursiveParseJSON } from './utils'; // Fields which should be restricted from adding it to query const RESTRICTED_FIELDS = ['timestamp']; @@ -168,18 +167,7 @@ function TableView({ if (record.field === 'body') { const parsedBody = recursiveParseJSON(field); if (!isEmpty(parsedBody)) { - return ( - - ); + return ; } } diff --git a/frontend/src/container/LogDetailedView/constant.ts b/frontend/src/container/LogDetailedView/constant.ts new file mode 100644 index 0000000000..46ea2c5b57 --- /dev/null +++ b/frontend/src/container/LogDetailedView/constant.ts @@ -0,0 +1,4 @@ +export const DROPDOWN_KEY = { + FILTER_IN: 'filterIn', + FILTER_OUT: 'filterOut', +}; diff --git a/frontend/src/container/LogDetailedView/util.test.ts b/frontend/src/container/LogDetailedView/util.test.ts index 5fcc8824a1..4f080e23c1 100644 --- a/frontend/src/container/LogDetailedView/util.test.ts +++ b/frontend/src/container/LogDetailedView/util.test.ts @@ -1,4 +1,6 @@ -import { flattenObject, recursiveParseJSON } from './utils'; +import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse'; + +import { flattenObject, getDataTypes, recursiveParseJSON } from './utils'; describe('recursiveParseJSON', () => { it('should return an empty object if the input is not valid JSON', () => { @@ -146,3 +148,40 @@ describe('flattenObject in the objects recursively', () => { expect(flattenObject(complexObj)).toEqual(expected); }); }); + +describe('Get Data Types utils', () => { + it('should return String for string input', () => { + expect(getDataTypes('hello')).toBe(DataTypes.String); + }); + + it('should return Float64 for float input', () => { + expect(getDataTypes(3.14)).toBe(DataTypes.Float64); + }); + + it('should return Int64 for integer input', () => { + expect(getDataTypes(42)).toBe(DataTypes.Int64); + }); + + // Test for arrays + it('should return ArrayString for string array input', () => { + expect(getDataTypes(['hello', 'world'])).toBe(DataTypes.ArrayString); + }); + + it('should return ArrayFloat64 for float array input', () => { + expect(getDataTypes([1.23, 4.56, 7.89])).toBe(DataTypes.ArrayFloat64); + }); + + it('should return ArrayInt64 for integer array input', () => { + expect(getDataTypes([1, 2, 3])).toBe(DataTypes.ArrayInt64); + }); + + // Edge cases + it('should return Int64 for empty array input', () => { + expect(getDataTypes([])).toBe(DataTypes.Int64); + }); + + it('should handle mixed array (return based on first element)', () => { + expect(getDataTypes([1, 2.5, 3])).toBe(DataTypes.ArrayInt64); + expect(getDataTypes([2.5, 3, 1])).toBe(DataTypes.ArrayFloat64); + }); +}); diff --git a/frontend/src/container/LogDetailedView/utils.ts b/frontend/src/container/LogDetailedView/utils.ts deleted file mode 100644 index b87a6a4ed0..0000000000 --- a/frontend/src/container/LogDetailedView/utils.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { MetricsType } from 'container/MetricsApplication/constant'; - -import { IFieldAttributes } from './LogDetailedView.types'; - -export const recursiveParseJSON = (obj: string): Record => { - try { - const value = JSON.parse(obj); - if (typeof value === 'string') { - return recursiveParseJSON(value); - } - if (typeof value === 'object') { - Object.entries(value).forEach(([key, val]) => { - if (typeof val === 'string') { - value[key] = val.trim(); - } else if (typeof val === 'object') { - value[key] = recursiveParseJSON(JSON.stringify(val)); - } - }); - } - return value; - } catch (e) { - return {}; - } -}; - -type AnyObject = { [key: string]: any }; - -export function flattenObject(obj: AnyObject, prefix = ''): AnyObject { - return Object.keys(obj).reduce((acc: AnyObject, k: string): AnyObject => { - const pre = prefix.length ? `${prefix}.` : ''; - if (typeof obj[k] === 'object' && obj[k] !== null && !Array.isArray(obj[k])) { - Object.assign(acc, flattenObject(obj[k], pre + k)); - } else { - acc[pre + k] = obj[k]; - } - return acc; - }, {}); -} - -export const getFieldAttributes = (field: string): IFieldAttributes => { - let dataType; - let newField; - let logType; - - if (field.startsWith('attributes_')) { - logType = MetricsType.Tag; - const stringWithoutPrefix = field.slice('attributes_'.length); - const parts = stringWithoutPrefix.split('.'); - [dataType, newField] = parts; - } else if (field.startsWith('resources_')) { - logType = MetricsType.Resource; - const stringWithoutPrefix = field.slice('resources_'.length); - const parts = stringWithoutPrefix.split('.'); - [dataType, newField] = parts; - } - - return { dataType, newField, logType }; -}; diff --git a/frontend/src/container/LogDetailedView/utils.tsx b/frontend/src/container/LogDetailedView/utils.tsx new file mode 100644 index 0000000000..8baee65965 --- /dev/null +++ b/frontend/src/container/LogDetailedView/utils.tsx @@ -0,0 +1,176 @@ +import { DataNode } from 'antd/es/tree'; +import { MetricsType } from 'container/MetricsApplication/constant'; +import { uniqueId } from 'lodash-es'; +import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse'; + +import BodyTitleRenderer from './BodyTitleRenderer'; +import { AnyObject, IFieldAttributes } from './LogDetailedView.types'; + +export const recursiveParseJSON = (obj: string): Record => { + try { + const value = JSON.parse(obj); + if (typeof value === 'string') { + return recursiveParseJSON(value); + } + return value; + } catch (e) { + return {}; + } +}; + +export const computeDataNode = ( + key: string, + valueIsArray: boolean, + value: unknown, + nodeKey: string, +): DataNode => ({ + key: uniqueId(), + title: `${key} ${valueIsArray ? '[...]' : ''}`, + // eslint-disable-next-line @typescript-eslint/no-use-before-define + children: jsonToDataNodes( + value as Record, + valueIsArray ? `${nodeKey}[*]` : nodeKey, + valueIsArray, + ), +}); + +export function jsonToDataNodes( + json: Record, + parentKey = '', + parentIsArray = false, +): DataNode[] { + return Object.entries(json).map(([key, value]) => { + let nodeKey = parentKey || key; + if (parentIsArray) { + nodeKey += `.${value}`; + } else if (parentKey) { + nodeKey += `.${key}`; + } + + const valueIsArray = Array.isArray(value); + + if (parentIsArray) { + if (typeof value === 'object' && value !== null) { + return computeDataNode(key, valueIsArray, value, nodeKey); + } + + return { + key: uniqueId(), + title: ( + + ), + children: jsonToDataNodes({}, nodeKey, valueIsArray), + }; + } + + if (typeof value === 'object' && value !== null) { + return computeDataNode(key, valueIsArray, value, nodeKey); + } + return { + key: uniqueId(), + title: ( + + ), + }; + }); +} + +export function flattenObject(obj: AnyObject, prefix = ''): AnyObject { + return Object.keys(obj).reduce((acc: AnyObject, k: string): AnyObject => { + const pre = prefix.length ? `${prefix}.` : ''; + if (typeof obj[k] === 'object' && obj[k] !== null && !Array.isArray(obj[k])) { + Object.assign(acc, flattenObject(obj[k], pre + k)); + } else { + acc[pre + k] = obj[k]; + } + return acc; + }, {}); +} + +const isFloat = (num: number): boolean => num % 1 !== 0; + +export const getDataTypes = (value: unknown): DataTypes => { + if (typeof value === 'string') { + return DataTypes.String; + } + + if (typeof value === 'number') { + return isFloat(value) ? DataTypes.Float64 : DataTypes.Int64; + } + + if (typeof value === 'boolean') { + return DataTypes.bool; + } + + if (Array.isArray(value)) { + const firstElement = value[0]; + + if (typeof firstElement === 'string') { + return DataTypes.ArrayString; + } + + if (typeof firstElement === 'boolean') { + return DataTypes.ArrayBool; + } + + if (typeof firstElement === 'number') { + return isFloat(firstElement) ? DataTypes.ArrayFloat64 : DataTypes.ArrayInt64; + } + } + + return DataTypes.Int64; +}; + +export const generateFieldKeyForArray = ( + fieldKey: string, + dataType: DataTypes, +): string => { + let lastDotIndex = fieldKey.lastIndexOf('.'); + let resultNodeKey = fieldKey; + if (lastDotIndex !== -1) { + resultNodeKey = fieldKey.substring(0, lastDotIndex); + } + + let newResultNodeKey = resultNodeKey; + + if (dataType === DataTypes.Float64) { + lastDotIndex = resultNodeKey.lastIndexOf('.'); + if (lastDotIndex !== -1) { + newResultNodeKey = resultNodeKey.substring(0, lastDotIndex); + } + } + return `body.${newResultNodeKey}`; +}; + +export const removeObjectFromString = (str: string): string => + str.replace(/\[object Object\]./g, ''); + +export const getFieldAttributes = (field: string): IFieldAttributes => { + let dataType; + let newField; + let logType; + + if (field.startsWith('attributes_')) { + logType = MetricsType.Tag; + const stringWithoutPrefix = field.slice('attributes_'.length); + const parts = stringWithoutPrefix.split('.'); + [dataType, newField] = parts; + } else if (field.startsWith('resources_')) { + logType = MetricsType.Resource; + const stringWithoutPrefix = field.slice('resources_'.length); + const parts = stringWithoutPrefix.split('.'); + [dataType, newField] = parts; + } + + return { dataType, newField, logType }; +}; diff --git a/frontend/src/container/LogsExplorerContext/utils.ts b/frontend/src/container/LogsExplorerContext/utils.ts index 93456ce0cd..ab926ec8aa 100644 --- a/frontend/src/container/LogsExplorerContext/utils.ts +++ b/frontend/src/container/LogsExplorerContext/utils.ts @@ -1,5 +1,6 @@ import { OPERATORS } from 'constants/queryBuilder'; import { ILog } from 'types/api/logs/log'; +import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData'; import { v4 as uuid } from 'uuid'; @@ -12,7 +13,7 @@ export const getFiltersFromResources = ( id: uuid(), key: { key, - dataType: 'string', + dataType: DataTypes.String, type: 'resource', isColumn: false, }, diff --git a/frontend/src/container/MetricsApplication/MetricsPageQueries/DBCallQueries.ts b/frontend/src/container/MetricsApplication/MetricsPageQueries/DBCallQueries.ts index aa491a01fd..78d66bcaa5 100644 --- a/frontend/src/container/MetricsApplication/MetricsPageQueries/DBCallQueries.ts +++ b/frontend/src/container/MetricsApplication/MetricsPageQueries/DBCallQueries.ts @@ -1,5 +1,8 @@ import { OPERATORS } from 'constants/queryBuilder'; -import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; +import { + BaseAutocompleteData, + DataTypes, +} from 'types/api/queryBuilder/queryAutocompleteResponse'; import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData'; import { DataSource, @@ -7,7 +10,7 @@ import { QueryBuilderData, } from 'types/common/queryBuilder'; -import { DataType, FORMULA, MetricsType, WidgetKeys } from '../constant'; +import { FORMULA, MetricsType, WidgetKeys } from '../constant'; import { DatabaseCallProps, DatabaseCallsRPSProps } from '../types'; import { getQueryBuilderQueries, @@ -22,13 +25,18 @@ export const databaseCallsRPS = ({ const autocompleteData: BaseAutocompleteData[] = [ { key: WidgetKeys.SignozDBLatencyCount, - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, type: '', }, ]; const groupBy: BaseAutocompleteData[] = [ - { dataType: DataType.STRING, isColumn: false, key: 'db_system', type: 'tag' }, + { + dataType: DataTypes.String, + isColumn: false, + key: 'db_system', + type: 'tag', + }, ]; const filterItems: TagFilterItem[][] = [ [ @@ -36,7 +44,7 @@ export const databaseCallsRPS = ({ id: '', key: { key: WidgetKeys.Service_name, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, type: MetricsType.Resource, }, @@ -65,13 +73,13 @@ export const databaseCallsAvgDuration = ({ }: DatabaseCallProps): QueryBuilderData => { const autocompleteDataA: BaseAutocompleteData = { key: WidgetKeys.SignozDbLatencySum, - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, type: '', }; const autocompleteDataB: BaseAutocompleteData = { key: WidgetKeys.SignozDBLatencyCount, - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, type: '', }; @@ -81,12 +89,12 @@ export const databaseCallsAvgDuration = ({ id: '', key: { key: WidgetKeys.Service_name, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, type: MetricsType.Resource, }, op: OPERATORS.IN, - value: [`${servicename}`], + value: [servicename], }, ...tagFilterItems, ]; diff --git a/frontend/src/container/MetricsApplication/MetricsPageQueries/ExternalQueries.ts b/frontend/src/container/MetricsApplication/MetricsPageQueries/ExternalQueries.ts index 94f024bf25..ef57aa764e 100644 --- a/frontend/src/container/MetricsApplication/MetricsPageQueries/ExternalQueries.ts +++ b/frontend/src/container/MetricsApplication/MetricsPageQueries/ExternalQueries.ts @@ -1,5 +1,8 @@ import { OPERATORS } from 'constants/queryBuilder'; -import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; +import { + BaseAutocompleteData, + DataTypes, +} from 'types/api/queryBuilder/queryAutocompleteResponse'; import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData'; import { DataSource, @@ -7,7 +10,7 @@ import { QueryBuilderData, } from 'types/common/queryBuilder'; -import { DataType, FORMULA, MetricsType, WidgetKeys } from '../constant'; +import { FORMULA, MetricsType, WidgetKeys } from '../constant'; import { ExternalCallDurationByAddressProps, ExternalCallProps, @@ -19,7 +22,7 @@ import { const groupBy: BaseAutocompleteData[] = [ { - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, key: WidgetKeys.Address, type: MetricsType.Tag, @@ -33,13 +36,13 @@ export const externalCallErrorPercent = ({ }: ExternalCallDurationByAddressProps): QueryBuilderData => { const autocompleteDataA: BaseAutocompleteData = { key: WidgetKeys.SignozExternalCallLatencyCount, - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, type: '', }; const autocompleteDataB: BaseAutocompleteData = { key: WidgetKeys.SignozExternalCallLatencyCount, - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, type: '', }; @@ -49,18 +52,18 @@ export const externalCallErrorPercent = ({ id: '', key: { key: WidgetKeys.Service_name, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, type: MetricsType.Resource, }, op: OPERATORS.IN, - value: [`${servicename}`], + value: [servicename], }, { id: '', key: { key: WidgetKeys.StatusCode, - dataType: DataType.INT64, + dataType: DataTypes.Int64, isColumn: false, type: MetricsType.Tag, }, @@ -74,7 +77,7 @@ export const externalCallErrorPercent = ({ id: '', key: { key: WidgetKeys.Service_name, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, type: MetricsType.Resource, }, @@ -115,13 +118,13 @@ export const externalCallDuration = ({ tagFilterItems, }: ExternalCallProps): QueryBuilderData => { const autocompleteDataA: BaseAutocompleteData = { - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, key: WidgetKeys.SignozExternalCallLatencySum, type: '', }; const autocompleteDataB: BaseAutocompleteData = { - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, key: WidgetKeys.SignozExternalCallLatencyCount, type: '', @@ -134,13 +137,13 @@ export const externalCallDuration = ({ { id: '', key: { - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, key: WidgetKeys.Service_name, type: MetricsType.Resource, }, op: OPERATORS.IN, - value: [`${servicename}`], + value: [servicename], }, ...tagFilterItems, ]; @@ -174,7 +177,7 @@ export const externalCallRpsByAddress = ({ }: ExternalCallDurationByAddressProps): QueryBuilderData => { const autocompleteData: BaseAutocompleteData[] = [ { - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, key: WidgetKeys.SignozExternalCallLatencyCount, type: '', @@ -185,13 +188,13 @@ export const externalCallRpsByAddress = ({ { id: '', key: { - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, key: WidgetKeys.Service_name, type: MetricsType.Resource, }, op: OPERATORS.IN, - value: [`${servicename}`], + value: [servicename], }, ...tagFilterItems, ], @@ -215,13 +218,13 @@ export const externalCallDurationByAddress = ({ tagFilterItems, }: ExternalCallDurationByAddressProps): QueryBuilderData => { const autocompleteDataA: BaseAutocompleteData = { - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, key: WidgetKeys.SignozExternalCallLatencySum, type: '', }; const autocompleteDataB: BaseAutocompleteData = { - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, key: WidgetKeys.SignozExternalCallLatencyCount, type: '', @@ -233,13 +236,13 @@ export const externalCallDurationByAddress = ({ { id: '', key: { - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, key: WidgetKeys.Service_name, type: MetricsType.Resource, }, op: OPERATORS.IN, - value: [`${servicename}`], + value: [servicename], }, ...tagFilterItems, ]; diff --git a/frontend/src/container/MetricsApplication/MetricsPageQueries/OverviewQueries.ts b/frontend/src/container/MetricsApplication/MetricsPageQueries/OverviewQueries.ts index 91e365a0b8..3186931891 100644 --- a/frontend/src/container/MetricsApplication/MetricsPageQueries/OverviewQueries.ts +++ b/frontend/src/container/MetricsApplication/MetricsPageQueries/OverviewQueries.ts @@ -1,5 +1,8 @@ import { OPERATORS } from 'constants/queryBuilder'; -import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; +import { + BaseAutocompleteData, + DataTypes, +} from 'types/api/queryBuilder/queryAutocompleteResponse'; import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData'; import { DataSource, @@ -8,7 +11,6 @@ import { } from 'types/common/queryBuilder'; import { - DataType, FORMULA, GraphTitle, LATENCY_AGGREGATEOPERATOR, @@ -40,7 +42,7 @@ export const latency = ({ key: isSpanMetricEnable ? WidgetKeys.Signoz_latency_bucket : WidgetKeys.DurationNano, - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, type: isSpanMetricEnable ? '' : MetricsType.Tag, }; @@ -52,7 +54,7 @@ export const latency = ({ id: '', key: { key: isSpanMetricEnable ? WidgetKeys.Service_name : WidgetKeys.ServiceName, - dataType: DataType.STRING, + dataType: DataTypes.String, type: isSpanMetricEnable ? MetricsType.Resource : MetricsType.Tag, isColumn: !isSpanMetricEnable, }, @@ -62,7 +64,7 @@ export const latency = ({ { id: '', key: { - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: !isSpanMetricEnable, key: isSpanMetricEnable ? WidgetKeys.Operation : WidgetKeys.Name, type: MetricsType.Tag, @@ -98,21 +100,21 @@ export const apDexTracesQueryBuilderQueries = ({ threashold, }: ApDexProps): QueryBuilderData => { const autoCompleteDataA: BaseAutocompleteData = { - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, key: '', type: '', }; const autoCompleteDataB: BaseAutocompleteData = { - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, key: '', type: '', }; const autoCompleteDataC: BaseAutocompleteData = { - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, key: '', type: '', @@ -123,7 +125,7 @@ export const apDexTracesQueryBuilderQueries = ({ id: '', key: { key: WidgetKeys.ServiceName, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: true, type: MetricsType.Tag, }, @@ -134,7 +136,7 @@ export const apDexTracesQueryBuilderQueries = ({ id: '', key: { key: WidgetKeys.Name, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: true, type: MetricsType.Tag, }, @@ -149,7 +151,7 @@ export const apDexTracesQueryBuilderQueries = ({ id: '', key: { key: WidgetKeys.HasError, - dataType: DataType.BOOL, + dataType: DataTypes.bool, isColumn: true, type: MetricsType.Tag, }, @@ -160,7 +162,7 @@ export const apDexTracesQueryBuilderQueries = ({ id: '', key: { key: WidgetKeys.DurationNano, - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, type: MetricsType.Tag, }, @@ -171,7 +173,7 @@ export const apDexTracesQueryBuilderQueries = ({ id: '', key: { key: WidgetKeys.ServiceName, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: true, type: MetricsType.Tag, }, @@ -182,7 +184,7 @@ export const apDexTracesQueryBuilderQueries = ({ id: '', key: { key: WidgetKeys.Name, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: true, type: MetricsType.Tag, }, @@ -196,7 +198,7 @@ export const apDexTracesQueryBuilderQueries = ({ id: '', key: { key: WidgetKeys.DurationNano, - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, type: MetricsType.Tag, }, @@ -207,7 +209,7 @@ export const apDexTracesQueryBuilderQueries = ({ id: '', key: { key: WidgetKeys.HasError, - dataType: DataType.BOOL, + dataType: DataTypes.bool, isColumn: true, type: MetricsType.Tag, }, @@ -218,7 +220,7 @@ export const apDexTracesQueryBuilderQueries = ({ id: '', key: { key: WidgetKeys.ServiceName, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: true, type: MetricsType.Tag, }, @@ -229,7 +231,7 @@ export const apDexTracesQueryBuilderQueries = ({ id: '', key: { key: WidgetKeys.Name, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: true, type: MetricsType.Tag, }, @@ -277,21 +279,21 @@ export const apDexMetricsQueryBuilderQueries = ({ }: ApDexMetricsQueryBuilderQueriesProps): QueryBuilderData => { const autoCompleteDataA: BaseAutocompleteData = { key: WidgetKeys.SignozLatencyCount, - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, type: '', }; const autoCompleteDataB: BaseAutocompleteData = { key: WidgetKeys.Signoz_latency_bucket, - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, type: '', }; const autoCompleteDataC: BaseAutocompleteData = { key: WidgetKeys.Signoz_latency_bucket, - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, type: '', }; @@ -301,7 +303,7 @@ export const apDexMetricsQueryBuilderQueries = ({ id: '', key: { key: WidgetKeys.Service_name, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, type: MetricsType.Tag, }, @@ -312,7 +314,7 @@ export const apDexMetricsQueryBuilderQueries = ({ id: '', key: { key: WidgetKeys.Operation, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, type: MetricsType.Tag, }, @@ -327,7 +329,7 @@ export const apDexMetricsQueryBuilderQueries = ({ id: '', key: { key: WidgetKeys.StatusCode, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, type: MetricsType.Tag, }, @@ -338,7 +340,7 @@ export const apDexMetricsQueryBuilderQueries = ({ id: '', key: { key: WidgetKeys.Le, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, type: MetricsType.Tag, }, @@ -349,7 +351,7 @@ export const apDexMetricsQueryBuilderQueries = ({ id: '', key: { key: WidgetKeys.Service_name, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, type: MetricsType.Tag, }, @@ -360,7 +362,7 @@ export const apDexMetricsQueryBuilderQueries = ({ id: '', key: { key: WidgetKeys.Operation, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, type: MetricsType.Tag, }, @@ -375,7 +377,7 @@ export const apDexMetricsQueryBuilderQueries = ({ id: '', key: { key: WidgetKeys.Le, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, type: MetricsType.Tag, }, @@ -386,7 +388,7 @@ export const apDexMetricsQueryBuilderQueries = ({ id: '', key: { key: WidgetKeys.StatusCode, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, type: MetricsType.Tag, }, @@ -397,7 +399,7 @@ export const apDexMetricsQueryBuilderQueries = ({ id: '', key: { key: WidgetKeys.Service_name, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, type: MetricsType.Tag, }, @@ -408,7 +410,7 @@ export const apDexMetricsQueryBuilderQueries = ({ id: '', key: { key: WidgetKeys.Operation, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, type: MetricsType.Tag, }, @@ -458,7 +460,7 @@ export const operationPerSec = ({ const autocompleteData: BaseAutocompleteData[] = [ { key: WidgetKeys.SignozLatencyCount, - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, type: '', }, @@ -470,7 +472,7 @@ export const operationPerSec = ({ id: '', key: { key: WidgetKeys.Service_name, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, type: MetricsType.Resource, }, @@ -481,7 +483,7 @@ export const operationPerSec = ({ id: '', key: { key: WidgetKeys.Operation, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, type: MetricsType.Tag, }, @@ -510,13 +512,13 @@ export const errorPercentage = ({ }: OperationPerSecProps): QueryBuilderData => { const autocompleteDataA: BaseAutocompleteData = { key: WidgetKeys.SignozCallsTotal, - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, type: '', }; const autocompleteDataB: BaseAutocompleteData = { key: WidgetKeys.SignozCallsTotal, - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, type: '', }; @@ -528,7 +530,7 @@ export const errorPercentage = ({ id: '', key: { key: WidgetKeys.Service_name, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, type: MetricsType.Resource, }, @@ -539,7 +541,7 @@ export const errorPercentage = ({ id: '', key: { key: WidgetKeys.Operation, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, type: MetricsType.Tag, }, @@ -550,7 +552,7 @@ export const errorPercentage = ({ id: '', key: { key: WidgetKeys.StatusCode, - dataType: DataType.INT64, + dataType: DataTypes.Int64, isColumn: false, type: MetricsType.Tag, }, @@ -565,7 +567,7 @@ export const errorPercentage = ({ id: '', key: { key: WidgetKeys.Service_name, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, type: MetricsType.Resource, }, @@ -576,7 +578,7 @@ export const errorPercentage = ({ id: '', key: { key: WidgetKeys.Operation, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, type: MetricsType.Tag, }, diff --git a/frontend/src/container/MetricsApplication/MetricsPageQueries/TopOperationQueries.ts b/frontend/src/container/MetricsApplication/MetricsPageQueries/TopOperationQueries.ts index 9356d5e860..225e2084cd 100644 --- a/frontend/src/container/MetricsApplication/MetricsPageQueries/TopOperationQueries.ts +++ b/frontend/src/container/MetricsApplication/MetricsPageQueries/TopOperationQueries.ts @@ -1,5 +1,8 @@ import { OPERATORS } from 'constants/queryBuilder'; -import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; +import { + BaseAutocompleteData, + DataTypes, +} from 'types/api/queryBuilder/queryAutocompleteResponse'; import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData'; import { DataSource, @@ -8,7 +11,6 @@ import { } from 'types/common/queryBuilder'; import { - DataType, GraphTitle, KeyOperationTableHeader, MetricsType, @@ -22,21 +24,21 @@ export const topOperationQueries = ({ }: TopOperationQueryFactoryProps): QueryBuilderData => { const latencyAutoCompleteData: BaseAutocompleteData = { key: WidgetKeys.Signoz_latency_bucket, - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, type: '', }; const errorRateAutoCompleteData: BaseAutocompleteData = { key: WidgetKeys.SignozCallsTotal, - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, type: '', }; const numOfCallAutoCompleteData: BaseAutocompleteData = { key: WidgetKeys.SignozLatencyCount, - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, type: '', }; @@ -46,7 +48,7 @@ export const topOperationQueries = ({ id: '', key: { key: WidgetKeys.Service_name, - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, type: MetricsType.Resource, }, @@ -59,7 +61,7 @@ export const topOperationQueries = ({ { id: '', key: { - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, key: WidgetKeys.Service_name, type: MetricsType.Resource, @@ -70,7 +72,7 @@ export const topOperationQueries = ({ { id: '', key: { - dataType: DataType.INT64, + dataType: DataTypes.Int64, isColumn: false, key: WidgetKeys.StatusCode, type: MetricsType.Tag, @@ -84,7 +86,7 @@ export const topOperationQueries = ({ const groupBy: BaseAutocompleteData[] = [ { - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, key: WidgetKeys.Operation, type: MetricsType.Tag, diff --git a/frontend/src/container/MetricsApplication/constant.ts b/frontend/src/container/MetricsApplication/constant.ts index 15055c7aa6..c731e925c8 100644 --- a/frontend/src/container/MetricsApplication/constant.ts +++ b/frontend/src/container/MetricsApplication/constant.ts @@ -41,13 +41,6 @@ export enum KeyOperationTableHeader { OPERATION_PR_SECOND = 'Op/s', } -export enum DataType { - STRING = 'string', - FLOAT64 = 'float64', - INT64 = 'int64', - BOOL = 'bool', -} - export enum MetricsType { Tag = 'tag', Resource = 'resource', diff --git a/frontend/src/container/OnboardingContainer/LogsManagement/common/LogsConnectionStatus/LogsConnectionStatus.tsx b/frontend/src/container/OnboardingContainer/LogsManagement/common/LogsConnectionStatus/LogsConnectionStatus.tsx index 40750b6abb..9fd9a2958e 100644 --- a/frontend/src/container/OnboardingContainer/LogsManagement/common/LogsConnectionStatus/LogsConnectionStatus.tsx +++ b/frontend/src/container/OnboardingContainer/LogsManagement/common/LogsConnectionStatus/LogsConnectionStatus.tsx @@ -12,6 +12,7 @@ import { useEffect, useState } from 'react'; import { SuccessResponse } from 'types/api'; import { ILog } from 'types/api/logs/log'; import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange'; +import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { Query } from 'types/api/queryBuilder/queryBuilderData'; import { EQueryType } from 'types/common/dashboard'; import { DataSource } from 'types/common/queryBuilder'; @@ -43,7 +44,7 @@ export default function LogsConnectionStatus({ aggregateOperator: 'noop', aggregateAttribute: { id: '------false', - dataType: '', + dataType: DataTypes.EMPTY, key: '', isColumn: false, type: '', diff --git a/frontend/src/container/QueryBuilder/filters/HavingFilter/__tests__/utils.test.tsx b/frontend/src/container/QueryBuilder/filters/HavingFilter/__tests__/utils.test.tsx index 5567947f44..5732b22712 100644 --- a/frontend/src/container/QueryBuilder/filters/HavingFilter/__tests__/utils.test.tsx +++ b/frontend/src/container/QueryBuilder/filters/HavingFilter/__tests__/utils.test.tsx @@ -6,6 +6,7 @@ import { initialQueryBuilderFormValuesMap, } from 'constants/queryBuilder'; import { transformFromStringToHaving } from 'lib/query/transformQueryBuilderData'; +import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse'; // ** Types import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; @@ -19,7 +20,7 @@ const valueWithAttributeAndOperator: IBuilderQuery = { isColumn: false, key: 'bytes', type: 'tag', - dataType: 'float64', + dataType: DataTypes.Float64, }, }; diff --git a/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/index.tsx b/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/index.tsx index 243441fa9b..3b78eae7bd 100644 --- a/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/index.tsx +++ b/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/index.tsx @@ -1,4 +1,6 @@ import { Select, Spin, Tag, Tooltip } from 'antd'; +import { OPERATORS } from 'constants/queryBuilder'; +import { getDataTypes } from 'container/LogDetailedView/utils'; import { useAutoComplete, WhereClauseConfig, @@ -12,7 +14,10 @@ import { useEffect, useMemo, } from 'react'; -import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; +import { + BaseAutocompleteData, + DataTypes, +} from 'types/api/queryBuilder/queryAutocompleteResponse'; import { IBuilderQuery, TagFilter, @@ -80,15 +85,22 @@ function QueryBuilderSearch({ handleSearch(value); }; + const isDisabled = + !!searchValue || + OPERATORS.HAS === tagOperator || + OPERATORS.NHAS === tagOperator; + return ( tagEditHandler(value)} + onClick={(): void => { + if (!isDisabled) tagEditHandler(value); + }} > {chipValue} @@ -119,6 +131,14 @@ function QueryBuilderSearch({ [query.dataSource], ); + const fetchValueDataType = (value: unknown, operator: string): DataTypes => { + if (operator === OPERATORS.HAS || operator === OPERATORS.NHAS) { + return getDataTypes([value]); + } + + return DataTypes.EMPTY; + }; + const queryTags = useMemo(() => { if (!query.aggregateAttribute.key && isMetricsDataSource) return []; return tags; @@ -129,26 +149,35 @@ function QueryBuilderSearch({ const initialSourceKeys = query.filters.items?.map( (item) => item.key as BaseAutocompleteData, ); - initialTagFilters.items = tags.map((tag) => { + + initialTagFilters.items = tags.map((tag, index) => { + const isJsonTrue = query.filters?.items[index]?.key?.isJSON; + const { tagKey, tagOperator, tagValue } = getTagToken(tag); + const filterAttribute = [...initialSourceKeys, ...sourceKeys].find( (key) => key.key === getRemovePrefixFromKey(tagKey), ); + + const computedTagValue = + tagValue && Array.isArray(tagValue) && tagValue[tagValue.length - 1] === '' + ? tagValue?.slice(0, -1) + : tagValue ?? ''; + return { id: uuid().slice(0, 8), key: filterAttribute ?? { key: tagKey, - dataType: '', + dataType: fetchValueDataType(computedTagValue, tagOperator), type: '', isColumn: false, + isJSON: isJsonTrue, }, op: getOperatorValue(tagOperator), - value: - tagValue[tagValue.length - 1] === '' - ? tagValue?.slice(0, -1) - : tagValue ?? '', + value: computedTagValue, }; }); + onChange(initialTagFilters); /* eslint-disable react-hooks/exhaustive-deps */ }, [sourceKeys]); diff --git a/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/utils.ts b/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/utils.ts index acac3b1072..1859254fc4 100644 --- a/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/utils.ts +++ b/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/utils.ts @@ -3,7 +3,8 @@ import { parse } from 'papaparse'; import { orderByValueDelimiter } from '../OrderByFilter/utils'; -export const tagRegexp = /([a-zA-Z0-9_.:@$()\-/\\]+)\s*(!=|=|<=|<|>=|>|IN|NOT_IN|LIKE|NOT_LIKE|REGEX|NOT_REGEX|EXISTS|NOT_EXISTS|CONTAINS|NOT_CONTAINS|-->|--!>)\s*([\s\S]*)/g; +// eslint-disable-next-line no-useless-escape +export const tagRegexp = /^\s*(.*?)\s*(IN|NOT_IN|LIKE|NOT_LIKE|REGEX|NOT_REGEX|=|!=|EXISTS|NOT_EXISTS|CONTAINS|NOT_CONTAINS|>=|>|<=|<|HAS|NHAS)\s*(.*)$/g; export function isInNInOperator(value: string): boolean { return value === OPERATORS.IN || value === OPERATORS.NIN; @@ -57,6 +58,10 @@ export function getOperatorValue(op: string): string { return 'nin'; case OPERATORS.REGEX: return 'regex'; + case OPERATORS.HAS: + return 'has'; + case OPERATORS.NHAS: + return 'nhas'; case OPERATORS.NREGEX: return 'nregex'; case 'LIKE': @@ -98,6 +103,10 @@ export function getOperatorFromValue(op: string): string { return 'CONTAINS'; case 'ncontains': return 'NOT_CONTAINS'; + case 'has': + return OPERATORS.HAS; + case 'nhas': + return OPERATORS.NHAS; default: return op; } diff --git a/frontend/src/container/ServiceApplication/ServiceMetrics/ServiceMetricsQuery.ts b/frontend/src/container/ServiceApplication/ServiceMetrics/ServiceMetricsQuery.ts index f0eff8beda..46f94acd87 100644 --- a/frontend/src/container/ServiceApplication/ServiceMetrics/ServiceMetricsQuery.ts +++ b/frontend/src/container/ServiceApplication/ServiceMetrics/ServiceMetricsQuery.ts @@ -1,13 +1,15 @@ import { ServiceDataProps } from 'api/metrics/getTopLevelOperations'; import { OPERATORS } from 'constants/queryBuilder'; import { - DataType, KeyOperationTableHeader, MetricsType, WidgetKeys, } from 'container/MetricsApplication/constant'; import { getQueryBuilderQuerieswithFormula } from 'container/MetricsApplication/MetricsPageQueries/MetricsPageQueriesFactory'; -import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; +import { + BaseAutocompleteData, + DataTypes, +} from 'types/api/queryBuilder/queryAutocompleteResponse'; import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData'; import { DataSource, @@ -19,21 +21,21 @@ export const serviceMetricsQuery = ( topLevelOperation: [keyof ServiceDataProps, string[]], ): QueryBuilderData => { const p99AutoCompleteData: BaseAutocompleteData = { - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, key: WidgetKeys.Signoz_latency_bucket, type: '', }; const errorRateAutoCompleteData: BaseAutocompleteData = { - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, key: WidgetKeys.SignozCallsTotal, type: '', }; const operationPrSecondAutoCompleteData: BaseAutocompleteData = { - dataType: DataType.FLOAT64, + dataType: DataTypes.Float64, isColumn: true, key: WidgetKeys.SignozCallsTotal, type: '', @@ -50,7 +52,7 @@ export const serviceMetricsQuery = ( { id: '', key: { - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, key: WidgetKeys.Service_name, type: MetricsType.Resource, @@ -61,7 +63,7 @@ export const serviceMetricsQuery = ( { id: '', key: { - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, key: WidgetKeys.Operation, type: MetricsType.Tag, @@ -75,7 +77,7 @@ export const serviceMetricsQuery = ( { id: '', key: { - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, key: WidgetKeys.Service_name, type: MetricsType.Resource, @@ -86,7 +88,7 @@ export const serviceMetricsQuery = ( { id: '', key: { - dataType: DataType.INT64, + dataType: DataTypes.Int64, isColumn: false, key: WidgetKeys.StatusCode, type: MetricsType.Tag, @@ -97,7 +99,7 @@ export const serviceMetricsQuery = ( { id: '', key: { - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, key: WidgetKeys.Operation, type: MetricsType.Tag, @@ -111,7 +113,7 @@ export const serviceMetricsQuery = ( { id: '', key: { - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, key: WidgetKeys.Service_name, type: MetricsType.Resource, @@ -122,7 +124,7 @@ export const serviceMetricsQuery = ( { id: '', key: { - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, key: WidgetKeys.Operation, type: MetricsType.Tag, @@ -136,7 +138,7 @@ export const serviceMetricsQuery = ( { id: '', key: { - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, key: WidgetKeys.Service_name, type: MetricsType.Resource, @@ -147,7 +149,7 @@ export const serviceMetricsQuery = ( { id: '', key: { - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, key: WidgetKeys.Operation, type: MetricsType.Tag, @@ -185,7 +187,7 @@ export const serviceMetricsQuery = ( const groupBy: BaseAutocompleteData[] = [ { - dataType: DataType.STRING, + dataType: DataTypes.String, isColumn: false, key: WidgetKeys.Service_name, type: MetricsType.Tag, diff --git a/frontend/src/hooks/logs/types.ts b/frontend/src/hooks/logs/types.ts index 3776ba606a..3dbcbb61f1 100644 --- a/frontend/src/hooks/logs/types.ts +++ b/frontend/src/hooks/logs/types.ts @@ -1,5 +1,6 @@ import { MouseEventHandler } from 'react'; import { ILog } from 'types/api/logs/log'; +import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse'; export type LogTimeRange = { start: number; @@ -20,5 +21,11 @@ export type UseActiveLog = { activeLog: ILog | null; onSetActiveLog: (log: ILog) => void; onClearActiveLog: () => void; - onAddToQuery: (fieldKey: string, fieldValue: string, operator: string) => void; + onAddToQuery: ( + fieldKey: string, + fieldValue: string, + operator: string, + isJSON?: boolean, + dataType?: DataTypes, + ) => void; }; diff --git a/frontend/src/hooks/logs/useActiveLog.ts b/frontend/src/hooks/logs/useActiveLog.ts index fae1b6f063..8dbd58976b 100644 --- a/frontend/src/hooks/logs/useActiveLog.ts +++ b/frontend/src/hooks/logs/useActiveLog.ts @@ -1,4 +1,5 @@ import { getAggregateKeys } from 'api/queryBuilder/getAttributeKeys'; +import { SOMETHING_WENT_WRONG } from 'constants/api'; import { QueryBuilderKeys } from 'constants/queryBuilder'; import ROUTES from 'constants/routes'; import { getOperatorValue } from 'container/QueryBuilder/filters/QueryBuilderSearch/utils'; @@ -7,14 +8,16 @@ import { useNotifications } from 'hooks/useNotifications'; import { getGeneratedFilterQueryString } from 'lib/getGeneratedFilterQueryString'; import { chooseAutocompleteFromCustomValue } from 'lib/newQueryBuilder/chooseAutocompleteFromCustomValue'; import { useCallback, useMemo, useState } from 'react'; -import { useTranslation } from 'react-i18next'; import { useQueryClient } from 'react-query'; import { useDispatch, useSelector } from 'react-redux'; import { useHistory, useLocation } from 'react-router-dom'; import { AppState } from 'store/reducers'; import { SET_DETAILED_LOG_DATA } from 'types/actions/logs'; import { ILog } from 'types/api/logs/log'; -import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; +import { + BaseAutocompleteData, + DataTypes, +} from 'types/api/queryBuilder/queryAutocompleteResponse'; import { Query } from 'types/api/queryBuilder/queryBuilderData'; import { ILogsReducer } from 'types/reducer/logs'; import { v4 as uuid } from 'uuid'; @@ -33,8 +36,6 @@ export const useActiveLog = (): UseActiveLog => { const { currentQuery, redirectWithQueryBuilderData } = useQueryBuilder(); const { notifications } = useNotifications(); - const { t } = useTranslation('common'); - const isLogsPage = useMemo(() => pathname === ROUTES.LOGS, [pathname]); const [activeLog, setActiveLog] = useState(null); @@ -67,6 +68,8 @@ export const useActiveLog = (): UseActiveLog => { fieldKey: string, fieldValue: string, operator: string, + isJSON?: boolean, + dataType?: DataTypes, ): Promise => { try { const keysAutocompleteResponse = await queryClient.fetchQuery( @@ -87,6 +90,8 @@ export const useActiveLog = (): UseActiveLog => { const existAutocompleteKey = chooseAutocompleteFromCustomValue( keysAutocomplete, fieldKey, + isJSON, + dataType, ); const currentOperator = getOperatorValue(operator); @@ -100,9 +105,7 @@ export const useActiveLog = (): UseActiveLog => { filters: { ...item.filters, items: [ - ...item.filters.items.filter( - (item) => item.key?.id !== existAutocompleteKey.id, - ), + ...item.filters.items, { id: uuid(), key: existAutocompleteKey, @@ -117,10 +120,10 @@ export const useActiveLog = (): UseActiveLog => { redirectWithQueryBuilderData(nextQuery); } catch { - notifications.error({ message: t('something_went_wrong') }); + notifications.error({ message: SOMETHING_WENT_WRONG }); } }, - [currentQuery, notifications, queryClient, redirectWithQueryBuilderData, t], + [currentQuery, notifications, queryClient, redirectWithQueryBuilderData], ); const onAddToQueryLogs = useCallback( diff --git a/frontend/src/hooks/queryBuilder/useFetchKeysAndValues.ts b/frontend/src/hooks/queryBuilder/useFetchKeysAndValues.ts index 70226b650d..4a61140ccc 100644 --- a/frontend/src/hooks/queryBuilder/useFetchKeysAndValues.ts +++ b/frontend/src/hooks/queryBuilder/useFetchKeysAndValues.ts @@ -9,7 +9,10 @@ import useDebounceValue from 'hooks/useDebounce'; import { isEqual, uniqWith } from 'lodash-es'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useDebounce } from 'react-use'; -import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; +import { + BaseAutocompleteData, + DataTypes, +} from 'types/api/queryBuilder/queryAutocompleteResponse'; import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; import { DataSource } from 'types/common/queryBuilder'; @@ -109,7 +112,7 @@ export const useFetchKeysAndValues = ( dataSource: query.dataSource, aggregateAttribute: query.aggregateAttribute.key, attributeKey: filterAttributeKey?.key ?? tagKey, - filterAttributeKeyDataType: filterAttributeKey?.dataType ?? '', + filterAttributeKeyDataType: filterAttributeKey?.dataType ?? DataTypes.EMPTY, tagType: filterAttributeKey?.type ?? '', searchText: isInNInOperator(tagOperator) ? tagValue[tagValue.length - 1]?.toString() ?? '' // last element of tagvalue will be always user search value diff --git a/frontend/src/hooks/queryBuilder/useOperatorType.ts b/frontend/src/hooks/queryBuilder/useOperatorType.ts index 45049af206..94de55df92 100644 --- a/frontend/src/hooks/queryBuilder/useOperatorType.ts +++ b/frontend/src/hooks/queryBuilder/useOperatorType.ts @@ -23,6 +23,8 @@ const operatorTypeMapper: Record = { [OPERATORS.NOT_CONTAINS]: 'SINGLE_VALUE', [OPERATORS['=']]: 'SINGLE_VALUE', [OPERATORS['!=']]: 'SINGLE_VALUE', + [OPERATORS.HAS]: 'SINGLE_VALUE', + [OPERATORS.NHAS]: 'SINGLE_VALUE', }; export const useOperatorType = (operator: string): OperatorType => diff --git a/frontend/src/hooks/queryBuilder/useOperators.ts b/frontend/src/hooks/queryBuilder/useOperators.ts index 141213d4ce..63f4a9222a 100644 --- a/frontend/src/hooks/queryBuilder/useOperators.ts +++ b/frontend/src/hooks/queryBuilder/useOperators.ts @@ -17,6 +17,8 @@ export const useOperators = ( useMemo(() => { const currentKey = keys?.find((el) => el.key === getRemovePrefixFromKey(key)); return currentKey?.dataType - ? QUERY_BUILDER_OPERATORS_BY_TYPES[currentKey.dataType] + ? QUERY_BUILDER_OPERATORS_BY_TYPES[ + currentKey.dataType as keyof typeof QUERY_BUILDER_OPERATORS_BY_TYPES + ] : QUERY_BUILDER_OPERATORS_BY_TYPES.universal; }, [keys, key]); diff --git a/frontend/src/hooks/useResourceAttribute/utils.ts b/frontend/src/hooks/useResourceAttribute/utils.ts index 75187ab060..8926621e32 100644 --- a/frontend/src/hooks/useResourceAttribute/utils.ts +++ b/frontend/src/hooks/useResourceAttribute/utils.ts @@ -4,7 +4,7 @@ import { } from 'api/metrics/getResourceAttributes'; import { OperatorConversions } from 'constants/resourceAttributes'; import ROUTES from 'constants/routes'; -import { DataType, MetricsType } from 'container/MetricsApplication/constant'; +import { MetricsType } from 'container/MetricsApplication/constant'; import { IOption, IResourceAttribute, @@ -12,6 +12,7 @@ import { } from 'hooks/useResourceAttribute/types'; import { decode } from 'js-base64'; import history from 'lib/history'; +import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData'; import { OperatorValues, Tags } from 'types/reducer/trace'; import { v4 as uuid } from 'uuid'; @@ -72,7 +73,7 @@ export const resourceAttributesToTagFilterItems = ( op: e.Operator, value: e.StringValues, key: { - dataType: DataType.STRING, + dataType: DataTypes.String, type: MetricsType.Resource, isColumn: false, key: e.Key, @@ -82,7 +83,12 @@ export const resourceAttributesToTagFilterItems = ( return queries.map((res) => ({ id: `${res.id}`, - key: { key: res.tagKey, isColumn: false, type: '', dataType: '' }, + key: { + key: res.tagKey, + isColumn: false, + type: '', + dataType: DataTypes.EMPTY, + }, op: `${res.operator}`, value: `${res.tagValue}`.split(','), })); diff --git a/frontend/src/lib/newQueryBuilder/chooseAutocompleteFromCustomValue.ts b/frontend/src/lib/newQueryBuilder/chooseAutocompleteFromCustomValue.ts index 3b1bad0abe..b65c7c3ca3 100644 --- a/frontend/src/lib/newQueryBuilder/chooseAutocompleteFromCustomValue.ts +++ b/frontend/src/lib/newQueryBuilder/chooseAutocompleteFromCustomValue.ts @@ -1,16 +1,26 @@ import { initialAutocompleteData } from 'constants/queryBuilder'; -import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; +import { + BaseAutocompleteData, + DataTypes, +} from 'types/api/queryBuilder/queryAutocompleteResponse'; export const chooseAutocompleteFromCustomValue = ( sourceList: BaseAutocompleteData[], value: string, + isJSON?: boolean, + dataType?: DataTypes, ): BaseAutocompleteData => { const firstBaseAutoCompleteValue = sourceList.find( (sourceAutoComplete) => value === sourceAutoComplete.key, ); if (!firstBaseAutoCompleteValue) { - return { ...initialAutocompleteData, key: value, dataType: 'string' }; + return { + ...initialAutocompleteData, + key: value, + dataType: dataType || DataTypes.EMPTY, + isJSON, + }; } return firstBaseAutoCompleteValue; diff --git a/frontend/src/lib/newQueryBuilder/getPaginationQueryData.ts b/frontend/src/lib/newQueryBuilder/getPaginationQueryData.ts index aa03c69a08..140808cdc1 100644 --- a/frontend/src/lib/newQueryBuilder/getPaginationQueryData.ts +++ b/frontend/src/lib/newQueryBuilder/getPaginationQueryData.ts @@ -1,4 +1,5 @@ import { FILTERS } from 'container/QueryBuilder/filters/OrderByFilter/config'; +import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { IBuilderQuery, OrderByPayload, @@ -47,7 +48,7 @@ export const getPaginationQueryData: SetupPaginationQueryData = ({ key: { key: 'id', type: '', - dataType: 'string', + dataType: DataTypes.String, isColumn: true, }, op: orderByTimestamp.order === FILTERS.ASC ? '>' : '<', diff --git a/frontend/src/types/api/queryBuilder/queryAutocompleteResponse.ts b/frontend/src/types/api/queryBuilder/queryAutocompleteResponse.ts index 24e062d9ab..67503761ca 100644 --- a/frontend/src/types/api/queryBuilder/queryAutocompleteResponse.ts +++ b/frontend/src/types/api/queryBuilder/queryAutocompleteResponse.ts @@ -1,15 +1,26 @@ -export type LocalDataType = 'number' | 'string' | 'bool'; +export enum DataTypes { + Int64 = 'int64', + String = 'string', + Float64 = 'float64', + bool = 'bool', + ArrayFloat64 = 'array(float64)', + ArrayInt64 = 'array(int64)', + ArrayString = 'array(string)', + ArrayBool = 'array(bool)', + EMPTY = '', +} -export type DataType = 'int64' | 'float64' | 'string' | 'bool' | ''; +export type LocalDataType = 'number' | 'string' | 'bool'; export type AutocompleteType = 'tag' | 'resource' | ''; export interface BaseAutocompleteData { id?: string; - dataType: DataType; + dataType: DataTypes; isColumn: boolean; key: string; type: AutocompleteType | string | null; + isJSON?: boolean; } export interface IQueryAutocompleteResponse { From e3f17b5420ee002d7f0c1ab713749cc790318610 Mon Sep 17 00:00:00 2001 From: Palash Gupta Date: Fri, 15 Sep 2023 10:38:07 +0530 Subject: [PATCH 3/5] chore: tree is expanded by default (#3563) --- frontend/src/container/LogDetailedView/TableView.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/src/container/LogDetailedView/TableView.tsx b/frontend/src/container/LogDetailedView/TableView.tsx index 5c76fa506e..28910afbde 100644 --- a/frontend/src/container/LogDetailedView/TableView.tsx +++ b/frontend/src/container/LogDetailedView/TableView.tsx @@ -167,7 +167,9 @@ function TableView({ if (record.field === 'body') { const parsedBody = recursiveParseJSON(field); if (!isEmpty(parsedBody)) { - return ; + return ( + + ); } } From 231c2fd28179e19b142bb7b9ab06ecc0395f7315 Mon Sep 17 00:00:00 2001 From: Rajat Dabade Date: Fri, 15 Sep 2023 12:56:59 +0530 Subject: [PATCH 4/5] [Fix]: show dashboard according to Id (#3564) * fix: show dashboard according to id * chore: removed log --- frontend/src/pages/NewDashboard/index.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/frontend/src/pages/NewDashboard/index.tsx b/frontend/src/pages/NewDashboard/index.tsx index 6d64ca500f..98ed3d394f 100644 --- a/frontend/src/pages/NewDashboard/index.tsx +++ b/frontend/src/pages/NewDashboard/index.tsx @@ -22,12 +22,10 @@ function NewDashboardPage({ getDashboard }: NewDashboardProps): JSX.Element { const { dashboardId } = useParams(); useEffect(() => { - if (dashboards.length !== 1) { - getDashboard({ - uuid: dashboardId, - }); - } - }, [getDashboard, dashboardId, dashboards.length]); + getDashboard({ + uuid: dashboardId, + }); + }, [getDashboard, dashboardId]); if ( error && From cf1b0c2f24e5941ca50bb5d44ba39a9d6285c4a9 Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Fri, 15 Sep 2023 13:33:55 +0530 Subject: [PATCH 5/5] =?UTF-8?q?chore(release):=20=F0=9F=93=8C=20pin=20vers?= =?UTF-8?q?ion:=20SigNoz=200.29.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Prashant Shahi --- deploy/docker-swarm/clickhouse-setup/docker-compose.yaml | 4 ++-- deploy/docker/clickhouse-setup/docker-compose.yaml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml b/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml index 20bc9cc1fa..964411f6e6 100644 --- a/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml +++ b/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml @@ -144,7 +144,7 @@ services: condition: on-failure query-service: - image: signoz/query-service:0.29.0 + image: signoz/query-service:0.29.1 command: [ "-config=/root/config/prometheus.yml", @@ -184,7 +184,7 @@ services: <<: *clickhouse-depend frontend: - image: signoz/frontend:0.29.0 + image: signoz/frontend:0.29.1 deploy: restart_policy: condition: on-failure diff --git a/deploy/docker/clickhouse-setup/docker-compose.yaml b/deploy/docker/clickhouse-setup/docker-compose.yaml index 1a543db348..dbe8d4326d 100644 --- a/deploy/docker/clickhouse-setup/docker-compose.yaml +++ b/deploy/docker/clickhouse-setup/docker-compose.yaml @@ -162,7 +162,7 @@ services: # Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh` & `./CONTRIBUTING.md` query-service: - image: signoz/query-service:${DOCKER_TAG:-0.29.0} + image: signoz/query-service:${DOCKER_TAG:-0.29.1} container_name: signoz-query-service command: [ @@ -201,7 +201,7 @@ services: <<: *clickhouse-depend frontend: - image: signoz/frontend:${DOCKER_TAG:-0.29.0} + image: signoz/frontend:${DOCKER_TAG:-0.29.1} container_name: signoz-frontend restart: on-failure depends_on: