mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-08 16:18:59 +08:00
[Refactor]: Added tag and datatype in options for query builder (#3555)
Co-authored-by: Vishal Sharma <makeavish786@gmail.com> Co-authored-by: Palash Gupta <palashgdev@gmail.com>
This commit is contained in:
parent
581bd07b35
commit
6b2f03d43f
@ -25,7 +25,9 @@ import { ExtendedSelectOption } from 'types/common/select';
|
|||||||
import { popupContainer } from 'utils/selectPopupContainer';
|
import { popupContainer } from 'utils/selectPopupContainer';
|
||||||
import { transformToUpperCase } from 'utils/transformToUpperCase';
|
import { transformToUpperCase } from 'utils/transformToUpperCase';
|
||||||
|
|
||||||
|
import { removePrefix } from '../GroupByFilter/utils';
|
||||||
import { selectStyle } from '../QueryBuilderSearch/config';
|
import { selectStyle } from '../QueryBuilderSearch/config';
|
||||||
|
import OptionRenderer from '../QueryBuilderSearch/OptionRenderer';
|
||||||
// ** Types
|
// ** Types
|
||||||
import { AgregatorFilterProps } from './AggregatorFilter.intefaces';
|
import { AgregatorFilterProps } from './AggregatorFilter.intefaces';
|
||||||
|
|
||||||
@ -64,11 +66,23 @@ export const AggregatorFilter = memo(function AggregatorFilter({
|
|||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
const options: ExtendedSelectOption[] =
|
const options: ExtendedSelectOption[] =
|
||||||
data?.payload?.attributeKeys?.map(({ id: _, ...item }) => ({
|
data?.payload?.attributeKeys?.map(({ id: _, ...item }) => ({
|
||||||
label: transformStringWithPrefix({
|
label: (
|
||||||
str: item.key,
|
<OptionRenderer
|
||||||
prefix: item.type || '',
|
label={transformStringWithPrefix({
|
||||||
condition: !item.isColumn,
|
str: item.key,
|
||||||
}),
|
prefix: item.type || '',
|
||||||
|
condition: !item.isColumn,
|
||||||
|
})}
|
||||||
|
value={removePrefix(
|
||||||
|
transformStringWithPrefix({
|
||||||
|
str: item.key,
|
||||||
|
prefix: item.type || '',
|
||||||
|
condition: !item.isColumn,
|
||||||
|
}),
|
||||||
|
)}
|
||||||
|
dataType={item.dataType}
|
||||||
|
/>
|
||||||
|
),
|
||||||
value: `${item.key}${selectValueDivider}${createIdFromObjectFields(
|
value: `${item.key}${selectValueDivider}${createIdFromObjectFields(
|
||||||
item,
|
item,
|
||||||
baseAutoCompleteIdKeysOrder,
|
baseAutoCompleteIdKeysOrder,
|
||||||
@ -165,18 +179,19 @@ export const AggregatorFilter = memo(function AggregatorFilter({
|
|||||||
[getAttributesData, handleChangeCustomValue, onChange],
|
[getAttributesData, handleChangeCustomValue, onChange],
|
||||||
);
|
);
|
||||||
|
|
||||||
const value = transformStringWithPrefix({
|
const value = removePrefix(
|
||||||
str: query.aggregateAttribute.key,
|
transformStringWithPrefix({
|
||||||
prefix: query.aggregateAttribute.type || '',
|
str: query.aggregateAttribute.key,
|
||||||
condition: !query.aggregateAttribute.isColumn,
|
prefix: query.aggregateAttribute.type || '',
|
||||||
});
|
condition: !query.aggregateAttribute.isColumn,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AutoComplete
|
<AutoComplete
|
||||||
getPopupContainer={popupContainer}
|
getPopupContainer={popupContainer}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
style={selectStyle}
|
style={selectStyle}
|
||||||
showArrow={false}
|
|
||||||
filterOption={false}
|
filterOption={false}
|
||||||
onSearch={handleSearchText}
|
onSearch={handleSearchText}
|
||||||
notFoundContent={isFetching ? <Spin size="small" /> : null}
|
notFoundContent={isFetching ? <Spin size="small" /> : null}
|
||||||
|
@ -14,14 +14,16 @@ import { chooseAutocompleteFromCustomValue } from 'lib/newQueryBuilder/chooseAut
|
|||||||
// ** Helpers
|
// ** Helpers
|
||||||
import { transformStringWithPrefix } from 'lib/query/transformStringWithPrefix';
|
import { transformStringWithPrefix } from 'lib/query/transformStringWithPrefix';
|
||||||
import { isEqual, uniqWith } from 'lodash-es';
|
import { isEqual, uniqWith } from 'lodash-es';
|
||||||
import { memo, useCallback, useEffect, useState } from 'react';
|
import { memo, ReactNode, useCallback, useEffect, useState } from 'react';
|
||||||
import { useQueryClient } from 'react-query';
|
import { useQueryClient } from 'react-query';
|
||||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||||
import { SelectOption } from 'types/common/select';
|
import { SelectOption } from 'types/common/select';
|
||||||
import { popupContainer } from 'utils/selectPopupContainer';
|
import { popupContainer } from 'utils/selectPopupContainer';
|
||||||
|
|
||||||
import { selectStyle } from '../QueryBuilderSearch/config';
|
import { selectStyle } from '../QueryBuilderSearch/config';
|
||||||
|
import OptionRenderer from '../QueryBuilderSearch/OptionRenderer';
|
||||||
import { GroupByFilterProps } from './GroupByFilter.interfaces';
|
import { GroupByFilterProps } from './GroupByFilter.interfaces';
|
||||||
|
import { removePrefix } from './utils';
|
||||||
|
|
||||||
export const GroupByFilter = memo(function GroupByFilter({
|
export const GroupByFilter = memo(function GroupByFilter({
|
||||||
query,
|
query,
|
||||||
@ -30,9 +32,9 @@ export const GroupByFilter = memo(function GroupByFilter({
|
|||||||
}: GroupByFilterProps): JSX.Element {
|
}: GroupByFilterProps): JSX.Element {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const [searchText, setSearchText] = useState<string>('');
|
const [searchText, setSearchText] = useState<string>('');
|
||||||
const [optionsData, setOptionsData] = useState<SelectOption<string, string>[]>(
|
const [optionsData, setOptionsData] = useState<
|
||||||
[],
|
SelectOption<string, ReactNode>[]
|
||||||
);
|
>([]);
|
||||||
const [localValues, setLocalValues] = useState<SelectOption<string, string>[]>(
|
const [localValues, setLocalValues] = useState<SelectOption<string, string>[]>(
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
@ -61,13 +63,26 @@ export const GroupByFilter = memo(function GroupByFilter({
|
|||||||
(attrKey) => !keys.includes(attrKey.key),
|
(attrKey) => !keys.includes(attrKey.key),
|
||||||
) || [];
|
) || [];
|
||||||
|
|
||||||
const options: SelectOption<string, string>[] =
|
const options: SelectOption<string, ReactNode>[] =
|
||||||
filteredOptions.map((item) => ({
|
filteredOptions.map((item) => ({
|
||||||
label: transformStringWithPrefix({
|
label: (
|
||||||
str: item.key,
|
<OptionRenderer
|
||||||
prefix: item.type || '',
|
key={item.key}
|
||||||
condition: !item.isColumn,
|
label={transformStringWithPrefix({
|
||||||
}),
|
str: item.key,
|
||||||
|
prefix: item.type || '',
|
||||||
|
condition: !item.isColumn,
|
||||||
|
})}
|
||||||
|
value={removePrefix(
|
||||||
|
transformStringWithPrefix({
|
||||||
|
str: item.key,
|
||||||
|
prefix: item.type || '',
|
||||||
|
condition: !item.isColumn,
|
||||||
|
}),
|
||||||
|
)}
|
||||||
|
dataType={item.dataType || ''}
|
||||||
|
/>
|
||||||
|
),
|
||||||
value: `${transformStringWithPrefix({
|
value: `${transformStringWithPrefix({
|
||||||
str: item.key,
|
str: item.key,
|
||||||
prefix: item.type || '',
|
prefix: item.type || '',
|
||||||
@ -152,11 +167,13 @@ export const GroupByFilter = memo(function GroupByFilter({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const currentValues: SelectOption<string, string>[] = query.groupBy.map(
|
const currentValues: SelectOption<string, string>[] = query.groupBy.map(
|
||||||
(item) => ({
|
(item) => ({
|
||||||
label: `${transformStringWithPrefix({
|
label: `${removePrefix(
|
||||||
str: item.key,
|
transformStringWithPrefix({
|
||||||
prefix: item.type || '',
|
str: item.key,
|
||||||
condition: !item.isColumn,
|
prefix: item.type || '',
|
||||||
})}`,
|
condition: !item.isColumn,
|
||||||
|
}),
|
||||||
|
)}`,
|
||||||
value: `${transformStringWithPrefix({
|
value: `${transformStringWithPrefix({
|
||||||
str: item.key,
|
str: item.key,
|
||||||
prefix: item.type || '',
|
prefix: item.type || '',
|
||||||
@ -176,7 +193,6 @@ export const GroupByFilter = memo(function GroupByFilter({
|
|||||||
onSearch={handleSearchKeys}
|
onSearch={handleSearchKeys}
|
||||||
showSearch
|
showSearch
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
showArrow={false}
|
|
||||||
filterOption={false}
|
filterOption={false}
|
||||||
onBlur={handleBlur}
|
onBlur={handleBlur}
|
||||||
onFocus={handleFocus}
|
onFocus={handleFocus}
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
import { MetricsType } from 'container/MetricsApplication/constant';
|
||||||
|
|
||||||
|
export function removePrefix(str: string): string {
|
||||||
|
const tagPrefix = `${MetricsType.Tag}_`;
|
||||||
|
const resourcePrefix = `${MetricsType.Resource}_`;
|
||||||
|
|
||||||
|
if (str.startsWith(tagPrefix)) {
|
||||||
|
return str.slice(tagPrefix.length);
|
||||||
|
}
|
||||||
|
if (str.startsWith(resourcePrefix)) {
|
||||||
|
return str.slice(resourcePrefix.length);
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
import {
|
||||||
|
SelectOptionContainer,
|
||||||
|
TagContainer,
|
||||||
|
TagLabel,
|
||||||
|
TagValue,
|
||||||
|
} from './style';
|
||||||
|
import { getOptionType } from './utils';
|
||||||
|
|
||||||
|
function OptionRenderer({
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
dataType,
|
||||||
|
}: OptionRendererProps): JSX.Element {
|
||||||
|
const optionType = getOptionType(label);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
{optionType ? (
|
||||||
|
<SelectOptionContainer>
|
||||||
|
<div>{value}</div>
|
||||||
|
<div>
|
||||||
|
<TagContainer>
|
||||||
|
<TagLabel>Type: </TagLabel>
|
||||||
|
<TagValue>{optionType}</TagValue>
|
||||||
|
</TagContainer>
|
||||||
|
<TagContainer>
|
||||||
|
<TagLabel>Data type: </TagLabel>
|
||||||
|
<TagValue>{dataType}</TagValue>
|
||||||
|
</TagContainer>
|
||||||
|
</div>
|
||||||
|
</SelectOptionContainer>
|
||||||
|
) : (
|
||||||
|
<span>{label}</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OptionRendererProps {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
dataType: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OptionRenderer;
|
@ -28,6 +28,7 @@ import { v4 as uuid } from 'uuid';
|
|||||||
|
|
||||||
import { selectStyle } from './config';
|
import { selectStyle } from './config';
|
||||||
import { PLACEHOLDER } from './constant';
|
import { PLACEHOLDER } from './constant';
|
||||||
|
import OptionRenderer from './OptionRenderer';
|
||||||
import { StyledCheckOutlined, TypographyText } from './style';
|
import { StyledCheckOutlined, TypographyText } from './style';
|
||||||
import {
|
import {
|
||||||
getOperatorValue,
|
getOperatorValue,
|
||||||
@ -205,7 +206,11 @@ function QueryBuilderSearch({
|
|||||||
>
|
>
|
||||||
{options.map((option) => (
|
{options.map((option) => (
|
||||||
<Select.Option key={option.label} value={option.value}>
|
<Select.Option key={option.label} value={option.value}>
|
||||||
{option.label}
|
<OptionRenderer
|
||||||
|
label={option.label}
|
||||||
|
value={option.value}
|
||||||
|
dataType={option.dataType || ''}
|
||||||
|
/>
|
||||||
{option.selected && <StyledCheckOutlined />}
|
{option.selected && <StyledCheckOutlined />}
|
||||||
</Select.Option>
|
</Select.Option>
|
||||||
))}
|
))}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { CheckOutlined } from '@ant-design/icons';
|
import { CheckOutlined } from '@ant-design/icons';
|
||||||
import { Typography } from 'antd';
|
import { Tag, Typography } from 'antd';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
export const TypographyText = styled(Typography.Text)<{
|
export const TypographyText = styled(Typography.Text)<{
|
||||||
@ -15,3 +15,27 @@ export const TypographyText = styled(Typography.Text)<{
|
|||||||
export const StyledCheckOutlined = styled(CheckOutlined)`
|
export const StyledCheckOutlined = styled(CheckOutlined)`
|
||||||
float: right;
|
float: right;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const SelectOptionContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const TagContainer = styled(Tag)`
|
||||||
|
&&& {
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
padding: 0.063rem 0.5rem;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 1.25rem;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const TagLabel = styled.span`
|
||||||
|
font-weight: 400;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const TagValue = styled.span`
|
||||||
|
text-transform: capitalize;
|
||||||
|
`;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { OPERATORS } from 'constants/queryBuilder';
|
import { OPERATORS } from 'constants/queryBuilder';
|
||||||
|
import { MetricsType } from 'container/MetricsApplication/constant';
|
||||||
import { parse } from 'papaparse';
|
import { parse } from 'papaparse';
|
||||||
|
|
||||||
import { orderByValueDelimiter } from '../OrderByFilter/utils';
|
import { orderByValueDelimiter } from '../OrderByFilter/utils';
|
||||||
@ -140,3 +141,15 @@ export function getRemoveOrderFromValue(tag: string): string {
|
|||||||
}
|
}
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getOptionType(label: string): MetricsType | undefined {
|
||||||
|
let optionType;
|
||||||
|
|
||||||
|
if (label.startsWith('tag_')) {
|
||||||
|
optionType = MetricsType.Tag;
|
||||||
|
} else if (label.startsWith('resource_')) {
|
||||||
|
optionType = MetricsType.Resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
return optionType;
|
||||||
|
}
|
||||||
|
@ -14,4 +14,5 @@ export type Option = {
|
|||||||
value: string;
|
value: string;
|
||||||
label: string;
|
label: string;
|
||||||
selected?: boolean;
|
selected?: boolean;
|
||||||
|
dataType?: string;
|
||||||
};
|
};
|
||||||
|
@ -43,6 +43,7 @@ export const useOptions = (
|
|||||||
items?.map((item) => ({
|
items?.map((item) => ({
|
||||||
label: `${getLabel(item)}`,
|
label: `${getLabel(item)}`,
|
||||||
value: item.key,
|
value: item.key,
|
||||||
|
dataType: item.dataType,
|
||||||
})),
|
})),
|
||||||
[getLabel],
|
[getLabel],
|
||||||
);
|
);
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
export type SelectOption<Value, Label extends unknown = string> = {
|
export type SelectOption<Value, Label extends unknown = string> = {
|
||||||
value: Value;
|
value: Value;
|
||||||
label: Label;
|
label: Label;
|
||||||
@ -6,7 +8,7 @@ export type SelectOption<Value, Label extends unknown = string> = {
|
|||||||
export type ExtendedSelectOption = {
|
export type ExtendedSelectOption = {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
key: string;
|
key: string;
|
||||||
label: string;
|
label: ReactNode;
|
||||||
title?: string;
|
title?: string;
|
||||||
value: string;
|
value: string;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user