Merge pull request #3565 from SigNoz/release/v0.29.1

Release/v0.29.1
This commit is contained in:
Prashant Shahi 2023-09-15 14:20:11 +05:30 committed by GitHub
commit 6aba701cca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 627 additions and 204 deletions

View File

@ -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

View File

@ -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:

View File

@ -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<AutocompleteType, AutocompleteType> = {
@ -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 = {

View File

@ -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 = [

View File

@ -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,
};

View File

@ -0,0 +1,11 @@
import styled from 'styled-components';
export const TitleWrapper = styled.span`
.hover-reveal {
visibility: hidden;
}
&:hover .hover-reveal {
visibility: visible;
}
`;

View File

@ -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 (
<TitleWrapper>
<Dropdown menu={menu} trigger={['click']}>
<SettingOutlined style={{ marginRight: 8 }} className="hover-reveal" />
</Dropdown>
{title.toString()}{' '}
{!parentIsArray && (
<span>
: <span style={{ color: orange[6] }}>{`${value}`}</span>
</span>
)}
</TitleWrapper>
);
}
export default BodyTitleRenderer;

View File

@ -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 (
<span>
{dataType && newField && logType ? (
<>
<span style={{ color: blue[4] }}>{newField} </span>
<Tag>Type: {logType}</Tag>
<Tag>Data type: {dataType}</Tag>
</>
) : (
<span style={{ color: blue[4] }}>{field}</span>
)}
</span>
);
}
export default FieldRenderer;

View File

@ -0,0 +1,20 @@
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;
}
export interface IFieldAttributes {
dataType?: string;
newField?: string;
logType?: MetricsType;
}

View File

@ -1,8 +1,7 @@
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 { Input, Space, Tooltip, Tree } from 'antd';
import { ColumnsType } from 'antd/es/table';
import Editor from 'components/Editor';
import AddToQueryHOC, {
AddToQueryHOCProps,
} from 'components/Logs/AddToQueryHOC';
@ -21,7 +20,8 @@ import { SET_DETAILED_LOG_DATA } from 'types/actions/logs';
import { ILog } from 'types/api/logs/log';
import ActionItem, { ActionItemProps } from './ActionItem';
import { flattenObject, recursiveParseJSON } from './utils';
import FieldRenderer from './FieldRenderer';
import { flattenObject, jsonToDataNodes, recursiveParseJSON } from './utils';
// Fields which should be restricted from adding it to query
const RESTRICTED_FIELDS = ['timestamp'];
@ -91,7 +91,7 @@ function TableView({
const columns: ColumnsType<DataType> = [
{
title: 'Action',
width: 30,
width: 11,
render: (fieldData: Record<string, string>): JSX.Element | null => {
const fieldKey = fieldData.field.split('.').slice(-1);
if (!RESTRICTED_FIELDS.includes(fieldKey[0])) {
@ -110,12 +110,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 = <span style={{ color: blue[4] }}>{field}</span>;
const renderedField = <FieldRenderer field={field} />;
if (record.field === 'trace_id') {
const traceId = flattenLogData[record.field];
@ -161,23 +161,14 @@ function TableView({
title: 'Value',
dataIndex: 'value',
key: 'value',
width: 80,
width: 70,
ellipsis: false,
render: (field, record): JSX.Element => {
if (record.field === 'body') {
const parsedBody = recursiveParseJSON(field);
if (!isEmpty(parsedBody)) {
return (
<Editor
value={JSON.stringify(parsedBody, null, 2).replace(/\\n/g, '\n')}
readOnly
height="70vh"
options={{
minimap: {
enabled: false,
},
}}
/>
<Tree defaultExpandAll showLine treeData={jsonToDataNodes(parsedBody)} />
);
}
}

View File

@ -0,0 +1,4 @@
export const DROPDOWN_KEY = {
FILTER_IN: 'filterIn',
FILTER_OUT: 'filterOut',
};

View File

@ -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);
});
});

View File

@ -1,34 +0,0 @@
export const recursiveParseJSON = (obj: string): Record<string, unknown> => {
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;
}, {});
}

View File

@ -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<string, unknown> => {
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<string, unknown>,
valueIsArray ? `${nodeKey}[*]` : nodeKey,
valueIsArray,
),
});
export function jsonToDataNodes(
json: Record<string, unknown>,
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: (
<BodyTitleRenderer
title={value as string}
nodeKey={nodeKey}
value={value}
parentIsArray={parentIsArray}
/>
),
children: jsonToDataNodes({}, nodeKey, valueIsArray),
};
}
if (typeof value === 'object' && value !== null) {
return computeDataNode(key, valueIsArray, value, nodeKey);
}
return {
key: uniqueId(),
title: (
<BodyTitleRenderer
title={key}
nodeKey={nodeKey}
value={value}
parentIsArray={parentIsArray}
/>
),
};
});
}
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 };
};

View File

@ -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,
},

View File

@ -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,
];

View File

@ -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,
];

View File

@ -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,
},

View File

@ -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,

View File

@ -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',

View File

@ -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: '',

View File

@ -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,
},
};

View File

@ -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 (
<Tag closable={!searchValue && closable} onClose={onCloseHandler}>
<Tooltip title={chipValue}>
<TypographyText
ellipsis
$isInNin={isInNin}
disabled={!!searchValue}
disabled={isDisabled}
$isEnabled={!!searchValue}
onClick={(): void => tagEditHandler(value)}
onClick={(): void => {
if (!isDisabled) tagEditHandler(value);
}}
>
{chipValue}
</TypographyText>
@ -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]);

View File

@ -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;
}

View File

@ -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,

View File

@ -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;
};

View File

@ -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<ILog | null>(null);
@ -67,6 +68,8 @@ export const useActiveLog = (): UseActiveLog => {
fieldKey: string,
fieldValue: string,
operator: string,
isJSON?: boolean,
dataType?: DataTypes,
): Promise<void> => {
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(

View File

@ -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

View File

@ -23,6 +23,8 @@ const operatorTypeMapper: Record<string, OperatorType> = {
[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 =>

View File

@ -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]);

View File

@ -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(','),
}));

View File

@ -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;

View File

@ -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 ? '>' : '<',

View File

@ -22,12 +22,10 @@ function NewDashboardPage({ getDashboard }: NewDashboardProps): JSX.Element {
const { dashboardId } = useParams<Params>();
useEffect(() => {
if (dashboards.length !== 1) {
getDashboard({
uuid: dashboardId,
});
}
}, [getDashboard, dashboardId, dashboards.length]);
getDashboard({
uuid: dashboardId,
});
}, [getDashboard, dashboardId]);
if (
error &&

View File

@ -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 {