feat: new qb selectedfields changes for logs and traces

This commit is contained in:
SagarRajput-7 2025-06-27 18:36:09 +05:30 committed by ahrefabhi
parent dfccbe0314
commit 10b5283edd
44 changed files with 521 additions and 375 deletions

View File

@ -9,5 +9,9 @@ export const getKeySuggestions = (
props: QueryKeyRequestProps,
): Promise<AxiosResponse<QueryKeySuggestionsResponseProps>> =>
axios.get(
`/fields/keys?signal=${props.signal}&name=${props.name}&metricName=${props.metricName}`,
`/fields/keys?signal=${props.signal}&searchText=${
props.searchText
}&metricName=${props.metricName ?? ''}&fieldContext=${
props.fieldContext ?? ''
}&fieldDataType=${props.fieldDataType ?? ''}`,
);

View File

@ -4,7 +4,6 @@ import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
import getStartEndRangeTime from 'lib/getStartEndRangeTime';
import { mapQueryDataToApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataToApi';
import { isEmpty } from 'lodash-es';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import {
IBuilderQuery,
QueryFunctionProps,
@ -126,10 +125,12 @@ function createBaseSpec(
selectFields: isEmpty(queryData.selectColumns)
? undefined
: queryData.selectColumns?.map(
(column: BaseAutocompleteData): TelemetryFieldKey => ({
name: column.key,
fieldDataType: column?.dataType as FieldDataType,
fieldContext: column?.type as FieldContext,
(column: any): TelemetryFieldKey => ({
name: column.name ?? column.key,
fieldDataType:
column?.fieldDataType ?? (column?.dataType as FieldDataType),
fieldContext: column?.fieldContext ?? (column?.type as FieldContext),
signal: column?.signal ?? undefined,
}),
),
};

View File

@ -410,18 +410,18 @@ export default function LogsFormatOptionsMenu({
)}
<div className="column-format">
{addColumn?.value?.map(({ key, id }) => (
<div className="column-name" key={id}>
{addColumn?.value?.map(({ name }) => (
<div className="column-name" key={name}>
<div className="name">
<Tooltip placement="left" title={key}>
{key}
<Tooltip placement="left" title={name}>
{name}
</Tooltip>
</div>
{addColumn?.value?.length > 1 && (
<X
className="delete-btn"
size={14}
onClick={(): void => addColumn.onRemove(id as string)}
onClick={(): void => addColumn.onRemove(name)}
/>
)}
</div>

View File

@ -143,7 +143,7 @@ function QuerySearch({
const fetchKeySuggestions = async (searchText?: string): Promise<void> => {
const response = await getKeySuggestions({
signal: dataSource,
name: searchText || '',
searchText: searchText || '',
metricName: queryData.aggregateAttribute.key ?? undefined,
});

View File

@ -13,6 +13,7 @@ import {
Typography,
} from 'antd';
import logEvent from 'api/common/logEvent';
import { TelemetryFieldKey } from 'api/v5/v5';
import axios from 'axios';
import cx from 'classnames';
import { getViewDetailsUsingViewKey } from 'components/ExplorerCard/utils';
@ -58,7 +59,6 @@ import {
} from 'react';
import { useHistory } from 'react-router-dom';
import { Dashboard } from 'types/api/dashboard/getAll';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { ViewProps } from 'types/api/saveViews/types';
import { DataSource, StringOperators } from 'types/common/queryBuilder';
@ -253,7 +253,7 @@ function ExplorerOptions({
const getUpdatedExtraData = (
extraData: string | undefined,
newSelectedColumns: BaseAutocompleteData[],
newSelectedColumns: TelemetryFieldKey[],
formattingOptions?: FormattingOptions,
): string => {
let updatedExtraData;
@ -337,7 +337,7 @@ function ExplorerOptions({
const { handleExplorerTabChange } = useHandleExplorerTabChange();
type ExtraData = {
selectColumns?: BaseAutocompleteData[];
selectColumns?: TelemetryFieldKey[];
version?: number;
};

View File

@ -87,8 +87,9 @@ function TableView({
}
});
} else {
// eslint-disable-next-line sonarjs/no-identical-functions
selectedOptions.selectColumns.forEach((val) => {
const path = findKeyPath(logData, val.key, '');
const path = findKeyPath(logData, val.name, '');
if (path) {
pinnedAttributes[path] = true;
}

View File

@ -1,11 +1,11 @@
import { TelemetryFieldKey } from 'api/v5/v5';
import { IField } from 'types/api/logs/fields';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
export const convertKeysToColumnFields = (
keys: BaseAutocompleteData[],
keys: TelemetryFieldKey[],
): IField[] =>
keys.map((item) => ({
dataType: item.dataType as string,
name: item.key,
type: item.type as string,
dataType: item.fieldDataType ?? '',
name: item.name,
type: item.fieldContext ?? '',
}));

View File

@ -1,5 +1,5 @@
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { defaultTraceSelectedColumns } from 'container/OptionsMenu/constants';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { LogsAggregatorOperator } from 'types/common/queryBuilder';
@ -43,48 +43,7 @@ export const listViewInitialTraceQuery = {
orderBy: [{ columnName: 'timestamp', order: 'desc' }],
offset: 0,
pageSize: 10,
selectColumns: [
{
key: 'serviceName',
dataType: 'string',
type: 'tag',
isColumn: true,
isJSON: false,
id: 'serviceName--string--tag--true',
},
{
key: 'name',
dataType: 'string',
type: 'tag',
isColumn: true,
isJSON: false,
id: 'name--string--tag--true',
},
{
key: 'durationNano',
dataType: 'float64',
type: 'tag',
isColumn: true,
isJSON: false,
id: 'durationNano--float64--tag--true',
},
{
key: 'httpMethod',
dataType: 'string',
type: 'tag',
isColumn: true,
isJSON: false,
id: 'httpMethod--string--tag--true',
},
{
key: 'responseStatusCode',
dataType: 'string',
type: 'tag',
isColumn: true,
isJSON: false,
id: 'responseStatusCode--string--tag--true',
},
] as BaseAutocompleteData[],
selectColumns: defaultTraceSelectedColumns,
},
],
},

View File

@ -25,9 +25,11 @@ function ExplorerAttributeColumns({
}
const filteredAttributeKeys =
data?.payload?.attributeKeys?.filter((attributeKey: any) =>
attributeKey.key.toLowerCase().includes(searchText.toLowerCase()),
) || [];
Object.values(data?.data?.data?.keys || {})
?.flat()
?.filter((attributeKey: any) =>
attributeKey.name.toLowerCase().includes(searchText.toLowerCase()),
) || [];
if (filteredAttributeKeys.length === 0) {
return (
<div className="attribute-columns">
@ -36,16 +38,17 @@ function ExplorerAttributeColumns({
);
}
console.log('filteredAttributeKeys', filteredAttributeKeys, data);
return (
<div className="attribute-columns">
{filteredAttributeKeys.map((attributeKey: any) => (
<Checkbox
checked={isAttributeKeySelected(attributeKey.key)}
onChange={(): void => handleCheckboxChange(attributeKey.key)}
checked={isAttributeKeySelected(attributeKey.name)}
onChange={(): void => handleCheckboxChange(attributeKey.name)}
style={{ padding: 0 }}
key={attributeKey.key}
key={attributeKey.name}
>
{attributeKey.key}
{attributeKey.name}
</Checkbox>
))}
</div>

View File

@ -1,3 +1,4 @@
/* eslint-disable sonarjs/no-identical-functions */
/* eslint-disable sonarjs/cognitive-complexity */
/* eslint-disable react/jsx-props-no-spreading */
import './ExplorerColumnsRenderer.styles.scss';
@ -5,9 +6,10 @@ import './ExplorerColumnsRenderer.styles.scss';
import { Color } from '@signozhq/design-tokens';
import { Button, Divider, Dropdown, Input, Tooltip, Typography } from 'antd';
import { MenuProps } from 'antd/lib';
import { FieldDataType } from 'api/v5/v5';
import { SOMETHING_WENT_WRONG } from 'constants/api';
import { useGetAggregateKeys } from 'hooks/queryBuilder/useGetAggregateKeys';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useGetQueryKeySuggestions } from 'hooks/querySuggestions/useGetQueryKeySuggestions';
import { useIsDarkMode } from 'hooks/useDarkMode';
import useDebouncedFn from 'hooks/useDebouncedFunction';
import {
@ -49,13 +51,27 @@ function ExplorerColumnsRenderer({
const initialDataSource = currentQuery.builder.queryData[0].dataSource;
const { data, isLoading, isError } = useGetAggregateKeys(
// const { data, isLoading, isError } = useGetAggregateKeys(
// {
// aggregateAttribute: '',
// dataSource: currentQuery.builder.queryData[0].dataSource,
// aggregateOperator: currentQuery.builder.queryData[0].aggregateOperator,
// searchText: querySearchText,
// tagType: '',
// },
// {
// queryKey: [
// currentQuery.builder.queryData[0].dataSource,
// currentQuery.builder.queryData[0].aggregateOperator,
// querySearchText,
// ],
// },
// );
const { data, isLoading, isError } = useGetQueryKeySuggestions(
{
aggregateAttribute: '',
dataSource: currentQuery.builder.queryData[0].dataSource,
aggregateOperator: currentQuery.builder.queryData[0].aggregateOperator,
searchText: querySearchText,
tagType: '',
signal: currentQuery.builder.queryData[0].dataSource,
},
{
queryKey: [
@ -71,7 +87,7 @@ function ExplorerColumnsRenderer({
return selectedLogFields.some((field) => field.name === key);
}
if (initialDataSource === DataSource.TRACES && selectedTracesFields) {
return selectedTracesFields.some((field) => field.key === key);
return selectedTracesFields.some((field) => field.name === key);
}
return false;
};
@ -99,18 +115,31 @@ function ExplorerColumnsRenderer({
initialDataSource === DataSource.TRACES &&
setSelectedTracesFields !== undefined
) {
const selectedField = data?.payload?.attributeKeys?.find(
(attributeKey) => attributeKey.key === key,
);
const selectedField = Object.values(data?.data?.data?.keys || {})
?.flat()
?.find((attributeKey) => attributeKey.name === key);
console.log('selectedField', selectedField);
if (selectedTracesFields) {
if (isAttributeKeySelected(key)) {
setSelectedTracesFields(
selectedTracesFields.filter((field) => field.key !== key),
selectedTracesFields.filter((field) => field.name !== key),
);
} else if (selectedField) {
setSelectedTracesFields([...selectedTracesFields, selectedField]);
setSelectedTracesFields([
...selectedTracesFields,
{
...selectedField,
fieldDataType: selectedField.fieldDataType as FieldDataType,
},
]);
}
} else if (selectedField) setSelectedTracesFields([selectedField]);
} else if (selectedField)
setSelectedTracesFields([
{
...selectedField,
fieldDataType: selectedField.fieldDataType as FieldDataType,
},
]);
}
setOpen(false);
};
@ -175,7 +204,7 @@ function ExplorerColumnsRenderer({
selectedTracesFields
) {
setSelectedTracesFields(
selectedTracesFields.filter((field) => field.key !== name),
selectedTracesFields.filter((field) => field.name !== name),
);
}
};
@ -218,6 +247,8 @@ function ExplorerColumnsRenderer({
const isDarkMode = useIsDarkMode();
console.log('selectedTracesFields', selectedTracesFields, selectedLogFields);
return (
<div className="explorer-columns-renderer">
<div className="title">
@ -279,12 +310,14 @@ function ExplorerColumnsRenderer({
>
<div className="explorer-column-title">
<GripVertical size={12} color="#5A5A5A" />
{field.key}
{field?.name || (field as any)?.key}
</div>
<Trash2
size={12}
color="red"
onClick={(): void => removeSelectedLogField(field.key)}
onClick={(): void =>
removeSelectedLogField(field?.name || (field as any)?.key)
}
data-testid="trash-icon"
/>
</div>

View File

@ -3,14 +3,12 @@
/* eslint-disable react/jsx-props-no-spreading */
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { TelemetryFieldKey } from 'api/v5/v5';
import { useGetAggregateKeys } from 'hooks/queryBuilder/useGetAggregateKeys';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import React from 'react';
import { DropResult } from 'react-beautiful-dnd';
import {
BaseAutocompleteData,
DataTypes,
} from 'types/api/queryBuilder/queryAutocompleteResponse';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { DataSource } from 'types/common/queryBuilder';
import ExplorerColumnsRenderer from '../ExplorerColumnsRenderer';
@ -321,7 +319,11 @@ describe('ExplorerColumnsRenderer', () => {
selectedLogFields={[]}
setSelectedLogFields={mockSetSelectedLogFields}
selectedTracesFields={[
{ key: 'trace_attribute1', dataType: DataTypes.String, type: 'tag' },
{
name: 'trace_attribute1',
fieldDataType: DataTypes.String,
fieldContext: '',
},
]}
setSelectedTracesFields={mockSetSelectedTracesFields}
/>,
@ -340,7 +342,11 @@ describe('ExplorerColumnsRenderer', () => {
selectedLogFields={[]}
setSelectedLogFields={mockSetSelectedLogFields}
selectedTracesFields={[
{ key: 'trace_attribute1', dataType: DataTypes.String, type: 'tag' },
{
name: 'trace_attribute1',
fieldDataType: DataTypes.String,
fieldContext: '',
},
]}
setSelectedTracesFields={mockSetSelectedTracesFields}
/>,
@ -355,15 +361,15 @@ describe('ExplorerColumnsRenderer', () => {
it('reorders trace fields on drag and drop', () => {
const initialSelectedFields = [
{ key: 'trace_field1', dataType: 'string', type: 'tag' },
{ key: 'trace_field2', dataType: 'string', type: 'tag' },
{ name: 'trace_field1', fieldDataType: 'string', fieldContext: 'tag' },
{ name: 'trace_field2', fieldDataType: 'string', fieldContext: 'tag' },
];
render(
<ExplorerColumnsRenderer
selectedLogFields={[]}
setSelectedLogFields={mockSetSelectedLogFields}
selectedTracesFields={initialSelectedFields as BaseAutocompleteData[]}
selectedTracesFields={initialSelectedFields as TelemetryFieldKey[]}
setSelectedTracesFields={mockSetSelectedTracesFields}
/>,
);
@ -383,8 +389,8 @@ describe('ExplorerColumnsRenderer', () => {
});
expect(mockSetSelectedTracesFields).toHaveBeenCalledWith([
{ key: 'trace_field2', dataType: 'string', type: 'tag' },
{ key: 'trace_field1', dataType: 'string', type: 'tag' },
{ name: 'trace_field2', fieldDataType: 'string', fieldContext: 'tag' },
{ name: 'trace_field1', fieldDataType: 'string', fieldContext: 'tag' },
]);
} else {
fail('DragDropContext or onDragEndMock not found');

View File

@ -6,9 +6,12 @@ import {
} from 'constants/queryBuilder';
import {
listViewInitialLogQuery,
listViewInitialTraceQuery,
PANEL_TYPES_INITIAL_QUERY,
} from 'container/NewDashboard/ComponentsSlider/constants';
import {
defaultLogsSelectedColumns,
defaultTraceSelectedColumns,
} from 'container/OptionsMenu/constants';
import { categoryToSupport } from 'container/QueryBuilder/filters/BuilderUnitsFilter/config';
import { cloneDeep, defaultTo, isEmpty, isEqual, set, unset } from 'lodash-es';
import { Layout } from 'react-grid-layout';
@ -503,7 +506,6 @@ export function handleQueryChange(
supersetQuery: Query,
currentPanelType: PANEL_TYPES,
): Query {
console.log('supersetQuery', supersetQuery);
return {
...supersetQuery,
builder: {
@ -564,21 +566,12 @@ export const getDefaultWidgetData = (
timePreferance: 'GLOBAL_TIME',
softMax: null,
softMin: null,
selectedLogFields: [
{
dataType: 'string',
type: '',
name: 'body',
},
{
dataType: 'string',
type: '',
name: 'timestamp',
},
],
selectedTracesFields: [
...listViewInitialTraceQuery.builder.queryData[0].selectColumns,
],
selectedLogFields: defaultLogsSelectedColumns.map((field) => ({
...field,
type: field.fieldContext ?? '',
dataType: field.fieldDataType ?? '',
})),
selectedTracesFields: defaultTraceSelectedColumns,
});
export const PANEL_TYPE_TO_QUERY_TYPES: Record<PANEL_TYPES, EQueryType[]> = {

View File

@ -42,10 +42,10 @@ function AddColumnField({ config }: AddColumnFieldProps): JSX.Element | null {
</SearchIconWrapper>
</Input.Group>
{config.value?.map(({ key, id }) => (
<AddColumnItem direction="horizontal" key={id}>
<Typography>{key}</Typography>
<DeleteOutlinedIcon onClick={(): void => config.onRemove(id as string)} />
{config.value?.map(({ name }) => (
<AddColumnItem direction="horizontal" key={name}>
<Typography>{name}</Typography>
<DeleteOutlinedIcon onClick={(): void => config.onRemove(name)} />
</AddColumnItem>
))}
</AddColumnWrapper>

View File

@ -1,4 +1,4 @@
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { TelemetryFieldKey } from 'api/v5/v5';
import { FontSize, OptionsQuery } from './types';
@ -11,71 +11,56 @@ export const defaultOptionsQuery: OptionsQuery = {
fontSize: FontSize.SMALL,
};
export const defaultLogsSelectedColumns = [
export const defaultLogsSelectedColumns: TelemetryFieldKey[] = [
{
key: 'timestamp',
dataType: DataTypes.String,
type: 'tag',
name: 'timestamp',
signal: 'logs',
fieldContext: 'log',
fieldDataType: '',
isColumn: true,
isJSON: false,
id: 'timestamp--string--tag--true',
isIndexed: false,
},
{
key: 'body',
dataType: DataTypes.String,
type: 'tag',
name: 'body',
signal: 'logs',
fieldContext: 'log',
fieldDataType: '',
isColumn: true,
isJSON: false,
id: 'body--string--tag--true',
isIndexed: false,
},
];
export const defaultTraceSelectedColumns = [
export const defaultTraceSelectedColumns: TelemetryFieldKey[] = [
{
key: 'serviceName',
dataType: DataTypes.String,
type: 'tag',
isColumn: true,
isJSON: false,
id: 'serviceName--string--tag--true',
isIndexed: false,
name: 'service.name',
signal: 'traces',
fieldContext: 'resource',
fieldDataType: 'string',
},
{
key: 'name',
dataType: DataTypes.String,
type: 'tag',
isColumn: true,
isJSON: false,
id: 'name--string--tag--true',
isIndexed: false,
name: 'name',
signal: 'traces',
fieldContext: 'span',
fieldDataType: 'string',
},
{
key: 'durationNano',
dataType: DataTypes.Float64,
type: 'tag',
isColumn: true,
isJSON: false,
id: 'durationNano--float64--tag--true',
isIndexed: false,
name: 'duration_nano',
signal: 'traces',
fieldContext: 'span',
fieldDataType: '',
},
{
key: 'httpMethod',
dataType: DataTypes.String,
type: 'tag',
isColumn: true,
isJSON: false,
id: 'httpMethod--string--tag--true',
isIndexed: false,
name: 'http_method',
signal: 'traces',
fieldContext: 'span',
fieldDataType: '',
},
{
key: 'responseStatusCode',
dataType: DataTypes.String,
type: 'tag',
isColumn: true,
isJSON: false,
id: 'responseStatusCode--string--tag--true',
isIndexed: false,
name: 'response_status_code',
signal: 'traces',
fieldContext: 'span',
fieldDataType: '',
},
];

View File

@ -1,6 +1,6 @@
import { InputNumberProps, RadioProps, SelectProps } from 'antd';
import { TelemetryFieldKey } from 'api/v5/v5';
import { LogViewMode } from 'container/LogsTable';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
export enum FontSize {
SMALL = 'small',
@ -13,7 +13,7 @@ interface FontSizeProps {
onChange: (val: FontSize) => void;
}
export interface OptionsQuery {
selectColumns: BaseAutocompleteData[];
selectColumns: TelemetryFieldKey[];
maxLines: number;
format: LogViewMode;
fontSize: FontSize;
@ -36,7 +36,7 @@ export type OptionsMenuConfig = {
'options' | 'onSelect' | 'onFocus' | 'onSearch' | 'onBlur'
> & {
isFetching: boolean;
value: BaseAutocompleteData[];
value: TelemetryFieldKey[];
onRemove: (key: string) => void;
};
};

View File

@ -1,21 +1,24 @@
import { getAggregateKeys } from 'api/queryBuilder/getAttributeKeys';
import { getKeySuggestions } from 'api/querySuggestions/getKeySuggestions';
import { TelemetryFieldKey } from 'api/v5/v5';
import { AxiosResponse } from 'axios';
import { LogViewMode } from 'container/LogsTable';
import { useGetAggregateKeys } from 'hooks/queryBuilder/useGetAggregateKeys';
import { useGetQueryKeySuggestions } from 'hooks/querySuggestions/useGetQueryKeySuggestions';
import useDebounce from 'hooks/useDebounce';
import { useNotifications } from 'hooks/useNotifications';
import useUrlQueryData from 'hooks/useUrlQueryData';
import {
AllTraceFilterKeys,
AllTraceFilterKeyValue,
} from 'pages/TracesExplorer/Filter/filterUtils';
import { AllTraceFilterKeyValue } from 'pages/TracesExplorer/Filter/filterUtils';
import { usePreferenceContext } from 'providers/preferences/context/PreferenceContextProvider';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useQueries } from 'react-query';
import { ErrorResponse, SuccessResponse } from 'types/api';
import {
BaseAutocompleteData,
IQueryAutocompleteResponse,
} from 'types/api/queryBuilder/queryAutocompleteResponse';
QueryKeyRequestProps,
QueryKeySuggestionsResponseProps,
} from 'types/api/querySuggestions/types';
import {
FieldContext,
FieldDataType,
SignalType,
} from 'types/api/v5/queryRange';
import { DataSource } from 'types/common/queryBuilder';
import {
@ -47,7 +50,7 @@ interface UseOptionsMenu {
const useOptionsMenu = ({
dataSource,
aggregateOperator,
// aggregateOperator,
initialOptions = {},
}: UseOptionsMenuProps): UseOptionsMenu => {
const { notifications } = useNotifications();
@ -61,15 +64,23 @@ const useOptionsMenu = ({
const [isFocused, setIsFocused] = useState<boolean>(false);
const debouncedSearchText = useDebounce(searchText, 300);
const initialQueryParams = useMemo(
// const initialQueryParams = useMemo(
// () => ({
// searchText: '',
// aggregateAttribute: '',
// tagType: undefined,
// dataSource,
// aggregateOperator,
// }),
// [dataSource, aggregateOperator],
// );
const initialQueryParamsV5: QueryKeyRequestProps = useMemo(
() => ({
signal: dataSource,
searchText: '',
aggregateAttribute: '',
tagType: undefined,
dataSource,
aggregateOperator,
}),
[dataSource, aggregateOperator],
[dataSource],
);
const {
@ -77,23 +88,37 @@ const useOptionsMenu = ({
redirectWithQuery: redirectWithOptionsData,
} = useUrlQueryData<OptionsQuery>(URL_OPTIONS, defaultOptionsQuery);
const initialQueries = useMemo(
// const initialQueries = useMemo(
// () =>
// initialOptions?.selectColumns?.map((column) => ({
// queryKey: column,
// queryFn: (): Promise<
// SuccessResponse<IQueryAutocompleteResponse> | ErrorResponse
// > =>
// getAggregateKeys({
// ...initialQueryParams,
// searchText: column,
// }),
// enabled: !!column && !optionsQuery,
// })) || [],
// [initialOptions?.selectColumns, initialQueryParams, optionsQuery],
// );
const initialQueriesV5 = useMemo(
() =>
initialOptions?.selectColumns?.map((column) => ({
queryKey: column,
queryFn: (): Promise<
SuccessResponse<IQueryAutocompleteResponse> | ErrorResponse
> =>
getAggregateKeys({
...initialQueryParams,
queryFn: (): Promise<AxiosResponse<QueryKeySuggestionsResponseProps>> =>
getKeySuggestions({
...initialQueryParamsV5,
searchText: column,
}),
enabled: !!column && !optionsQuery,
})) || [],
[initialOptions?.selectColumns, initialQueryParams, optionsQuery],
[initialOptions?.selectColumns, initialQueryParamsV5, optionsQuery],
);
const initialAttributesResult = useQueries(initialQueries);
const initialAttributesResult = useQueries(initialQueriesV5);
const isFetchedInitialAttributes = useMemo(
() => initialAttributesResult.every((result) => result.isFetched),
@ -106,42 +131,52 @@ const useOptionsMenu = ({
}
const attributesData = initialAttributesResult?.reduce(
(acc, attributeResponse) => {
const data = attributeResponse?.data?.payload?.attributeKeys || [];
(acc: TelemetryFieldKey[], attributeResponse): TelemetryFieldKey[] => {
const suggestions =
Object.values(attributeResponse?.data?.data?.data?.keys || {}).flat() ||
[];
return [...acc, ...data];
const mappedSuggestions: TelemetryFieldKey[] = suggestions.map(
(suggestion) => ({
name: suggestion.name,
signal: suggestion.signal as SignalType,
fieldDataType: suggestion.fieldDataType as FieldDataType,
fieldContext: suggestion.fieldContext as FieldContext,
}),
);
return [...acc, ...mappedSuggestions];
},
[] as BaseAutocompleteData[],
[],
);
let initialSelected = initialOptions.selectColumns
?.map((column) => attributesData.find(({ key }) => key === column))
.filter(Boolean) as BaseAutocompleteData[];
let initialSelected: TelemetryFieldKey[] | undefined =
initialOptions.selectColumns
?.map((column) => attributesData.find(({ name }) => name === column))
.filter((e) => !!e) || [];
if (dataSource === DataSource.TRACES) {
initialSelected = initialSelected
?.map((col) => {
if (col && Object.keys(AllTraceFilterKeyValue).includes(col?.key)) {
if (col && Object.keys(AllTraceFilterKeyValue).includes(col?.name)) {
const metaData = defaultTraceSelectedColumns.find(
(coln) => coln.key === (col.key as AllTraceFilterKeys),
(coln) => coln.name === col.name,
);
return {
...metaData,
key: metaData?.key,
dataType: metaData?.dataType,
type: metaData?.type,
isColumn: metaData?.isColumn,
isJSON: metaData?.isJSON,
id: metaData?.id,
name: metaData?.name || '',
};
}
return col;
})
.filter(Boolean) as BaseAutocompleteData[];
.filter((e) => !!e);
if (!initialSelected || !initialSelected?.length) {
initialSelected = defaultTraceSelectedColumns;
initialSelected = defaultTraceSelectedColumns.map((e) => ({
...e,
name: e.name,
}));
}
}
@ -154,41 +189,91 @@ const useOptionsMenu = ({
]);
const {
data: searchedAttributesData,
isFetching: isSearchedAttributesFetching,
} = useGetAggregateKeys(
data: searchedAttributesDataV5,
isFetching: isSearchedAttributesFetchingV5,
} = useGetQueryKeySuggestions(
{
...initialQueryParams,
...initialQueryParamsV5,
searchText: debouncedSearchText,
},
{ queryKey: [debouncedSearchText, isFocused], enabled: isFocused },
);
const searchedAttributeKeys = useMemo(() => {
if (searchedAttributesData?.payload?.attributeKeys?.length) {
// const {
// data: searchedAttributesData,
// isFetching: isSearchedAttributesFetching,
// } = useGetAggregateKeys(
// {
// ...initialQueryParams,
// searchText: debouncedSearchText,
// },
// { queryKey: [debouncedSearchText, isFocused], enabled: isFocused },
// );
const searchedAttributeKeys: TelemetryFieldKey[] = useMemo(() => {
const searchedAttributesDataList = Object.values(
searchedAttributesDataV5?.data.data.keys || {},
).flat();
if (searchedAttributesDataList.length) {
if (dataSource === DataSource.LOGS) {
const logsSelectedColumns: TelemetryFieldKey[] = defaultLogsSelectedColumns.map(
(e) => ({
...e,
name: e.name,
signal: e.signal as SignalType,
fieldContext: e.fieldContext as FieldContext,
fieldDataType: e.fieldDataType as FieldDataType,
}),
);
return [
...defaultLogsSelectedColumns,
...searchedAttributesData.payload.attributeKeys.filter(
(attribute) => attribute.key !== 'body',
),
...logsSelectedColumns,
...searchedAttributesDataList
.filter((attribute) => attribute.name !== 'body')
// eslint-disable-next-line sonarjs/no-identical-functions
.map((e) => ({
...e,
name: e.name,
signal: e.signal as SignalType,
fieldContext: e.fieldContext as FieldContext,
fieldDataType: e.fieldDataType as FieldDataType,
})),
];
}
return searchedAttributesData.payload.attributeKeys;
// eslint-disable-next-line sonarjs/no-identical-functions
return searchedAttributesDataList.map((e) => ({
...e,
name: e.name,
signal: e.signal as SignalType,
fieldContext: e.fieldContext as FieldContext,
fieldDataType: e.fieldDataType as FieldDataType,
}));
}
if (dataSource === DataSource.TRACES) {
return defaultTraceSelectedColumns;
return defaultTraceSelectedColumns.map((e) => ({
...e,
name: e.name,
}));
}
return [];
}, [dataSource, searchedAttributesData?.payload?.attributeKeys]);
}, [dataSource, searchedAttributesDataV5?.data.data.keys]);
const initialOptionsQuery: OptionsQuery = useMemo(() => {
let defaultColumns = defaultOptionsQuery.selectColumns;
let defaultColumns: TelemetryFieldKey[] = defaultOptionsQuery.selectColumns;
if (dataSource === DataSource.TRACES) {
defaultColumns = defaultTraceSelectedColumns;
defaultColumns = defaultTraceSelectedColumns.map((e) => ({
...e,
name: e.name,
}));
} else if (dataSource === DataSource.LOGS) {
defaultColumns = defaultLogsSelectedColumns;
// eslint-disable-next-line sonarjs/no-identical-functions
defaultColumns = defaultLogsSelectedColumns.map((e) => ({
...e,
name: e.name,
signal: e.signal as SignalType,
fieldContext: e.fieldContext as FieldContext,
fieldDataType: e.fieldDataType as FieldDataType,
}));
}
const finalSelectColumns = initialOptions?.selectColumns
@ -203,14 +288,14 @@ const useOptionsMenu = ({
}, [dataSource, initialOptions, initialSelectedColumns]);
const selectedColumnKeys = useMemo(
() => preferences?.columns?.map(({ id }) => id) || [],
() => preferences?.columns?.map(({ name }) => name) || [],
[preferences?.columns],
);
const optionsFromAttributeKeys = useMemo(() => {
const filteredAttributeKeys = searchedAttributeKeys.filter((item) => {
if (dataSource !== DataSource.LOGS) {
return item.key !== 'body';
return item.name !== 'body';
}
return true;
});
@ -232,11 +317,11 @@ const useOptionsMenu = ({
const column = [
...searchedAttributeKeys,
...(preferences?.columns || []),
].find(({ id }) => id === key);
].find(({ name }) => name === key);
if (!column) return acc;
return [...acc, column];
}, [] as BaseAutocompleteData[]);
}, [] as TelemetryFieldKey[]);
const optionsData: OptionsQuery = {
...defaultOptionsQuery,
@ -261,7 +346,7 @@ const useOptionsMenu = ({
const handleRemoveSelectedColumn = useCallback(
(columnKey: string) => {
const newSelectedColumns = preferences?.columns?.filter(
({ id }) => id !== columnKey,
({ name }) => name !== columnKey,
);
if (!newSelectedColumns?.length && dataSource !== DataSource.LOGS) {
@ -367,7 +452,7 @@ const useOptionsMenu = ({
const optionsMenuConfig: Required<OptionsMenuConfig> = useMemo(
() => ({
addColumn: {
isFetching: isSearchedAttributesFetching,
isFetching: isSearchedAttributesFetchingV5,
value: preferences?.columns || defaultOptionsQuery.selectColumns,
options: optionsFromAttributeKeys || [],
onFocus: handleFocus,
@ -390,7 +475,7 @@ const useOptionsMenu = ({
},
}),
[
isSearchedAttributesFetching,
isSearchedAttributesFetchingV5,
preferences,
optionsFromAttributeKeys,
handleSelectColumns,

View File

@ -1,13 +1,13 @@
import { SelectProps } from 'antd';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { TelemetryFieldKey } from 'api/v5/v5';
export const getOptionsFromKeys = (
keys: BaseAutocompleteData[],
keys: TelemetryFieldKey[],
selectedKeys: (string | undefined)[],
): SelectProps['options'] => {
const options = keys.map(({ id, key }) => ({
label: key,
value: id,
const options = keys.map(({ name }) => ({
label: name,
value: name,
}));
return options.filter(

View File

@ -1,11 +1,12 @@
import { DEFAULT_PER_PAGE_OPTIONS } from 'hooks/queryPagination';
export const defaultSelectedColumns: string[] = [
'serviceName',
'service.name',
'name',
'durationNano',
'httpMethod',
'responseStatusCode',
'duration_nano',
'http_method',
'response_status_code',
'timestamp',
];
export const PER_PAGE_OPTIONS: number[] = [10, ...DEFAULT_PER_PAGE_OPTIONS];

View File

@ -65,6 +65,8 @@ function ListView({ isFilterApplied }: ListViewProps): JSX.Element {
},
});
console.log('options', options);
const { draggedColumns, onDragColumns } = useDragColumns<RowData>(
LOCALSTORAGE.TRACES_LIST_COLUMNS,
);

View File

@ -1,5 +1,6 @@
import { Tag, Typography } from 'antd';
import { ColumnsType } from 'antd/es/table';
import { TelemetryFieldKey } from 'api/v5/v5';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import ROUTES from 'constants/routes';
import { getMs } from 'container/Trace/Filters/Panel/PanelBody/Duration/util';
@ -9,7 +10,6 @@ import { RowData } from 'lib/query/createTableColumnsFromQuery';
import LineClampedText from 'periscope/components/LineClampedText/LineClampedText';
import { Link } from 'react-router-dom';
import { ILog } from 'types/api/logs/log';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { QueryDataV3 } from 'types/api/widgets/getQuery';
export function BlockLink({
@ -47,7 +47,7 @@ export const getTraceLink = (record: RowData): string =>
})}`;
export const getListColumns = (
selectedColumns: BaseAutocompleteData[],
selectedColumns: TelemetryFieldKey[],
formatTimezoneAdjustedTimestamp: (
input: TimestampInput,
format?: string,
@ -80,48 +80,58 @@ export const getListColumns = (
];
const columns: ColumnsType<RowData> =
selectedColumns.map(({ dataType, key, type }) => ({
title: key,
dataIndex: key,
key: `${key}-${dataType}-${type}`,
width: 145,
render: (value, item): JSX.Element => {
if (value === '') {
selectedColumns.map((props) => {
const name = props?.name || (props as any)?.key;
const fieldDataType = props?.fieldDataType || (props as any)?.dataType;
const fieldContext = props?.fieldContext || (props as any)?.type;
return {
title: name,
dataIndex: name,
key: `${name}-${fieldDataType}-${fieldContext}`,
width: 145,
render: (value, item): JSX.Element => {
if (value === '') {
return (
<BlockLink to={getTraceLink(item)} openInNewTab={false}>
<Typography data-testid={name}>N/A</Typography>
</BlockLink>
);
}
if (
name === 'httpMethod' ||
name === 'responseStatusCode' ||
name === 'response_status_code' ||
name === 'http_method'
) {
return (
<BlockLink to={getTraceLink(item)} openInNewTab={false}>
<Tag data-testid={name} color="magenta">
{value}
</Tag>
</BlockLink>
);
}
if (name === 'durationNano' || name === 'duration_nano') {
return (
<BlockLink to={getTraceLink(item)} openInNewTab={false}>
<Typography data-testid={name}>{getMs(value)}ms</Typography>
</BlockLink>
);
}
return (
<BlockLink to={getTraceLink(item)} openInNewTab={false}>
<Typography data-testid={key}>N/A</Typography>
<Typography data-testid={name}>
<LineClampedText text={value} lines={3} />
</Typography>
</BlockLink>
);
}
if (key === 'httpMethod' || key === 'responseStatusCode') {
return (
<BlockLink to={getTraceLink(item)} openInNewTab={false}>
<Tag data-testid={key} color="magenta">
{value}
</Tag>
</BlockLink>
);
}
if (key === 'durationNano' || key === 'duration_nano') {
return (
<BlockLink to={getTraceLink(item)} openInNewTab={false}>
<Typography data-testid={key}>{getMs(value)}ms</Typography>
</BlockLink>
);
}
return (
<BlockLink to={getTraceLink(item)} openInNewTab={false}>
<Typography data-testid={key}>
<LineClampedText text={value} lines={3} />
</Typography>
</BlockLink>
);
},
responsive: ['md'],
})) || [];
},
responsive: ['md'],
};
}) || [];
return [...initialColumns, ...columns];
};

View File

@ -42,6 +42,8 @@ function TracesTableComponent({
});
const { safeNavigate } = useSafeNavigate();
console.log('widget.selectedTracesFields', widget.selectedTracesFields);
useEffect(() => {
setRequestData((prev) => ({
...prev,
@ -79,6 +81,7 @@ function TracesTableComponent({
[queryTableData],
);
console.log('transformedQueryTableData', transformedQueryTableData, columns);
const handleRow = useCallback(
(record: RowData): HTMLAttributes<RowData> => ({
onClick: (event): void => {

View File

@ -1,8 +1,8 @@
import { TelemetryFieldKey } from 'api/v5/v5';
import { PANEL_TYPES } from 'constants/queryBuilder';
import { convertKeysToColumnFields } from 'container/LogsExplorerList/utils';
import { placeWidgetAtBottom } from 'container/NewWidget/utils';
import { Dashboard } from 'types/api/dashboard/getAll';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
const baseLogsSelectedColumns = {
@ -16,7 +16,7 @@ export const addEmptyWidgetInDashboardJSONWithQuery = (
query: Query,
widgetId: string,
panelType?: PANEL_TYPES,
selectedColumns?: BaseAutocompleteData[] | null,
selectedColumns?: TelemetryFieldKey[] | null,
): Dashboard => {
const logsSelectedColumns = [
baseLogsSelectedColumns,

View File

@ -1,3 +1,4 @@
import { ENTITY_VERSION_V5 } from 'constants/app';
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
@ -58,7 +59,8 @@ export const useGetExplorerQueryRange = (
query: requestData || initialQueriesMap.metrics,
params,
},
version,
// version,
ENTITY_VERSION_V5,
{
...options,
retry: false,

View File

@ -1,21 +1,66 @@
import { getKeySuggestions } from 'api/querySuggestions/getKeySuggestions';
import { AxiosError, AxiosResponse } from 'axios';
import { useQuery, UseQueryResult } from 'react-query';
import { QueryKeySuggestionsResponseProps } from 'types/api/querySuggestions/types';
import { useMemo } from 'react';
import { useQuery, UseQueryOptions, UseQueryResult } from 'react-query';
import {
QueryKeyRequestProps,
QueryKeySuggestionsResponseProps,
} from 'types/api/querySuggestions/types';
export const useGetQueryKeySuggestions = ({
signal,
name,
metricName,
}: {
signal: string;
name: string;
metricName?: string;
}): UseQueryResult<
type UseGetQueryKeySuggestions = (
requestData: QueryKeyRequestProps,
options?: UseQueryOptions<
AxiosResponse<QueryKeySuggestionsResponseProps>,
AxiosError
>,
) => UseQueryResult<
AxiosResponse<QueryKeySuggestionsResponseProps>,
AxiosError
> =>
useQuery<AxiosResponse<QueryKeySuggestionsResponseProps>, AxiosError>({
queryKey: ['queryKeySuggestions', signal, name, metricName],
queryFn: () => getKeySuggestions({ signal, name, metricName }),
>;
export const useGetQueryKeySuggestions: UseGetQueryKeySuggestions = (
{
signal,
searchText,
fieldContext,
fieldDataType,
metricName,
}: QueryKeyRequestProps,
options?: UseQueryOptions<
AxiosResponse<QueryKeySuggestionsResponseProps>,
AxiosError
>,
) => {
const queryKey = useMemo(() => {
if (options?.queryKey && Array.isArray(options.queryKey)) {
return ['queryKeySuggestions', ...options.queryKey];
}
return [
'queryKeySuggestions',
signal,
searchText,
metricName,
fieldContext,
fieldDataType,
];
}, [
options?.queryKey,
signal,
searchText,
metricName,
fieldContext,
fieldDataType,
]);
return useQuery<AxiosResponse<QueryKeySuggestionsResponseProps>, AxiosError>({
queryKey,
queryFn: () =>
getKeySuggestions({
signal,
searchText,
metricName,
fieldContext,
fieldDataType,
}),
...options,
});
};

View File

@ -3,6 +3,7 @@ import './LogsExplorer.styles.scss';
import * as Sentry from '@sentry/react';
import getLocalStorageKey from 'api/browser/localstorage/get';
import setLocalStorageApi from 'api/browser/localstorage/set';
import { TelemetryFieldKey } from 'api/v5/v5';
import cx from 'classnames';
import ExplorerCard from 'components/ExplorerCard/ExplorerCard';
import QuickFilters from 'components/QuickFilters/QuickFilters';
@ -31,7 +32,6 @@ import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFall
import { usePreferenceContext } from 'providers/preferences/context/PreferenceContextProvider';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useSearchParams } from 'react-router-dom-v5-compat';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { DataSource } from 'types/common/queryBuilder';
import {
@ -200,11 +200,11 @@ function LogsExplorer(): JSX.Element {
// Check if the columns have the required columns (timestamp, body)
const hasRequiredColumns = useCallback(
(columns?: Array<{ key: string }> | null): boolean => {
(columns?: TelemetryFieldKey[] | null): boolean => {
if (!columns?.length) return false;
const hasTimestamp = columns.some((col) => col.key === 'timestamp');
const hasBody = columns.some((col) => col.key === 'body');
const hasTimestamp = columns.some((col) => col.name === 'timestamp');
const hasBody = columns.some((col) => col.name === 'body');
return hasTimestamp && hasBody;
},
@ -213,7 +213,7 @@ function LogsExplorer(): JSX.Element {
// Merge the columns with the required columns (timestamp, body) if missing
const mergeWithRequiredColumns = useCallback(
(columns: BaseAutocompleteData[]): BaseAutocompleteData[] => [
(columns: TelemetryFieldKey[]): TelemetryFieldKey[] => [
// Add required columns (timestamp, body) if missing
...(!hasRequiredColumns(columns) ? defaultLogsSelectedColumns : []),
...columns,

View File

@ -12,18 +12,28 @@ import { DataSource } from 'types/common/queryBuilder';
export const AllTraceFilterKeyValue: Record<string, string> = {
durationNanoMin: 'Duration',
durationNano: 'Duration',
duration_nano: 'Duration',
durationNanoMax: 'Duration',
'deployment.environment': 'Environment',
hasError: 'Status',
has_error: 'Status',
serviceName: 'Service Name',
'service.name': 'service.name',
name: 'Operation / Name',
rpcMethod: 'RPC Method',
'rpc.method': 'RPC Method',
responseStatusCode: 'Status Code',
response_status_code: 'Status Code',
httpHost: 'HTTP Host',
http_host: 'HTTP Host',
httpMethod: 'HTTP Method',
http_method: 'HTTP Method',
httpRoute: 'HTTP Route',
'http.route': 'HTTP Route',
httpUrl: 'HTTP URL',
'http.url': 'HTTP URL',
traceID: 'Trace ID',
trace_id: 'Trace ID',
} as const;
export type AllTraceFilterKeys = keyof typeof AllTraceFilterKeyValue;

View File

@ -1,12 +1,12 @@
/* eslint-disable sonarjs/no-identical-functions */
import { render, screen } from '@testing-library/react';
import { TelemetryFieldKey } from 'api/v5/v5';
import {
FormattingOptions,
PreferenceMode,
Preferences,
} from 'providers/preferences/types';
import { MemoryRouter, Route, Switch } from 'react-router-dom';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import {
PreferenceContextProvider,
@ -17,7 +17,7 @@ import {
jest.mock('../sync/usePreferenceSync', () => ({
usePreferenceSync: jest.fn().mockReturnValue({
preferences: {
columns: [] as BaseAutocompleteData[],
columns: [] as TelemetryFieldKey[],
formatting: {
maxLines: 2,
format: 'table',

View File

@ -150,7 +150,7 @@ describe('logsLoaderConfig', () => {
const result = await logsLoaderConfig.default();
expect(result).toEqual({
columns: defaultLogsSelectedColumns as BaseAutocompleteData[],
columns: defaultLogsSelectedColumns,
formatting: {
maxLines: 2,
format: 'table' as LogViewMode,

View File

@ -1,3 +1,4 @@
import { TelemetryFieldKey } from 'api/v5/v5';
import { LOCALSTORAGE } from 'constants/localStorage';
import { LogViewMode } from 'container/LogsTable';
import { defaultOptionsQuery } from 'container/OptionsMenu/constants';
@ -7,10 +8,7 @@ import {
PreferenceMode,
Preferences,
} from 'providers/preferences/types';
import {
BaseAutocompleteData,
DataTypes,
} from 'types/api/queryBuilder/queryAutocompleteResponse';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import getLogsUpdaterConfig from '../configs/logsUpdaterConfig';
@ -65,11 +63,11 @@ describe('logsUpdaterConfig', () => {
setSavedViewPreferences,
);
const newColumns: BaseAutocompleteData[] = [
const newColumns: TelemetryFieldKey[] = [
{
key: 'new-column',
type: 'tag',
dataType: DataTypes.String,
name: 'new-column',
fieldContext: '',
fieldDataType: DataTypes.String,
isColumn: true,
},
];
@ -114,11 +112,11 @@ describe('logsUpdaterConfig', () => {
setSavedViewPreferences,
);
const newColumns: BaseAutocompleteData[] = [
const newColumns: TelemetryFieldKey[] = [
{
key: 'new-column',
type: 'tag',
dataType: DataTypes.String,
name: 'new-column',
fieldContext: '',
fieldDataType: DataTypes.String,
isColumn: true,
},
];

View File

@ -4,6 +4,7 @@ import {
BaseAutocompleteData,
DataTypes,
} from 'types/api/queryBuilder/queryAutocompleteResponse';
import { TelemetryFieldKey } from 'types/api/v5/queryRange';
import tracesLoaderConfig from '../configs/tracesLoaderConfig';
@ -125,7 +126,7 @@ describe('tracesLoaderConfig', () => {
const result = await tracesLoaderConfig.default();
expect(result).toEqual({
columns: defaultTraceSelectedColumns as BaseAutocompleteData[],
columns: defaultTraceSelectedColumns as TelemetryFieldKey[],
});
});
});

View File

@ -1,9 +1,7 @@
import { TelemetryFieldKey } from 'api/v5/v5';
import { LOCALSTORAGE } from 'constants/localStorage';
import { defaultOptionsQuery } from 'container/OptionsMenu/constants';
import {
BaseAutocompleteData,
DataTypes,
} from 'types/api/queryBuilder/queryAutocompleteResponse';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import getTracesUpdaterConfig from '../configs/tracesUpdaterConfig';
import { PreferenceMode } from '../types';
@ -34,11 +32,11 @@ describe('tracesUpdaterConfig', () => {
const mockSetSavedViewPreferences = jest.fn();
// Test data
const mockColumns: BaseAutocompleteData[] = [
const mockColumns: TelemetryFieldKey[] = [
{
key: 'test-trace-column',
type: 'tag',
dataType: DataTypes.String,
name: 'test-trace-column',
fieldContext: '',
fieldDataType: DataTypes.String,
isColumn: true,
},
];

View File

@ -1,5 +1,6 @@
/* eslint-disable sonarjs/no-identical-functions */
import { renderHook } from '@testing-library/react';
import { TelemetryFieldKey } from 'api/v5/v5';
import { LogViewMode } from 'container/LogsTable';
import { FontSize } from 'container/OptionsMenu/types';
import {
@ -8,10 +9,7 @@ import {
Preferences,
} from 'providers/preferences/types';
import { act } from 'react-dom/test-utils';
import {
BaseAutocompleteData,
DataTypes,
} from 'types/api/queryBuilder/queryAutocompleteResponse';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { DataSource } from 'types/common/queryBuilder';
import { usePreferenceUpdater } from '../updater/usePreferenceUpdater';
@ -81,11 +79,11 @@ describe('usePreferenceUpdater', () => {
it('should call the logs updater for updateColumns with logs dataSource', () => {
const setReSync = jest.fn();
const setSavedViewPreferences = jest.fn();
const newColumns: BaseAutocompleteData[] = [
const newColumns: TelemetryFieldKey[] = [
{
key: 'new-column',
type: 'tag',
dataType: DataTypes.String,
name: 'new-column',
fieldContext: '',
fieldDataType: DataTypes.String,
isColumn: true,
},
];
@ -147,11 +145,11 @@ describe('usePreferenceUpdater', () => {
it('should call the traces updater for updateColumns with traces dataSource', () => {
const setReSync = jest.fn();
const setSavedViewPreferences = jest.fn();
const newColumns: BaseAutocompleteData[] = [
const newColumns: TelemetryFieldKey[] = [
{
key: 'new-trace-column',
type: 'tag',
dataType: DataTypes.String,
name: 'new-trace-column',
fieldContext: '',
fieldDataType: DataTypes.String,
isColumn: true,
},
];
@ -227,9 +225,9 @@ describe('usePreferenceUpdater', () => {
act(() => {
result.current.updateColumns([
{
key: 'column',
type: 'tag',
dataType: DataTypes.String,
name: 'column',
fieldContext: '',
fieldDataType: DataTypes.String,
isColumn: true,
},
]);

View File

@ -1,5 +1,6 @@
/* eslint-disable no-empty */
import getLocalStorageKey from 'api/browser/localstorage/get';
import { TelemetryFieldKey } from 'api/v5/v5';
import { LOCALSTORAGE } from 'constants/localStorage';
import { defaultLogsSelectedColumns } from 'container/OptionsMenu/constants';
import { FontSize } from 'container/OptionsMenu/types';
@ -50,10 +51,10 @@ const logsLoaders = {
return { columns: [], formatting: undefined } as any;
},
default: async (): Promise<{
columns: BaseAutocompleteData[];
columns: TelemetryFieldKey[];
formatting: FormattingOptions;
}> => ({
columns: defaultLogsSelectedColumns as BaseAutocompleteData[],
columns: defaultLogsSelectedColumns,
formatting: {
maxLines: 2,
format: 'table',

View File

@ -1,9 +1,9 @@
import setLocalStorageKey from 'api/browser/localstorage/set';
import { TelemetryFieldKey } from 'api/v5/v5';
import { LOCALSTORAGE } from 'constants/localStorage';
import { defaultOptionsQuery } from 'container/OptionsMenu/constants';
import { FontSize, OptionsQuery } from 'container/OptionsMenu/types';
import { Dispatch, SetStateAction } from 'react';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { FormattingOptions, PreferenceMode, Preferences } from '../types';
@ -13,10 +13,10 @@ const getLogsUpdaterConfig = (
redirectWithOptionsData: (options: OptionsQuery) => void,
setSavedViewPreferences: Dispatch<SetStateAction<Preferences | null>>,
): {
updateColumns: (newColumns: BaseAutocompleteData[], mode: string) => void;
updateColumns: (newColumns: TelemetryFieldKey[], mode: string) => void;
updateFormatting: (newFormatting: FormattingOptions, mode: string) => void;
} => ({
updateColumns: (newColumns: BaseAutocompleteData[], mode: string): void => {
updateColumns: (newColumns: TelemetryFieldKey[], mode: string): void => {
if (mode === PreferenceMode.SAVED_VIEW) {
setSavedViewPreferences((prev) => {
if (!prev) {

View File

@ -1,5 +1,6 @@
/* eslint-disable no-empty */
import getLocalStorageKey from 'api/browser/localstorage/get';
import { TelemetryFieldKey } from 'api/v5/v5';
import { LOCALSTORAGE } from 'constants/localStorage';
import { defaultTraceSelectedColumns } from 'container/OptionsMenu/constants';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
@ -33,9 +34,9 @@ const tracesLoaders = {
return { columns: [] };
},
default: async (): Promise<{
columns: BaseAutocompleteData[];
columns: TelemetryFieldKey[];
}> => ({
columns: defaultTraceSelectedColumns as BaseAutocompleteData[],
columns: defaultTraceSelectedColumns,
}),
priority: ['local', 'url', 'default'] as const,
};

View File

@ -1,9 +1,9 @@
import setLocalStorageKey from 'api/browser/localstorage/set';
import { TelemetryFieldKey } from 'api/v5/v5';
import { LOCALSTORAGE } from 'constants/localStorage';
import { defaultOptionsQuery } from 'container/OptionsMenu/constants';
import { FontSize, OptionsQuery } from 'container/OptionsMenu/types';
import { Dispatch, SetStateAction } from 'react';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { PreferenceMode, Preferences } from '../types';
@ -12,10 +12,10 @@ const getTracesUpdaterConfig = (
redirectWithOptionsData: (options: OptionsQuery) => void,
setSavedViewPreferences: Dispatch<SetStateAction<Preferences | null>>,
): {
updateColumns: (newColumns: BaseAutocompleteData[], mode: string) => void;
updateColumns: (newColumns: TelemetryFieldKey[], mode: string) => void;
updateFormatting: () => void;
} => ({
updateColumns: (newColumns: BaseAutocompleteData[], mode: string): void => {
updateColumns: (newColumns: TelemetryFieldKey[], mode: string): void => {
// remove the formatting props
if (mode === PreferenceMode.SAVED_VIEW) {
setSavedViewPreferences({

View File

@ -1,7 +1,7 @@
/* eslint-disable sonarjs/cognitive-complexity */
/* eslint-disable no-empty */
import { TelemetryFieldKey } from 'api/v5/v5';
import { useEffect, useState } from 'react';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { DataSource } from 'types/common/queryBuilder';
import logsLoaderConfig from '../configs/logsLoaderConfig';
@ -43,14 +43,14 @@ async function preferencesLoader<T>(config: {
// Use the generic loader with specific configs
async function logsPreferencesLoader(): Promise<{
columns: BaseAutocompleteData[];
columns: TelemetryFieldKey[];
formatting: FormattingOptions;
}> {
return preferencesLoader(logsLoaderConfig);
}
async function tracesPreferencesLoader(): Promise<{
columns: BaseAutocompleteData[];
columns: TelemetryFieldKey[];
}> {
return preferencesLoader(tracesLoaderConfig);
}

View File

@ -1,8 +1,8 @@
import { TelemetryFieldKey } from 'api/v5/v5';
import { defaultLogsSelectedColumns } from 'container/OptionsMenu/constants';
import { defaultSelectedColumns as defaultTracesSelectedColumns } from 'container/TracesExplorer/ListView/configs';
import { useGetAllViews } from 'hooks/saveViews/useGetAllViews';
import { useEffect, useState } from 'react';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { DataSource } from 'types/common/queryBuilder';
import { usePreferenceLoader } from '../loader/usePreferenceLoader';
@ -21,7 +21,7 @@ export function usePreferenceSync({
preferences: Preferences | null;
loading: boolean;
error: Error | null;
updateColumns: (newColumns: BaseAutocompleteData[]) => void;
updateColumns: (newColumns: TelemetryFieldKey[]) => void;
updateFormatting: (newFormatting: FormattingOptions) => void;
} {
const { data: viewsData } = useGetAllViews(dataSource);
@ -37,7 +37,7 @@ export function usePreferenceSync({
)?.extraData;
const parsedExtraData = JSON.parse(extraData || '{}');
let columns: BaseAutocompleteData[] = [];
let columns: TelemetryFieldKey[] = [];
let formatting: FormattingOptions | undefined;
if (dataSource === DataSource.LOGS) {
columns = parsedExtraData?.selectColumns || defaultLogsSelectedColumns;

View File

@ -1,6 +1,6 @@
import { TelemetryFieldKey } from 'api/v5/v5';
import { LogViewMode } from 'container/LogsTable';
import { FontSize } from 'container/OptionsMenu/types';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { DataSource } from 'types/common/queryBuilder';
export enum PreferenceMode {
@ -15,7 +15,7 @@ export interface PreferenceContextValue {
mode: PreferenceMode;
savedViewId?: string;
dataSource: DataSource;
updateColumns: (newColumns: BaseAutocompleteData[]) => void;
updateColumns: (newColumns: TelemetryFieldKey[]) => void;
updateFormatting: (newFormatting: FormattingOptions) => void;
}
@ -27,6 +27,6 @@ export interface FormattingOptions {
}
export interface Preferences {
columns: BaseAutocompleteData[];
columns: TelemetryFieldKey[];
formatting?: FormattingOptions;
}

View File

@ -1,3 +1,4 @@
import { TelemetryFieldKey } from 'api/v5/v5';
import {
defaultOptionsQuery,
URL_OPTIONS,
@ -5,7 +6,6 @@ import {
import { OptionsQuery } from 'container/OptionsMenu/types';
import useUrlQueryData from 'hooks/useUrlQueryData';
import { Dispatch, SetStateAction } from 'react';
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { DataSource } from 'types/common/queryBuilder';
import getLogsUpdaterConfig from '../configs/logsUpdaterConfig';
@ -24,7 +24,7 @@ const getUpdaterConfig = (
): Record<
DataSource,
{
updateColumns: (newColumns: BaseAutocompleteData[], mode: string) => void;
updateColumns: (newColumns: TelemetryFieldKey[], mode: string) => void;
updateFormatting: (newFormatting: FormattingOptions, mode: string) => void;
}
> => ({
@ -53,7 +53,7 @@ export function usePreferenceUpdater({
setReSync: Dispatch<SetStateAction<boolean>>;
setSavedViewPreferences: Dispatch<SetStateAction<Preferences | null>>;
}): {
updateColumns: (newColumns: BaseAutocompleteData[]) => void;
updateColumns: (newColumns: TelemetryFieldKey[]) => void;
updateFormatting: (newFormatting: FormattingOptions) => void;
} {
const {
@ -66,7 +66,7 @@ export function usePreferenceUpdater({
)[dataSource];
return {
updateColumns: (newColumns: BaseAutocompleteData[]): void => {
updateColumns: (newColumns: TelemetryFieldKey[]): void => {
updater.updateColumns(newColumns, mode);
setReSync(true);
},

View File

@ -7,7 +7,7 @@ import { Layout } from 'react-grid-layout';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { IField } from '../logs/fields';
import { BaseAutocompleteData } from '../queryBuilder/queryAutocompleteResponse';
import { TelemetryFieldKey } from '../v5/queryRange';
export const VariableQueryTypeArr = ['QUERY', 'TEXTBOX', 'CUSTOM'] as const;
export type TVariableQueryType = typeof VariableQueryTypeArr[number];
@ -115,7 +115,7 @@ export interface IBaseWidget {
fillSpans?: boolean;
columnUnits?: ColumnUnit;
selectedLogFields: IField[] | null;
selectedTracesFields: BaseAutocompleteData[] | null;
selectedTracesFields: TelemetryFieldKey[] | null;
isLogScale?: boolean;
columnWidths?: Record<string, number>;
legendPosition?: LegendPosition;

View File

@ -1,3 +1,4 @@
import { TelemetryFieldKey } from 'api/v5/v5';
import { Format } from 'container/NewWidget/RightContainer/types';
import { EQueryType } from 'types/common/dashboard';
import {
@ -85,7 +86,7 @@ export type IBuilderQuery = {
legend: string;
pageSize?: number;
offset?: number;
selectColumns?: BaseAutocompleteData[];
selectColumns?: BaseAutocompleteData[] | TelemetryFieldKey[];
};
export interface IClickHouseQuery {

View File

@ -4,10 +4,10 @@ export interface QueryKeyDataSuggestionsProps {
info?: string;
apply?: string;
detail?: string;
fieldContext: string;
fieldDataType: string;
fieldContext?: 'resource' | 'scope' | 'attribute' | 'span';
fieldDataType?: 'string' | 'number' | 'boolean';
name: string;
signal: string;
signal: 'traces' | 'logs' | 'metrics';
}
export interface QueryKeySuggestionsResponseProps {
@ -21,8 +21,10 @@ export interface QueryKeySuggestionsResponseProps {
}
export interface QueryKeyRequestProps {
signal: string;
name: string;
signal: 'traces' | 'logs' | 'metrics';
searchText: string;
fieldContext?: 'resource' | 'scope' | 'attribute' | 'span';
fieldDataType?: 'string' | 'number' | 'boolean';
metricName?: string;
}

View File

@ -130,6 +130,9 @@ export interface TelemetryFieldKey {
fieldContext?: FieldContext;
fieldDataType?: FieldDataType;
materialized?: boolean;
isColumn?: boolean;
isJSON?: boolean;
isIndexed?: boolean;
}
export interface Filter {