feat: add the traces view for the traces explorer (#2966)

* feat: add dynamic table based on query

* feat: add the list view for the traces explorer

* feat: add the list view for the traces explorer

* feat: add the list view for the traces explorer

* feat: add the table view for the traces explorer

* feat: add the table view for the traces explorer

* feat: add the trace view for the traces explorer

* feat: update the traces view tab for the traces explorer page

* feat: update the traces view

---------

Co-authored-by: Yevhen Shevchenko <y.shevchenko@seedium.io>
Co-authored-by: Nazarenko19 <danil.nazarenko2000@gmail.com>
Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
This commit is contained in:
dnazarenkoo 2023-07-04 08:24:34 +03:00 committed by GitHub
parent 78da014b52
commit 10a3a6d3e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 424 additions and 104 deletions

View File

@ -232,8 +232,8 @@ export const PANEL_TYPES: Record<PanelTypeKeys, GRAPH_TYPES> = {
VALUE: 'value',
TABLE: 'table',
LIST: 'list',
EMPTY_WIDGET: 'EMPTY_WIDGET',
TRACE: 'trace',
EMPTY_WIDGET: 'EMPTY_WIDGET',
};
export type IQueryBuilderState = 'search';

View File

@ -1,13 +1,14 @@
import { LeftOutlined, RightOutlined } from '@ant-design/icons';
import { Button, Select } from 'antd';
import { Pagination } from 'hooks/queryPagination';
import { DEFAULT_PER_PAGE_OPTIONS, Pagination } from 'hooks/queryPagination';
import { memo, useMemo } from 'react';
import { defaultSelectStyle, ITEMS_PER_PAGE_OPTIONS } from './config';
import { defaultSelectStyle } from './config';
import { Container } from './styles';
function Controls({
offset = 0,
perPageOptions = DEFAULT_PER_PAGE_OPTIONS,
isLoading,
totalCount,
countPerPage,
@ -51,7 +52,7 @@ function Controls({
value={countPerPage}
onChange={handleCountItemsPerPageChange}
>
{ITEMS_PER_PAGE_OPTIONS.map((count) => (
{perPageOptions.map((count) => (
<Select.Option
key={count}
value={count}
@ -64,10 +65,12 @@ function Controls({
Controls.defaultProps = {
offset: 0,
perPageOptions: DEFAULT_PER_PAGE_OPTIONS,
};
export interface ControlsProps {
offset?: Pagination['offset'];
perPageOptions?: number[];
totalCount: number;
countPerPage: Pagination['limit'];
isLoading: boolean;

View File

@ -40,6 +40,7 @@ export const Query = memo(function Query({
const {
operators,
isMetricsDataSource,
isTracePanelType,
listOfAdditionalFilters,
handleChangeAggregatorAttribute,
handleChangeDataSource,
@ -352,13 +353,15 @@ export const Query = memo(function Query({
</Col>
</Row>
</Col>
<Col span={24}>
<AdditionalFiltersToggler listOfAdditionalFilter={listOfAdditionalFilters}>
<Row gutter={[0, 11]} justify="space-between">
{renderAdditionalFilters()}
</Row>
</AdditionalFiltersToggler>
</Col>
{!isTracePanelType && (
<Col span={24}>
<AdditionalFiltersToggler listOfAdditionalFilter={listOfAdditionalFilters}>
<Row gutter={[0, 11]} justify="space-between">
{renderAdditionalFilters()}
</Row>
</AdditionalFiltersToggler>
</Col>
)}
<Row style={{ width: '100%' }}>
<Input
onChange={handleChangeQueryLegend}

View File

@ -1,4 +1,5 @@
import { TableProps } from 'antd';
import { ColumnsType } from 'antd/es/table';
import { RowData } from 'lib/query/createTableColumnsFromQuery';
import { ReactNode } from 'react';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
@ -11,4 +12,5 @@ export type QueryTableProps = Omit<
queryTableData: QueryDataV3[];
query: Query;
renderActionCell?: (record: RowData) => ReactNode;
modifyColumns?: (columns: ColumnsType<RowData>) => ColumnsType<RowData>;
};

View File

@ -13,6 +13,7 @@ export function QueryTable({
queryTableData,
query,
renderActionCell,
modifyColumns,
...props
}: QueryTableProps): JSX.Element {
const { columns, dataSource } = useMemo(
@ -39,9 +40,13 @@ export function QueryTable({
return currentColumns;
}, [columns]);
const tableColumns = modifyColumns
? modifyColumns(modifiedColumns)
: modifiedColumns;
return (
<ResizeTable
columns={modifiedColumns}
columns={tableColumns}
tableLayout="fixed"
dataSource={dataSource}
scroll={{ x: true }}

View File

@ -33,9 +33,9 @@ function TimeSeriesViewContainer({
queryKey: [
REACT_QUERY_KEY.GET_QUERY_RANGE,
globalSelectedTime,
stagedQuery,
maxTime,
minTime,
stagedQuery,
],
enabled: !!stagedQuery,
},

View File

@ -1,25 +1,51 @@
import Controls from 'container/Controls';
import Controls, { ControlsProps } from 'container/Controls';
import OptionsMenu from 'container/OptionsMenu';
import { OptionsMenuConfig } from 'container/OptionsMenu/types';
import useQueryPagination from 'hooks/queryPagination/useQueryPagination';
import { memo } from 'react';
import { Container } from './styles';
function TraceExplorerControls(): JSX.Element | null {
const handleCountItemsPerPageChange = (): void => {};
const handleNavigatePrevious = (): void => {};
const handleNavigateNext = (): void => {};
function TraceExplorerControls({
isLoading,
totalCount,
perPageOptions,
config,
}: TraceExplorerControlsProps): JSX.Element | null {
const {
pagination,
handleCountItemsPerPageChange,
handleNavigateNext,
handleNavigatePrevious,
} = useQueryPagination(totalCount, perPageOptions);
return (
<Container>
{config && <OptionsMenu config={{ addColumn: config?.addColumn }} />}
<Controls
isLoading={false}
totalCount={0}
countPerPage={25}
handleNavigatePrevious={handleNavigatePrevious}
handleNavigateNext={handleNavigateNext}
isLoading={isLoading}
totalCount={totalCount}
offset={pagination.offset}
countPerPage={pagination.limit}
perPageOptions={perPageOptions}
handleCountItemsPerPageChange={handleCountItemsPerPageChange}
handleNavigateNext={handleNavigateNext}
handleNavigatePrevious={handleNavigatePrevious}
/>
</Container>
);
}
TraceExplorerControls.defaultProps = {
config: null,
};
type TraceExplorerControlsProps = Pick<
ControlsProps,
'isLoading' | 'totalCount' | 'perPageOptions'
> & {
config?: OptionsMenuConfig | null;
};
export default memo(TraceExplorerControls);

View File

@ -3,6 +3,7 @@ import { PANEL_TYPES } from 'constants/queryBuilder';
import { QueryBuilder } from 'container/QueryBuilder';
import { useGetPanelTypesQueryParam } from 'hooks/queryBuilder/useGetPanelTypesQueryParam';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { memo } from 'react';
import { DataSource } from 'types/common/queryBuilder';
import { ButtonWrapper, Container } from './styles';
@ -10,7 +11,7 @@ import { ButtonWrapper, Container } from './styles';
function QuerySection(): JSX.Element {
const { handleRunQuery } = useQueryBuilder();
const panelTypes = useGetPanelTypesQueryParam(PANEL_TYPES.TIME_SERIES);
const panelTypes = useGetPanelTypesQueryParam(PANEL_TYPES.LIST);
return (
<Container>
@ -32,4 +33,4 @@ function QuerySection(): JSX.Element {
);
}
export default QuerySection;
export default memo(QuerySection);

View File

@ -0,0 +1,49 @@
import { Typography } from 'antd';
import { ColumnsType } from 'antd/es/table';
import ROUTES from 'constants/routes';
import { getMs } from 'container/Trace/Filters/Panel/PanelBody/Duration/util';
import { DEFAULT_PER_PAGE_OPTIONS } from 'hooks/queryPagination';
import { generatePath } from 'react-router-dom';
import { ListItem } from 'types/api/widgets/getQuery';
export const PER_PAGE_OPTIONS: number[] = [10, ...DEFAULT_PER_PAGE_OPTIONS];
export const columns: ColumnsType<ListItem['data']> = [
{
title: 'Root Service Name',
dataIndex: 'subQuery.serviceName',
key: 'serviceName',
},
{
title: 'Root Operation Name',
dataIndex: 'subQuery.name',
key: 'name',
},
{
title: 'Root Duration (in ms)',
dataIndex: 'subQuery.durationNano',
key: 'durationNano',
render: (duration: number): JSX.Element => (
<Typography>{getMs(String(duration))}ms</Typography>
),
},
{
title: 'No of Spans',
dataIndex: 'span_count',
key: 'span_count',
},
{
title: 'TraceID',
dataIndex: 'traceID',
key: 'traceID',
render: (traceID: string): JSX.Element => (
<Typography.Link
href={generatePath(ROUTES.TRACE_DETAIL, {
id: traceID,
})}
>
{traceID}
</Typography.Link>
),
},
];

View File

@ -0,0 +1,87 @@
import Typography from 'antd/es/typography/Typography';
import { ResizeTable } from 'components/ResizeTable';
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { Pagination, URL_PAGINATION } from 'hooks/queryPagination';
import useUrlQueryData from 'hooks/useUrlQueryData';
import { useMemo } from 'react';
import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
import { GlobalReducer } from 'types/reducer/globalTime';
import TraceExplorerControls from '../Controls';
import { columns, PER_PAGE_OPTIONS } from './configs';
import { ActionsContainer, Container } from './styles';
function TracesView(): JSX.Element {
const { stagedQuery, panelType } = useQueryBuilder();
const { selectedTime: globalSelectedTime, maxTime, minTime } = useSelector<
AppState,
GlobalReducer
>((state) => state.globalTime);
const { queryData: paginationQueryData } = useUrlQueryData<Pagination>(
URL_PAGINATION,
);
const { data, isLoading } = useGetQueryRange(
{
query: stagedQuery || initialQueriesMap.traces,
graphType: panelType || PANEL_TYPES.TRACE,
selectedTime: 'GLOBAL_TIME',
globalSelectedInterval: globalSelectedTime,
params: {
dataSource: 'traces',
},
tableParams: {
pagination: paginationQueryData,
},
},
{
queryKey: [
REACT_QUERY_KEY.GET_QUERY_RANGE,
globalSelectedTime,
maxTime,
minTime,
stagedQuery,
panelType,
paginationQueryData,
],
enabled: !!stagedQuery && panelType === PANEL_TYPES.TRACE,
},
);
const responseData = data?.payload?.data?.newResult?.data?.result[0]?.list;
const tableData = useMemo(
() => responseData?.map((listItem) => listItem.data),
[responseData],
);
return (
<Container>
<ActionsContainer>
<Typography>
Showing up to X of the slowest traces form the selected time range
</Typography>
<TraceExplorerControls
isLoading={isLoading}
totalCount={responseData?.length || 0}
perPageOptions={PER_PAGE_OPTIONS}
/>
</ActionsContainer>
<ResizeTable
loading={isLoading}
columns={columns}
tableLayout="fixed"
dataSource={tableData}
scroll={{ x: true }}
pagination={false}
/>
</Container>
);
}
export default TracesView;

View File

@ -0,0 +1,13 @@
import styled from 'styled-components';
export const Container = styled.div`
display: flex;
flex-direction: column;
gap: 15px;
`;
export const ActionsContainer = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
`;

View File

@ -122,6 +122,10 @@ export const useQueryOperations: UseQueryOperations = ({ query, index }) => {
[query.dataSource],
);
const isTracePanelType = useMemo(() => panelType === PANEL_TYPES.TRACE, [
panelType,
]);
useEffect(() => {
if (initialDataSource && dataSource !== initialDataSource) return;
@ -142,6 +146,7 @@ export const useQueryOperations: UseQueryOperations = ({ query, index }) => {
}, [dataSource, aggregateOperator, getNewListOfAdditionalFilters]);
return {
isTracePanelType,
isMetricsDataSource,
operators,
listOfAdditionalFilters,

View File

@ -1,8 +1,3 @@
import { Pagination } from './types';
export const URL_PAGINATION = 'pagination';
export const defaultPaginationConfig: Pagination = {
offset: 0,
limit: 25,
};
export const DEFAULT_PER_PAGE_OPTIONS: number[] = [25, 50, 100, 200];

View File

@ -1,4 +1,4 @@
export interface Pagination {
offset: number;
limit: 25 | 50 | 100 | 200;
limit: number;
}

View File

@ -1,12 +1,23 @@
import { ControlsProps } from 'container/Controls';
import useUrlQueryData from 'hooks/useUrlQueryData';
import { useCallback, useEffect } from 'react';
import { useCallback, useEffect, useMemo } from 'react';
import { defaultPaginationConfig, URL_PAGINATION } from './config';
import { DEFAULT_PER_PAGE_OPTIONS, URL_PAGINATION } from './config';
import { Pagination } from './types';
import { checkIsValidPaginationData } from './utils';
import {
checkIsValidPaginationData,
getDefaultPaginationConfig,
} from './utils';
const useQueryPagination = (
totalCount: number,
perPageOptions: number[] = DEFAULT_PER_PAGE_OPTIONS,
): UseQueryPagination => {
const defaultPaginationConfig = useMemo(
() => getDefaultPaginationConfig(perPageOptions),
[perPageOptions],
);
const useQueryPagination = (totalCount: number): UseQueryPagination => {
const {
query: paginationQuery,
queryData: paginationQueryData,
@ -45,12 +56,19 @@ const useQueryPagination = (totalCount: number): UseQueryPagination => {
useEffect(() => {
const isValidPaginationData = checkIsValidPaginationData(
paginationQueryData || defaultPaginationConfig,
perPageOptions,
);
if (paginationQuery && isValidPaginationData) return;
redirectWithCurrentPagination(defaultPaginationConfig);
}, [paginationQuery, paginationQueryData, redirectWithCurrentPagination]);
}, [
defaultPaginationConfig,
perPageOptions,
paginationQuery,
paginationQueryData,
redirectWithCurrentPagination,
]);
return {
pagination: paginationQueryData || defaultPaginationConfig,

View File

@ -1,12 +1,20 @@
import { DEFAULT_PER_PAGE_OPTIONS } from './config';
import { Pagination } from './types';
export const checkIsValidPaginationData = ({
limit,
offset,
}: Pagination): boolean =>
export const checkIsValidPaginationData = (
{ limit, offset }: Pagination,
perPageOptions: number[],
): boolean =>
Boolean(
limit &&
(limit === 25 || limit === 50 || limit === 100 || limit === 200) &&
offset &&
offset > 0,
Number.isInteger(limit) &&
limit > 0 &&
offset >= 0 &&
perPageOptions.find((option) => option === limit),
);
export const getDefaultPaginationConfig = (
perPageOptions = DEFAULT_PER_PAGE_OPTIONS,
): Pagination => ({
offset: 0,
limit: perPageOptions[0],
});

View File

@ -10,7 +10,7 @@ const useUrlQueryData = <T>(
const location = useLocation();
const urlQuery = useUrlQuery();
const query = urlQuery.get(queryKey);
const query = useMemo(() => urlQuery.get(queryKey), [queryKey, urlQuery]);
const queryData: T = useMemo(() => (query ? JSON.parse(query) : defaultData), [
query,

View File

@ -15,12 +15,16 @@ export const getOperatorsBySourceAndPanelType = ({
}: GetQueryOperatorsParams): SelectOption<string, string>[] => {
let operatorsByDataSource = mapOfOperators[dataSource];
if (panelType === PANEL_TYPES.LIST) {
if (panelType === PANEL_TYPES.LIST || panelType === PANEL_TYPES.TRACE) {
operatorsByDataSource = operatorsByDataSource.filter(
(operator) => operator.value === StringOperators.NOOP,
);
}
if (dataSource !== DataSource.METRICS && panelType !== PANEL_TYPES.LIST) {
if (
dataSource !== DataSource.METRICS &&
panelType !== PANEL_TYPES.LIST &&
panelType !== PANEL_TYPES.TRACE
) {
operatorsByDataSource = operatorsByDataSource.filter(
(operator) => operator.value !== StringOperators.NOOP,
);

View File

@ -1,3 +1,4 @@
import { GetQueryResultsProps } from 'store/actions/dashboard/getQueryResults';
import {
MapData,
MapQueryDataToApiResult,
@ -6,6 +7,7 @@ import {
export const mapQueryDataToApi = <Data extends MapData, Key extends keyof Data>(
data: Data[],
nameField: Key,
tableParams?: GetQueryResultsProps['tableParams'],
): MapQueryDataToApiResult<Record<string, Data>> => {
const newLegendMap: Record<string, string> = {};
@ -14,6 +16,10 @@ export const mapQueryDataToApi = <Data extends MapData, Key extends keyof Data>(
...acc,
[query[nameField] as string]: {
...query,
...tableParams?.pagination,
...(tableParams?.selectColumns
? { selectColumns: tableParams?.selectColumns }
: null),
},
};

View File

@ -5,7 +5,7 @@ import { QueryTableProps } from 'container/QueryTable/QueryTable.intefaces';
import { toCapitalize } from 'lib/toCapitalize';
import { ReactNode } from 'react';
import { IBuilderQuery, Query } from 'types/api/queryBuilder/queryBuilderData';
import { QueryDataV3, SeriesItem } from 'types/api/widgets/getQuery';
import { ListItem, QueryDataV3, SeriesItem } from 'types/api/widgets/getQuery';
import { v4 as uuid } from 'uuid';
type CreateTableDataFromQueryParams = Pick<
@ -47,6 +47,10 @@ type GetDynamicColumns = (
query: Query,
) => DynamicColumns;
type ListItemData = ListItem['data'];
type ListItemKey = keyof ListItemData;
type SeriesItemLabels = SeriesItem['labels'];
const isFormula = (queryName: string): boolean =>
FORMULA_REGEXP.test(queryName);
@ -72,57 +76,77 @@ const prepareColumnTitle = (title: string): string => {
return toCapitalize(title);
};
const createLabels = <T extends ListItemData | SeriesItemLabels>(
labels: T,
label: keyof T,
dynamicColumns: DynamicColumns,
): void => {
if (isColumnExist(label as string, dynamicColumns)) return;
if (isFormula(label as string)) return;
const labelValue = labels[label];
const isNumber = !Number.isNaN(parseFloat(String(labelValue)));
const fieldObj: DynamicColumn = {
key: label as string,
data: [],
type: 'field',
sortable: isNumber,
};
dynamicColumns.push(fieldObj);
};
const getDynamicColumns: GetDynamicColumns = (queryTableData, query) => {
const dynamicColumns: DynamicColumns = [];
queryTableData.forEach((currentQuery) => {
if (!currentQuery.series) return;
if (!isColumnExist('timestamp', dynamicColumns)) {
dynamicColumns.push({
key: 'timestamp',
data: [],
type: 'field',
sortable: true,
if (currentQuery.list) {
currentQuery.list.forEach((listItem) => {
Object.keys(listItem.data).forEach((label) => {
createLabels<ListItemData>(
listItem.data,
label as ListItemKey,
dynamicColumns,
);
});
});
}
currentQuery.series.forEach((seria) => {
Object.keys(seria.labels).forEach((label) => {
if (isColumnExist(label, dynamicColumns)) return;
if (isFormula(label)) return;
const labelValue = seria.labels[label];
const isNumber = !Number.isNaN(parseFloat(labelValue));
const fieldObj: DynamicColumn = {
key: label,
if (currentQuery.series) {
if (!isColumnExist('timestamp', dynamicColumns)) {
dynamicColumns.push({
key: 'timestamp',
data: [],
type: 'field',
sortable: isNumber,
};
sortable: true,
});
}
dynamicColumns.push(fieldObj);
currentQuery.series.forEach((seria) => {
Object.keys(seria.labels).forEach((label) => {
createLabels<SeriesItemLabels>(seria.labels, label, dynamicColumns);
});
});
});
if (!isFormula(currentQuery.queryName)) {
const builderQuery = query.builder.queryData.find(
(q) => q.queryName === currentQuery.queryName,
);
if (!isFormula(currentQuery.queryName)) {
const builderQuery = query.builder.queryData.find(
(q) => q.queryName === currentQuery.queryName,
);
const operator = builderQuery ? builderQuery.aggregateOperator : '';
const operator = builderQuery ? builderQuery.aggregateOperator : '';
if (isColumnExist(operator, dynamicColumns)) return;
if (isColumnExist(operator, dynamicColumns)) return;
const operatorColumn: DynamicColumn = {
key: operator,
data: [],
type: 'operator',
sortable: true,
};
dynamicColumns.push(operatorColumn);
const operatorColumn: DynamicColumn = {
key: operator,
data: [],
type: 'operator',
sortable: true,
};
dynamicColumns.push(operatorColumn);
}
}
});
@ -194,22 +218,47 @@ const fillDataFromSeria = (
});
};
const fillDataFromList = (
listItem: ListItem,
columns: DynamicColumns,
): void => {
columns.forEach((column) => {
if (isFormula(column.key as string)) return;
Object.keys(listItem.data).forEach((label) => {
if (column.key === label) {
if (listItem.data[label as ListItemKey]) {
column.data.push(listItem.data[label as ListItemKey] as string | number);
} else {
column.data.push('N/A');
}
}
});
});
};
const fillColumnsData: FillColumnData = (queryTableData, cols, query) => {
const fields = cols.filter((item) => item.type === 'field');
const operators = cols.filter((item) => item.type === 'operator');
const resultColumns = [...fields, ...operators];
queryTableData.forEach((currentQuery) => {
if (!currentQuery.series) return;
const currentOperator = getQueryOperator(
query.builder.queryData,
currentQuery.queryName,
);
currentQuery.series.forEach((seria) => {
fillDataFromSeria(seria, resultColumns, currentOperator);
});
if (currentQuery.series) {
currentQuery.series.forEach((seria) => {
fillDataFromSeria(seria, resultColumns, currentOperator);
});
}
if (currentQuery.list) {
currentQuery.list.forEach((listItem) => {
fillDataFromList(listItem, resultColumns);
});
}
});
const rowsLength = resultColumns.length > 0 ? resultColumns[0].data.length : 0;

View File

@ -16,7 +16,7 @@ import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
import { useNotifications } from 'hooks/useNotifications';
import history from 'lib/history';
import { useCallback, useMemo } from 'react';
import { useCallback, useEffect, useMemo } from 'react';
import { generatePath } from 'react-router-dom';
import { Dashboard } from 'types/api/dashboard/getAll';
import { DataSource } from 'types/common/queryBuilder';
@ -34,19 +34,38 @@ function TracesExplorer(): JSX.Element {
redirectWithQueryBuilderData,
} = useQueryBuilder();
const tabsItems = getTabsItems();
const currentTab = panelType || PANEL_TYPES.TIME_SERIES;
const currentTab = panelType || PANEL_TYPES.LIST;
const isMultipleQueries = useMemo(
() =>
currentQuery.builder.queryData.length > 1 ||
currentQuery.builder.queryFormulas.length > 0,
[currentQuery],
);
const defaultQuery = useMemo(
() =>
updateAllQueriesOperators(
initialQueriesMap.traces,
PANEL_TYPES.TIME_SERIES,
PANEL_TYPES.LIST,
DataSource.TRACES,
),
[updateAllQueriesOperators],
);
const isGroupByExist = useMemo(() => {
const groupByCount: number = currentQuery.builder.queryData.reduce<number>(
(acc, query) => acc + query.groupBy.length,
0,
);
return groupByCount > 0;
}, [currentQuery]);
const tabsItems = getTabsItems({
isListViewDisabled: isMultipleQueries || isGroupByExist,
});
const exportDefaultQuery = useMemo(
() =>
updateAllQueriesOperators(
@ -114,6 +133,17 @@ function TracesExplorer(): JSX.Element {
useShareBuilderUrl(defaultQuery);
useEffect(() => {
const shouldChangeView = isMultipleQueries || isGroupByExist;
if (
(currentTab === PANEL_TYPES.LIST || currentTab === PANEL_TYPES.TRACE) &&
shouldChangeView
) {
handleTabChange(PANEL_TYPES.TIME_SERIES);
}
}, [currentTab, isMultipleQueries, isGroupByExist, handleTabChange]);
return (
<>
<QuerySection />

View File

@ -1,17 +1,25 @@
import { TabsProps } from 'antd';
import { PANEL_TYPES } from 'constants/queryBuilder';
import TimeSeriesView from 'container/TimeSeriesView';
import TracesView from 'container/TracesExplorer/TracesView';
import { DataSource } from 'types/common/queryBuilder';
export const getTabsItems = (): TabsProps['items'] => [
interface GetTabsItemsProps {
isListViewDisabled: boolean;
}
export const getTabsItems = ({
isListViewDisabled,
}: GetTabsItemsProps): TabsProps['items'] => [
{
label: 'Traces',
key: PANEL_TYPES.TRACE,
children: <TracesView />,
disabled: isListViewDisabled,
},
{
label: 'Time Series',
key: PANEL_TYPES.TIME_SERIES,
children: <TimeSeriesView dataSource={DataSource.TRACES} />,
},
{
label: 'Traces',
key: PANEL_TYPES.TRACE,
children: <div>Traces tab</div>,
},
];

View File

@ -16,12 +16,14 @@ import { SuccessResponse } from 'types/api';
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { EQueryType } from 'types/common/dashboard';
import { Pagination } from 'hooks/queryPagination';
export async function GetMetricQueryRange({
query,
globalSelectedInterval,
graphType,
selectedTime,
tableParams,
variables = {},
params = {},
}: GetQueryResultsProps): Promise<SuccessResponse<MetricRangePayloadProps>> {
@ -38,8 +40,9 @@ export async function GetMetricQueryRange({
switch (query.queryType) {
case EQueryType.QUERY_BUILDER: {
const { queryData: data, queryFormulas } = query.builder;
const currentQueryData = mapQueryDataToApi(data, 'queryName');
const currentQueryData = mapQueryDataToApi(data, 'queryName', tableParams);
const currentFormulas = mapQueryDataToApi(queryFormulas, 'queryName');
const builderQueries = {
...currentQueryData.data,
...currentFormulas.data,
@ -140,4 +143,8 @@ export interface GetQueryResultsProps {
globalSelectedInterval: Time;
variables?: Record<string, unknown>;
params?: Record<string, unknown>;
tableParams?: {
pagination?: Pagination;
selectColumns?: any;
};
}

View File

@ -5,7 +5,7 @@ export interface PayloadProps {
result: QueryData[];
}
type ListItem = { timestamp: string; data: Omit<ILog, 'timestamp'> };
export type ListItem = { timestamp: string; data: Omit<ILog, 'timestamp'> };
export interface QueryData {
metric: {

View File

@ -18,6 +18,7 @@ export type HandleChangeQueryData = <
export type UseQueryOperations = (
params: UseQueryOperationsParams,
) => {
isTracePanelType: boolean;
isMetricsDataSource: boolean;
operators: SelectOption<string, string>[];
listOfAdditionalFilters: string[];

View File

@ -143,8 +143,8 @@ export type PanelTypeKeys =
| 'VALUE'
| 'TABLE'
| 'LIST'
| 'EMPTY_WIDGET'
| 'TRACE';
| 'TRACE'
| 'EMPTY_WIDGET';
export type ReduceOperators = 'last' | 'sum' | 'avg' | 'max' | 'min';