mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-14 06:26:03 +08:00
feat: add the list view for the traces explorer (#2947)
* feat: add dynamic table based on query * feat: add the list view for the traces explorer * fix: fix the options menu * feat: update the list view columns config for the traces explorer * feat: fix columns for the list view for the traces explorer page * feat: update customization columns for the list view from the traces explorer * feat: add error msg for the list view, fix creating data for the table --------- 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:
parent
2722538e82
commit
5540692500
@ -1,6 +1,7 @@
|
|||||||
import { RadioChangeEvent } from 'antd';
|
import { RadioChangeEvent } from 'antd';
|
||||||
import { getAggregateKeys } from 'api/queryBuilder/getAttributeKeys';
|
import { getAggregateKeys } from 'api/queryBuilder/getAttributeKeys';
|
||||||
import { QueryBuilderKeys } from 'constants/queryBuilder';
|
import { QueryBuilderKeys } from 'constants/queryBuilder';
|
||||||
|
import { useNotifications } from 'hooks/useNotifications';
|
||||||
import useUrlQueryData from 'hooks/useUrlQueryData';
|
import useUrlQueryData from 'hooks/useUrlQueryData';
|
||||||
import { useCallback, useEffect, useMemo } from 'react';
|
import { useCallback, useEffect, useMemo } from 'react';
|
||||||
import { useQuery } from 'react-query';
|
import { useQuery } from 'react-query';
|
||||||
@ -28,6 +29,8 @@ const useOptionsMenu = ({
|
|||||||
aggregateOperator,
|
aggregateOperator,
|
||||||
initialOptions = {},
|
initialOptions = {},
|
||||||
}: UseOptionsMenuProps): UseOptionsMenu => {
|
}: UseOptionsMenuProps): UseOptionsMenu => {
|
||||||
|
const { notifications } = useNotifications();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
query: optionsQuery,
|
query: optionsQuery,
|
||||||
queryData: optionsQueryData,
|
queryData: optionsQueryData,
|
||||||
@ -91,14 +94,22 @@ const useOptionsMenu = ({
|
|||||||
|
|
||||||
const handleRemoveSelectedColumn = useCallback(
|
const handleRemoveSelectedColumn = useCallback(
|
||||||
(columnKey: string) => {
|
(columnKey: string) => {
|
||||||
redirectWithOptionsData({
|
const newSelectedColumns = optionsQueryData?.selectColumns?.filter(
|
||||||
...defaultOptionsQuery,
|
({ id }) => id !== columnKey,
|
||||||
selectColumns: optionsQueryData?.selectColumns?.filter(
|
);
|
||||||
({ id }) => id !== columnKey,
|
|
||||||
),
|
if (!newSelectedColumns.length) {
|
||||||
});
|
notifications.error({
|
||||||
|
message: 'There must be at least one selected column',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
redirectWithOptionsData({
|
||||||
|
...defaultOptionsQuery,
|
||||||
|
selectColumns: newSelectedColumns,
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[optionsQueryData, redirectWithOptionsData],
|
[optionsQueryData, notifications, redirectWithOptionsData],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleFormatChange = useCallback(
|
const handleFormatChange = useCallback(
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
import { initialQueriesMap } from 'constants/queryBuilder';
|
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
|
import { PANEL_TYPES_QUERY } from 'constants/queryBuilderQueryNames';
|
||||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||||
|
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
|
||||||
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
||||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
|
import useUrlQueryData from 'hooks/useUrlQueryData';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
import { DataSource } from 'types/common/queryBuilder';
|
import { DataSource } from 'types/common/queryBuilder';
|
||||||
@ -19,10 +22,15 @@ function TimeSeriesViewContainer({
|
|||||||
GlobalReducer
|
GlobalReducer
|
||||||
>((state) => state.globalTime);
|
>((state) => state.globalTime);
|
||||||
|
|
||||||
|
const { queryData: panelTypeParam } = useUrlQueryData<GRAPH_TYPES>(
|
||||||
|
PANEL_TYPES_QUERY,
|
||||||
|
PANEL_TYPES.TIME_SERIES,
|
||||||
|
);
|
||||||
|
|
||||||
const { data, isLoading, isError } = useGetQueryRange(
|
const { data, isLoading, isError } = useGetQueryRange(
|
||||||
{
|
{
|
||||||
query: stagedQuery || initialQueriesMap[dataSource],
|
query: stagedQuery || initialQueriesMap[dataSource],
|
||||||
graphType: 'graph',
|
graphType: panelTypeParam,
|
||||||
selectedTime: 'GLOBAL_TIME',
|
selectedTime: 'GLOBAL_TIME',
|
||||||
globalSelectedInterval: globalSelectedTime,
|
globalSelectedInterval: globalSelectedTime,
|
||||||
params: {
|
params: {
|
||||||
@ -37,7 +45,7 @@ function TimeSeriesViewContainer({
|
|||||||
minTime,
|
minTime,
|
||||||
stagedQuery,
|
stagedQuery,
|
||||||
],
|
],
|
||||||
enabled: !!stagedQuery,
|
enabled: !!stagedQuery && panelTypeParam === PANEL_TYPES.TIME_SERIES,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
11
frontend/src/container/TracesExplorer/ListView/configs.tsx
Normal file
11
frontend/src/container/TracesExplorer/ListView/configs.tsx
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { DEFAULT_PER_PAGE_OPTIONS } from 'hooks/queryPagination';
|
||||||
|
|
||||||
|
export const defaultSelectedColumns: string[] = [
|
||||||
|
'name',
|
||||||
|
'serviceName',
|
||||||
|
'responseStatusCode',
|
||||||
|
'httpMethod',
|
||||||
|
'durationNano',
|
||||||
|
];
|
||||||
|
|
||||||
|
export const PER_PAGE_OPTIONS: number[] = [10, ...DEFAULT_PER_PAGE_OPTIONS];
|
133
frontend/src/container/TracesExplorer/ListView/index.tsx
Normal file
133
frontend/src/container/TracesExplorer/ListView/index.tsx
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
import { ColumnsType } from 'antd/es/table';
|
||||||
|
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
|
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||||
|
import { useOptionsMenu } from 'container/OptionsMenu';
|
||||||
|
import { QueryTable } from 'container/QueryTable';
|
||||||
|
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 history from 'lib/history';
|
||||||
|
import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
||||||
|
import { HTMLAttributes, memo, useCallback, useMemo } from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { AppState } from 'store/reducers';
|
||||||
|
import { DataSource } from 'types/common/queryBuilder';
|
||||||
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
|
|
||||||
|
import TraceExplorerControls from '../Controls';
|
||||||
|
import { defaultSelectedColumns, PER_PAGE_OPTIONS } from './configs';
|
||||||
|
import { Container, ErrorText, tableStyles } from './styles';
|
||||||
|
import { getTraceLink, modifyColumns, transformDataWithDate } from './utils';
|
||||||
|
|
||||||
|
function ListView(): JSX.Element {
|
||||||
|
const { stagedQuery, panelType } = useQueryBuilder();
|
||||||
|
|
||||||
|
const { selectedTime: globalSelectedTime, maxTime, minTime } = useSelector<
|
||||||
|
AppState,
|
||||||
|
GlobalReducer
|
||||||
|
>((state) => state.globalTime);
|
||||||
|
|
||||||
|
const { options, config } = useOptionsMenu({
|
||||||
|
dataSource: DataSource.TRACES,
|
||||||
|
aggregateOperator: 'count',
|
||||||
|
initialOptions: {
|
||||||
|
selectColumns: defaultSelectedColumns,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { queryData: paginationQueryData } = useUrlQueryData<Pagination>(
|
||||||
|
URL_PAGINATION,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { data, isFetching, isError } = useGetQueryRange(
|
||||||
|
{
|
||||||
|
query: stagedQuery || initialQueriesMap.traces,
|
||||||
|
graphType: panelType || PANEL_TYPES.LIST,
|
||||||
|
selectedTime: 'GLOBAL_TIME',
|
||||||
|
globalSelectedInterval: globalSelectedTime,
|
||||||
|
params: {
|
||||||
|
dataSource: 'traces',
|
||||||
|
},
|
||||||
|
tableParams: {
|
||||||
|
pagination: paginationQueryData,
|
||||||
|
selectColumns: options?.selectColumns,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
queryKey: [
|
||||||
|
REACT_QUERY_KEY.GET_QUERY_RANGE,
|
||||||
|
globalSelectedTime,
|
||||||
|
maxTime,
|
||||||
|
minTime,
|
||||||
|
stagedQuery,
|
||||||
|
panelType,
|
||||||
|
paginationQueryData,
|
||||||
|
options?.selectColumns,
|
||||||
|
],
|
||||||
|
enabled: !!stagedQuery && panelType === PANEL_TYPES.LIST,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const dataLength =
|
||||||
|
data?.payload?.data?.newResult?.data?.result[0]?.list?.length;
|
||||||
|
const totalCount = useMemo(() => dataLength || 0, [dataLength]);
|
||||||
|
|
||||||
|
const queryTableDataResult = data?.payload.data.newResult.data.result;
|
||||||
|
const queryTableData = useMemo(() => queryTableDataResult || [], [
|
||||||
|
queryTableDataResult,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const transformedQueryTableData = useMemo(
|
||||||
|
() => transformDataWithDate(queryTableData),
|
||||||
|
[queryTableData],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleModifyColumns = useCallback(
|
||||||
|
(columns: ColumnsType<RowData>) =>
|
||||||
|
modifyColumns(columns, options?.selectColumns || []),
|
||||||
|
[options?.selectColumns],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleRow = useCallback(
|
||||||
|
(record: RowData): HTMLAttributes<RowData> => ({
|
||||||
|
onClick: (event): void => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
if (event.metaKey || event.ctrlKey) {
|
||||||
|
window.open(getTraceLink(record), '_blank');
|
||||||
|
} else {
|
||||||
|
history.push(getTraceLink(record));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<TraceExplorerControls
|
||||||
|
isLoading={isFetching}
|
||||||
|
totalCount={totalCount}
|
||||||
|
config={config}
|
||||||
|
perPageOptions={PER_PAGE_OPTIONS}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{isError && <ErrorText>{data?.error || 'Something went wrong'}</ErrorText>}
|
||||||
|
|
||||||
|
{!isError && (
|
||||||
|
<QueryTable
|
||||||
|
query={stagedQuery || initialQueriesMap.traces}
|
||||||
|
queryTableData={transformedQueryTableData}
|
||||||
|
modifyColumns={handleModifyColumns}
|
||||||
|
loading={isFetching}
|
||||||
|
pagination={false}
|
||||||
|
style={tableStyles}
|
||||||
|
onRow={handleRow}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(ListView);
|
17
frontend/src/container/TracesExplorer/ListView/styles.ts
Normal file
17
frontend/src/container/TracesExplorer/ListView/styles.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { Typography } from 'antd';
|
||||||
|
import { CSSProperties } from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
export const tableStyles: CSSProperties = {
|
||||||
|
cursor: 'pointer',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Container = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ErrorText = styled(Typography)`
|
||||||
|
text-align: center;
|
||||||
|
`;
|
97
frontend/src/container/TracesExplorer/ListView/utils.tsx
Normal file
97
frontend/src/container/TracesExplorer/ListView/utils.tsx
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import { Tag } from 'antd';
|
||||||
|
import { ColumnsType } from 'antd/es/table';
|
||||||
|
import Typography from 'antd/es/typography/Typography';
|
||||||
|
import ROUTES from 'constants/routes';
|
||||||
|
import { getMs } from 'container/Trace/Filters/Panel/PanelBody/Duration/util';
|
||||||
|
import { formUrlParams } from 'container/TraceDetail/utils';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
||||||
|
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||||
|
import { QueryDataV3 } from 'types/api/widgets/getQuery';
|
||||||
|
|
||||||
|
export const transformDataWithDate = (data: QueryDataV3[]): QueryDataV3[] =>
|
||||||
|
data.map((query) => ({
|
||||||
|
...query,
|
||||||
|
list:
|
||||||
|
query?.list?.map((listItem) => ({
|
||||||
|
...listItem,
|
||||||
|
data: {
|
||||||
|
...listItem?.data,
|
||||||
|
date: listItem?.timestamp,
|
||||||
|
},
|
||||||
|
})) || null,
|
||||||
|
}));
|
||||||
|
|
||||||
|
export const modifyColumns = (
|
||||||
|
columns: ColumnsType<RowData>,
|
||||||
|
selectedColumns: BaseAutocompleteData[],
|
||||||
|
): ColumnsType<RowData> => {
|
||||||
|
const initialColumns = columns.filter(({ key }) => {
|
||||||
|
let isValidColumn = true;
|
||||||
|
|
||||||
|
const checkIsExistColumnByKey = (attributeKey: string): boolean =>
|
||||||
|
!selectedColumns.find(({ key }) => key === attributeKey) &&
|
||||||
|
attributeKey === key;
|
||||||
|
|
||||||
|
const isSelectedSpanId = checkIsExistColumnByKey('spanID');
|
||||||
|
const isSelectedTraceId = checkIsExistColumnByKey('traceID');
|
||||||
|
|
||||||
|
if (isSelectedSpanId || isSelectedTraceId || key === 'date')
|
||||||
|
isValidColumn = false;
|
||||||
|
|
||||||
|
return isValidColumn;
|
||||||
|
});
|
||||||
|
|
||||||
|
const dateColumn = columns.find(({ key }) => key === 'date');
|
||||||
|
|
||||||
|
if (dateColumn) {
|
||||||
|
initialColumns.unshift(dateColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return initialColumns.map((column) => {
|
||||||
|
const key = column.key as string;
|
||||||
|
|
||||||
|
const getHttpMethodOrStatus = (value: string): JSX.Element => {
|
||||||
|
if (value === 'N/A') {
|
||||||
|
return <Typography>{value}</Typography>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Tag color="magenta">{value}</Tag>;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (key === 'durationNano') {
|
||||||
|
return {
|
||||||
|
...column,
|
||||||
|
render: (duration: string): JSX.Element => (
|
||||||
|
<Typography>{getMs(duration)}ms</Typography>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key === 'httpMethod' || key === 'responseStatusCode') {
|
||||||
|
return {
|
||||||
|
...column,
|
||||||
|
render: getHttpMethodOrStatus,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key === 'date') {
|
||||||
|
return {
|
||||||
|
...column,
|
||||||
|
render: (date: string): JSX.Element => {
|
||||||
|
const day = dayjs(date);
|
||||||
|
return <Typography>{day.format('YYYY/MM/DD HH:mm:ss')}</Typography>;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return column;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getTraceLink = (record: RowData): string =>
|
||||||
|
`${ROUTES.TRACE}/${record.traceID}${formUrlParams({
|
||||||
|
spanId: record.spanID,
|
||||||
|
levelUp: 0,
|
||||||
|
levelDown: 0,
|
||||||
|
})}`;
|
@ -6,7 +6,7 @@ import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
|||||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
import { Pagination, URL_PAGINATION } from 'hooks/queryPagination';
|
import { Pagination, URL_PAGINATION } from 'hooks/queryPagination';
|
||||||
import useUrlQueryData from 'hooks/useUrlQueryData';
|
import useUrlQueryData from 'hooks/useUrlQueryData';
|
||||||
import { useMemo } from 'react';
|
import { memo, useMemo } from 'react';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
@ -84,4 +84,4 @@ function TracesView(): JSX.Element {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TracesView;
|
export default memo(TracesView);
|
||||||
|
@ -23,7 +23,7 @@ type DynamicColumn = {
|
|||||||
key: keyof RowData;
|
key: keyof RowData;
|
||||||
data: (string | number)[];
|
data: (string | number)[];
|
||||||
type: 'field' | 'operator';
|
type: 'field' | 'operator';
|
||||||
sortable: boolean;
|
// sortable: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type DynamicColumns = DynamicColumn[];
|
type DynamicColumns = DynamicColumn[];
|
||||||
@ -91,15 +91,15 @@ const createLabels = <T extends ListItemData | SeriesItemLabels>(
|
|||||||
): void => {
|
): void => {
|
||||||
if (isColumnExist(label as string, dynamicColumns)) return;
|
if (isColumnExist(label as string, dynamicColumns)) return;
|
||||||
|
|
||||||
const labelValue = labels[label];
|
// const labelValue = labels[label];
|
||||||
|
|
||||||
const isNumber = !Number.isNaN(parseFloat(String(labelValue)));
|
// const isNumber = !Number.isNaN(parseFloat(String(labelValue)));
|
||||||
|
|
||||||
const fieldObj: DynamicColumn = {
|
const fieldObj: DynamicColumn = {
|
||||||
key: label as string,
|
key: label as string,
|
||||||
data: [],
|
data: [],
|
||||||
type: 'field',
|
type: 'field',
|
||||||
sortable: isNumber,
|
// sortable: isNumber,
|
||||||
};
|
};
|
||||||
|
|
||||||
dynamicColumns.push(fieldObj);
|
dynamicColumns.push(fieldObj);
|
||||||
@ -127,7 +127,7 @@ const getDynamicColumns: GetDynamicColumns = (queryTableData, query) => {
|
|||||||
key: 'timestamp',
|
key: 'timestamp',
|
||||||
data: [],
|
data: [],
|
||||||
type: 'field',
|
type: 'field',
|
||||||
sortable: true,
|
// sortable: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +148,7 @@ const getDynamicColumns: GetDynamicColumns = (queryTableData, query) => {
|
|||||||
key: operator,
|
key: operator,
|
||||||
data: [],
|
data: [],
|
||||||
type: 'operator',
|
type: 'operator',
|
||||||
sortable: true,
|
// sortable: true,
|
||||||
};
|
};
|
||||||
dynamicColumns.push(operatorColumn);
|
dynamicColumns.push(operatorColumn);
|
||||||
}
|
}
|
||||||
@ -220,8 +220,8 @@ const fillDataFromList = (
|
|||||||
|
|
||||||
Object.keys(listItem.data).forEach((label) => {
|
Object.keys(listItem.data).forEach((label) => {
|
||||||
if (column.key === label) {
|
if (column.key === label) {
|
||||||
if (listItem.data[label as ListItemKey]) {
|
if (listItem.data[label as ListItemKey] !== '') {
|
||||||
column.data.push(listItem.data[label as ListItemKey] as string | number);
|
column.data.push(listItem.data[label as ListItemKey].toString());
|
||||||
} else {
|
} else {
|
||||||
column.data.push('N/A');
|
column.data.push('N/A');
|
||||||
}
|
}
|
||||||
@ -291,10 +291,10 @@ const generateTableColumns = (
|
|||||||
dataIndex: item.key,
|
dataIndex: item.key,
|
||||||
key: item.key,
|
key: item.key,
|
||||||
title: prepareColumnTitle(item.key as string),
|
title: prepareColumnTitle(item.key as string),
|
||||||
sorter: item.sortable
|
// sorter: item.sortable
|
||||||
? (a: RowData, b: RowData): number =>
|
// ? (a: RowData, b: RowData): number =>
|
||||||
(a[item.key] as number) - (b[item.key] as number)
|
// (a[item.key] as number) - (b[item.key] as number)
|
||||||
: false,
|
// : false,
|
||||||
};
|
};
|
||||||
|
|
||||||
return [...acc, column];
|
return [...acc, column];
|
||||||
|
@ -43,6 +43,15 @@ function TracesExplorer(): JSX.Element {
|
|||||||
[currentQuery],
|
[currentQuery],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isGroupByExist = useMemo(() => {
|
||||||
|
const groupByCount: number = currentQuery.builder.queryData.reduce<number>(
|
||||||
|
(acc, query) => acc + query.groupBy.length,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
|
||||||
|
return groupByCount > 0;
|
||||||
|
}, [currentQuery]);
|
||||||
|
|
||||||
const defaultQuery = useMemo(
|
const defaultQuery = useMemo(
|
||||||
() =>
|
() =>
|
||||||
updateAllQueriesOperators(
|
updateAllQueriesOperators(
|
||||||
@ -53,15 +62,6 @@ function TracesExplorer(): JSX.Element {
|
|||||||
[updateAllQueriesOperators],
|
[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({
|
const tabsItems = getTabsItems({
|
||||||
isListViewDisabled: isMultipleQueries || isGroupByExist,
|
isListViewDisabled: isMultipleQueries || isGroupByExist,
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { TabsProps } from 'antd';
|
import { TabsProps } from 'antd';
|
||||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import TimeSeriesView from 'container/TimeSeriesView';
|
import TimeSeriesView from 'container/TimeSeriesView';
|
||||||
|
import ListView from 'container/TracesExplorer/ListView';
|
||||||
import TracesView from 'container/TracesExplorer/TracesView';
|
import TracesView from 'container/TracesExplorer/TracesView';
|
||||||
import { DataSource } from 'types/common/queryBuilder';
|
import { DataSource } from 'types/common/queryBuilder';
|
||||||
|
|
||||||
@ -11,6 +12,12 @@ interface GetTabsItemsProps {
|
|||||||
export const getTabsItems = ({
|
export const getTabsItems = ({
|
||||||
isListViewDisabled,
|
isListViewDisabled,
|
||||||
}: GetTabsItemsProps): TabsProps['items'] => [
|
}: GetTabsItemsProps): TabsProps['items'] => [
|
||||||
|
{
|
||||||
|
label: 'List View',
|
||||||
|
key: PANEL_TYPES.LIST,
|
||||||
|
children: <ListView />,
|
||||||
|
disabled: isListViewDisabled,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'Traces',
|
label: 'Traces',
|
||||||
key: PANEL_TYPES.TRACE,
|
key: PANEL_TYPES.TRACE,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export interface ILog {
|
export interface ILog {
|
||||||
|
date: string;
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
id: string;
|
id: string;
|
||||||
traceId: string;
|
traceId: string;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user