diff --git a/frontend/src/container/QueryBuilder/filters/AggregatorFilter/AggregatorFilter.tsx b/frontend/src/container/QueryBuilder/filters/AggregatorFilter/AggregatorFilter.tsx index c491e55b54..f27336e96a 100644 --- a/frontend/src/container/QueryBuilder/filters/AggregatorFilter/AggregatorFilter.tsx +++ b/frontend/src/container/QueryBuilder/filters/AggregatorFilter/AggregatorFilter.tsx @@ -25,7 +25,9 @@ import { ExtendedSelectOption } from 'types/common/select'; import { popupContainer } from 'utils/selectPopupContainer'; import { transformToUpperCase } from 'utils/transformToUpperCase'; +import { removePrefix } from '../GroupByFilter/utils'; import { selectStyle } from '../QueryBuilderSearch/config'; +import OptionRenderer from '../QueryBuilderSearch/OptionRenderer'; // ** Types import { AgregatorFilterProps } from './AggregatorFilter.intefaces'; @@ -64,11 +66,23 @@ export const AggregatorFilter = memo(function AggregatorFilter({ onSuccess: (data) => { const options: ExtendedSelectOption[] = data?.payload?.attributeKeys?.map(({ id: _, ...item }) => ({ - label: transformStringWithPrefix({ - str: item.key, - prefix: item.type || '', - condition: !item.isColumn, - }), + label: ( + + ), value: `${item.key}${selectValueDivider}${createIdFromObjectFields( item, baseAutoCompleteIdKeysOrder, @@ -165,18 +179,19 @@ export const AggregatorFilter = memo(function AggregatorFilter({ [getAttributesData, handleChangeCustomValue, onChange], ); - const value = transformStringWithPrefix({ - str: query.aggregateAttribute.key, - prefix: query.aggregateAttribute.type || '', - condition: !query.aggregateAttribute.isColumn, - }); + const value = removePrefix( + transformStringWithPrefix({ + str: query.aggregateAttribute.key, + prefix: query.aggregateAttribute.type || '', + condition: !query.aggregateAttribute.isColumn, + }), + ); return ( : null} diff --git a/frontend/src/container/QueryBuilder/filters/GroupByFilter/GroupByFilter.tsx b/frontend/src/container/QueryBuilder/filters/GroupByFilter/GroupByFilter.tsx index 905684de89..386786f70c 100644 --- a/frontend/src/container/QueryBuilder/filters/GroupByFilter/GroupByFilter.tsx +++ b/frontend/src/container/QueryBuilder/filters/GroupByFilter/GroupByFilter.tsx @@ -14,14 +14,16 @@ import { chooseAutocompleteFromCustomValue } from 'lib/newQueryBuilder/chooseAut // ** Helpers import { transformStringWithPrefix } from 'lib/query/transformStringWithPrefix'; 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 { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; import { SelectOption } from 'types/common/select'; import { popupContainer } from 'utils/selectPopupContainer'; import { selectStyle } from '../QueryBuilderSearch/config'; +import OptionRenderer from '../QueryBuilderSearch/OptionRenderer'; import { GroupByFilterProps } from './GroupByFilter.interfaces'; +import { removePrefix } from './utils'; export const GroupByFilter = memo(function GroupByFilter({ query, @@ -30,9 +32,9 @@ export const GroupByFilter = memo(function GroupByFilter({ }: GroupByFilterProps): JSX.Element { const queryClient = useQueryClient(); const [searchText, setSearchText] = useState(''); - const [optionsData, setOptionsData] = useState[]>( - [], - ); + const [optionsData, setOptionsData] = useState< + SelectOption[] + >([]); const [localValues, setLocalValues] = useState[]>( [], ); @@ -61,13 +63,26 @@ export const GroupByFilter = memo(function GroupByFilter({ (attrKey) => !keys.includes(attrKey.key), ) || []; - const options: SelectOption[] = + const options: SelectOption[] = filteredOptions.map((item) => ({ - label: transformStringWithPrefix({ - str: item.key, - prefix: item.type || '', - condition: !item.isColumn, - }), + label: ( + + ), value: `${transformStringWithPrefix({ str: item.key, prefix: item.type || '', @@ -152,11 +167,13 @@ export const GroupByFilter = memo(function GroupByFilter({ useEffect(() => { const currentValues: SelectOption[] = query.groupBy.map( (item) => ({ - label: `${transformStringWithPrefix({ - str: item.key, - prefix: item.type || '', - condition: !item.isColumn, - })}`, + label: `${removePrefix( + transformStringWithPrefix({ + str: item.key, + prefix: item.type || '', + condition: !item.isColumn, + }), + )}`, value: `${transformStringWithPrefix({ str: item.key, prefix: item.type || '', @@ -176,7 +193,6 @@ export const GroupByFilter = memo(function GroupByFilter({ onSearch={handleSearchKeys} showSearch disabled={disabled} - showArrow={false} filterOption={false} onBlur={handleBlur} onFocus={handleFocus} diff --git a/frontend/src/container/QueryBuilder/filters/GroupByFilter/utils.ts b/frontend/src/container/QueryBuilder/filters/GroupByFilter/utils.ts new file mode 100644 index 0000000000..50dccec4d9 --- /dev/null +++ b/frontend/src/container/QueryBuilder/filters/GroupByFilter/utils.ts @@ -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; +} diff --git a/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/OptionRenderer.tsx b/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/OptionRenderer.tsx new file mode 100644 index 0000000000..7373690f2b --- /dev/null +++ b/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/OptionRenderer.tsx @@ -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 ( + + {optionType ? ( + +
{value}
+
+ + Type: + {optionType} + + + Data type: + {dataType} + +
+
+ ) : ( + {label} + )} +
+ ); +} + +interface OptionRendererProps { + label: string; + value: string; + dataType: string; +} + +export default OptionRenderer; diff --git a/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/index.tsx b/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/index.tsx index 59c693b6e6..975c79a4a8 100644 --- a/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/index.tsx +++ b/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/index.tsx @@ -28,6 +28,7 @@ import { v4 as uuid } from 'uuid'; import { selectStyle } from './config'; import { PLACEHOLDER } from './constant'; +import OptionRenderer from './OptionRenderer'; import { StyledCheckOutlined, TypographyText } from './style'; import { getOperatorValue, @@ -205,7 +206,11 @@ function QueryBuilderSearch({ > {options.map((option) => ( - {option.label} + {option.selected && } ))} diff --git a/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/style.ts b/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/style.ts index 07ccce0cb9..c9c2e0e221 100644 --- a/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/style.ts +++ b/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/style.ts @@ -1,5 +1,5 @@ import { CheckOutlined } from '@ant-design/icons'; -import { Typography } from 'antd'; +import { Tag, Typography } from 'antd'; import styled from 'styled-components'; export const TypographyText = styled(Typography.Text)<{ @@ -15,3 +15,27 @@ export const TypographyText = styled(Typography.Text)<{ export const StyledCheckOutlined = styled(CheckOutlined)` 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; +`; diff --git a/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/utils.ts b/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/utils.ts index d00a9d3fad..e767550be7 100644 --- a/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/utils.ts +++ b/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/utils.ts @@ -1,4 +1,5 @@ import { OPERATORS } from 'constants/queryBuilder'; +import { MetricsType } from 'container/MetricsApplication/constant'; import { parse } from 'papaparse'; import { orderByValueDelimiter } from '../OrderByFilter/utils'; @@ -140,3 +141,15 @@ export function getRemoveOrderFromValue(tag: string): string { } 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; +} diff --git a/frontend/src/container/QueryBuilder/type.ts b/frontend/src/container/QueryBuilder/type.ts index d7d746497e..892330ebdd 100644 --- a/frontend/src/container/QueryBuilder/type.ts +++ b/frontend/src/container/QueryBuilder/type.ts @@ -14,4 +14,5 @@ export type Option = { value: string; label: string; selected?: boolean; + dataType?: string; }; diff --git a/frontend/src/hooks/queryBuilder/useOptions.ts b/frontend/src/hooks/queryBuilder/useOptions.ts index 6b9c749777..322934372c 100644 --- a/frontend/src/hooks/queryBuilder/useOptions.ts +++ b/frontend/src/hooks/queryBuilder/useOptions.ts @@ -43,6 +43,7 @@ export const useOptions = ( items?.map((item) => ({ label: `${getLabel(item)}`, value: item.key, + dataType: item.dataType, })), [getLabel], ); diff --git a/frontend/src/types/common/select.ts b/frontend/src/types/common/select.ts index 6743e5bf2a..8ee453c432 100644 --- a/frontend/src/types/common/select.ts +++ b/frontend/src/types/common/select.ts @@ -1,3 +1,5 @@ +import { ReactNode } from 'react'; + export type SelectOption = { value: Value; label: Label; @@ -6,7 +8,7 @@ export type SelectOption = { export type ExtendedSelectOption = { disabled?: boolean; key: string; - label: string; + label: ReactNode; title?: string; value: string; };