Compare commits
9 Commits
main
...
v0.75.0-pa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c0c922faa | ||
|
|
6aec0d5c9b | ||
|
|
8c994ee751 | ||
|
|
a0a7b82e55 | ||
|
|
ce49c774f1 | ||
|
|
65d0041672 | ||
|
|
31d59cc3c6 | ||
|
|
81c8ba1978 | ||
|
|
14a0a372c2 |
@@ -8,19 +8,13 @@ import { DEFAULT_ENTITY_VERSION } from 'constants/app';
|
||||
import LogsError from 'container/LogsError/LogsError';
|
||||
import { LogsLoading } from 'container/LogsLoading/LogsLoading';
|
||||
import { FontSize } from 'container/OptionsMenu/types';
|
||||
import { ORDERBY_FILTERS } from 'container/QueryBuilder/filters/OrderByFilter/config';
|
||||
import { useHandleLogsPagination } from 'hooks/infraMonitoring/useHandleLogsPagination';
|
||||
import { GetMetricQueryRange } from 'lib/dashboard/getQueryResults';
|
||||
import { isEqual } from 'lodash-es';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { useQuery } from 'react-query';
|
||||
import { Virtuoso } from 'react-virtuoso';
|
||||
import { ILog } from 'types/api/logs/log';
|
||||
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import {
|
||||
IBuilderQuery,
|
||||
TagFilterItem,
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { v4 } from 'uuid';
|
||||
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
import { getHostLogsQueryPayload } from './constants';
|
||||
import NoLogsContainer from './NoLogsContainer';
|
||||
@@ -30,51 +24,30 @@ interface Props {
|
||||
startTime: number;
|
||||
endTime: number;
|
||||
};
|
||||
handleChangeLogFilters: (filters: IBuilderQuery['filters']) => void;
|
||||
filters: IBuilderQuery['filters'];
|
||||
}
|
||||
|
||||
function HostMetricsLogs({
|
||||
timeRange,
|
||||
handleChangeLogFilters,
|
||||
filters,
|
||||
}: Props): JSX.Element {
|
||||
const [logs, setLogs] = useState<ILog[]>([]);
|
||||
const [hasReachedEndOfLogs, setHasReachedEndOfLogs] = useState(false);
|
||||
const [restFilters, setRestFilters] = useState<TagFilterItem[]>([]);
|
||||
const [resetLogsList, setResetLogsList] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
const newRestFilters = filters.items.filter(
|
||||
(item) => item.key?.key !== 'id' && item.key?.key !== 'host.name',
|
||||
);
|
||||
|
||||
const areFiltersSame = isEqual(restFilters, newRestFilters);
|
||||
|
||||
if (!areFiltersSame) {
|
||||
setResetLogsList(true);
|
||||
}
|
||||
|
||||
setRestFilters(newRestFilters);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [filters]);
|
||||
|
||||
const queryPayload = useMemo(() => {
|
||||
const basePayload = getHostLogsQueryPayload(
|
||||
timeRange.startTime,
|
||||
timeRange.endTime,
|
||||
filters,
|
||||
);
|
||||
|
||||
basePayload.query.builder.queryData[0].pageSize = 100;
|
||||
basePayload.query.builder.queryData[0].orderBy = [
|
||||
{ columnName: 'timestamp', order: ORDERBY_FILTERS.DESC },
|
||||
];
|
||||
|
||||
return basePayload;
|
||||
}, [timeRange.startTime, timeRange.endTime, filters]);
|
||||
|
||||
const [isPaginating, setIsPaginating] = useState(false);
|
||||
function HostMetricsLogs({ timeRange, filters }: Props): JSX.Element {
|
||||
const basePayload = getHostLogsQueryPayload(
|
||||
timeRange.startTime,
|
||||
timeRange.endTime,
|
||||
filters,
|
||||
);
|
||||
const {
|
||||
logs,
|
||||
hasReachedEndOfLogs,
|
||||
isPaginating,
|
||||
currentPage,
|
||||
setIsPaginating,
|
||||
handleNewData,
|
||||
loadMoreLogs,
|
||||
queryPayload,
|
||||
} = useHandleLogsPagination({
|
||||
timeRange,
|
||||
filters,
|
||||
excludeFilterKeys: ['host.name'],
|
||||
basePayload,
|
||||
});
|
||||
|
||||
const { data, isLoading, isFetching, isError } = useQuery({
|
||||
queryKey: [
|
||||
@@ -82,6 +55,7 @@ function HostMetricsLogs({
|
||||
timeRange.startTime,
|
||||
timeRange.endTime,
|
||||
filters,
|
||||
currentPage,
|
||||
],
|
||||
queryFn: () => GetMetricQueryRange(queryPayload, DEFAULT_ENTITY_VERSION),
|
||||
enabled: !!queryPayload,
|
||||
@@ -90,33 +64,13 @@ function HostMetricsLogs({
|
||||
|
||||
useEffect(() => {
|
||||
if (data?.payload?.data?.newResult?.data?.result) {
|
||||
const currentData = data.payload.data.newResult.data.result;
|
||||
|
||||
if (resetLogsList) {
|
||||
const currentLogs: ILog[] =
|
||||
currentData[0].list?.map((item) => ({
|
||||
...item.data,
|
||||
timestamp: item.timestamp,
|
||||
})) || [];
|
||||
|
||||
setLogs(currentLogs);
|
||||
|
||||
setResetLogsList(false);
|
||||
}
|
||||
|
||||
if (currentData.length > 0 && currentData[0].list) {
|
||||
const currentLogs: ILog[] =
|
||||
currentData[0].list.map((item) => ({
|
||||
...item.data,
|
||||
timestamp: item.timestamp,
|
||||
})) || [];
|
||||
|
||||
setLogs((prev) => [...prev, ...currentLogs]);
|
||||
} else {
|
||||
setHasReachedEndOfLogs(true);
|
||||
}
|
||||
handleNewData(data.payload.data.newResult.data.result);
|
||||
}
|
||||
}, [data, restFilters, isPaginating, resetLogsList]);
|
||||
}, [data, handleNewData]);
|
||||
|
||||
useEffect(() => {
|
||||
setIsPaginating(false);
|
||||
}, [data, setIsPaginating]);
|
||||
|
||||
const getItemContent = useCallback(
|
||||
(_: number, logToRender: ILog): JSX.Element => (
|
||||
@@ -144,39 +98,6 @@ function HostMetricsLogs({
|
||||
[],
|
||||
);
|
||||
|
||||
const loadMoreLogs = useCallback(() => {
|
||||
if (!logs.length) return;
|
||||
|
||||
setIsPaginating(true);
|
||||
const lastLog = logs[logs.length - 1];
|
||||
|
||||
const newItems = [
|
||||
...filters.items.filter((item) => item.key?.key !== 'id'),
|
||||
{
|
||||
id: v4(),
|
||||
key: {
|
||||
key: 'id',
|
||||
type: '',
|
||||
dataType: DataTypes.String,
|
||||
isColumn: true,
|
||||
},
|
||||
op: '<',
|
||||
value: lastLog.id,
|
||||
},
|
||||
];
|
||||
|
||||
const newFilters = {
|
||||
op: 'AND',
|
||||
items: newItems,
|
||||
} as IBuilderQuery['filters'];
|
||||
|
||||
handleChangeLogFilters(newFilters);
|
||||
}, [logs, filters, handleChangeLogFilters]);
|
||||
|
||||
useEffect(() => {
|
||||
setIsPaginating(false);
|
||||
}, [data]);
|
||||
|
||||
const renderFooter = useCallback(
|
||||
(): JSX.Element | null => (
|
||||
// eslint-disable-next-line react/jsx-no-useless-fragment
|
||||
|
||||
@@ -7,6 +7,7 @@ import { DEFAULT_ENTITY_VERSION } from 'constants/app';
|
||||
import { EventContents } from 'container/InfraMonitoringK8s/commonUtils';
|
||||
import { K8sCategory } from 'container/InfraMonitoringK8s/constants';
|
||||
import LoadingContainer from 'container/InfraMonitoringK8s/LoadingContainer';
|
||||
import { INITIAL_PAGE_SIZE } from 'container/LogsContextList/configs';
|
||||
import LogsError from 'container/LogsError/LogsError';
|
||||
import { ORDERBY_FILTERS } from 'container/QueryBuilder/filters/OrderByFilter/config';
|
||||
import QueryBuilderSearch from 'container/QueryBuilder/filters/QueryBuilderSearch';
|
||||
@@ -21,10 +22,8 @@ import { isArray } from 'lodash-es';
|
||||
import { ChevronDown, ChevronLeft, ChevronRight, Loader2 } from 'lucide-react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useQuery } from 'react-query';
|
||||
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import {
|
||||
EntityDetailsEmptyContainer,
|
||||
@@ -123,16 +122,19 @@ export default function Events({
|
||||
filters,
|
||||
);
|
||||
|
||||
basePayload.query.builder.queryData[0].pageSize = 10;
|
||||
basePayload.query.builder.queryData[0].pageSize = INITIAL_PAGE_SIZE;
|
||||
basePayload.query.builder.queryData[0].offset =
|
||||
(page - 1) * INITIAL_PAGE_SIZE;
|
||||
basePayload.query.builder.queryData[0].orderBy = [
|
||||
{ columnName: 'timestamp', order: ORDERBY_FILTERS.DESC },
|
||||
{ columnName: 'id', order: ORDERBY_FILTERS.DESC },
|
||||
];
|
||||
|
||||
return basePayload;
|
||||
}, [timeRange.startTime, timeRange.endTime, filters]);
|
||||
}, [timeRange.startTime, timeRange.endTime, filters, page]);
|
||||
|
||||
const { data: eventsData, isLoading, isFetching, isError } = useQuery({
|
||||
queryKey: [queryKey, timeRange.startTime, timeRange.endTime, filters],
|
||||
queryKey: [queryKey, timeRange.startTime, timeRange.endTime, filters, page],
|
||||
queryFn: () => GetMetricQueryRange(queryPayload, DEFAULT_ENTITY_VERSION),
|
||||
enabled: !!queryPayload,
|
||||
});
|
||||
@@ -189,61 +191,12 @@ export default function Events({
|
||||
|
||||
const handlePrev = (): void => {
|
||||
if (!formattedEntityEvents.length) return;
|
||||
|
||||
setPage(page - 1);
|
||||
|
||||
const firstEvent = formattedEntityEvents[0];
|
||||
|
||||
const newItems = [
|
||||
...filters.items.filter((item) => item.key?.key !== 'id'),
|
||||
{
|
||||
id: v4(),
|
||||
key: {
|
||||
key: 'id',
|
||||
type: '',
|
||||
dataType: DataTypes.String,
|
||||
isColumn: true,
|
||||
},
|
||||
op: '>',
|
||||
value: firstEvent.id,
|
||||
},
|
||||
];
|
||||
|
||||
const newFilters = {
|
||||
op: 'AND',
|
||||
items: newItems,
|
||||
} as IBuilderQuery['filters'];
|
||||
|
||||
handleChangeEventFilters(newFilters);
|
||||
};
|
||||
|
||||
const handleNext = (): void => {
|
||||
if (!formattedEntityEvents.length) return;
|
||||
|
||||
setPage(page + 1);
|
||||
const lastEvent = formattedEntityEvents[formattedEntityEvents.length - 1];
|
||||
|
||||
const newItems = [
|
||||
...filters.items.filter((item) => item.key?.key !== 'id'),
|
||||
{
|
||||
id: v4(),
|
||||
key: {
|
||||
key: 'id',
|
||||
type: '',
|
||||
dataType: DataTypes.String,
|
||||
isColumn: true,
|
||||
},
|
||||
op: '<',
|
||||
value: lastEvent.id,
|
||||
},
|
||||
];
|
||||
|
||||
const newFilters = {
|
||||
op: 'AND',
|
||||
items: newItems,
|
||||
} as IBuilderQuery['filters'];
|
||||
|
||||
handleChangeEventFilters(newFilters);
|
||||
};
|
||||
|
||||
const handleExpandRowIcon = ({
|
||||
|
||||
@@ -9,19 +9,13 @@ import { K8sCategory } from 'container/InfraMonitoringK8s/constants';
|
||||
import LogsError from 'container/LogsError/LogsError';
|
||||
import { LogsLoading } from 'container/LogsLoading/LogsLoading';
|
||||
import { FontSize } from 'container/OptionsMenu/types';
|
||||
import { ORDERBY_FILTERS } from 'container/QueryBuilder/filters/OrderByFilter/config';
|
||||
import { useHandleLogsPagination } from 'hooks/infraMonitoring/useHandleLogsPagination';
|
||||
import { GetMetricQueryRange } from 'lib/dashboard/getQueryResults';
|
||||
import { isEqual } from 'lodash-es';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { useQuery } from 'react-query';
|
||||
import { Virtuoso } from 'react-virtuoso';
|
||||
import { ILog } from 'types/api/logs/log';
|
||||
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import {
|
||||
IBuilderQuery,
|
||||
TagFilterItem,
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { v4 } from 'uuid';
|
||||
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
import {
|
||||
EntityDetailsEmptyContainer,
|
||||
@@ -33,7 +27,6 @@ interface Props {
|
||||
startTime: number;
|
||||
endTime: number;
|
||||
};
|
||||
handleChangeLogFilters: (filters: IBuilderQuery['filters']) => void;
|
||||
filters: IBuilderQuery['filters'];
|
||||
queryKey: string;
|
||||
category: K8sCategory;
|
||||
@@ -42,87 +35,33 @@ interface Props {
|
||||
|
||||
function EntityLogs({
|
||||
timeRange,
|
||||
handleChangeLogFilters,
|
||||
filters,
|
||||
queryKey,
|
||||
category,
|
||||
queryKeyFilters,
|
||||
}: Props): JSX.Element {
|
||||
const [logs, setLogs] = useState<ILog[]>([]);
|
||||
const [hasReachedEndOfLogs, setHasReachedEndOfLogs] = useState(false);
|
||||
const [restFilters, setRestFilters] = useState<TagFilterItem[]>([]);
|
||||
const [resetLogsList, setResetLogsList] = useState<boolean>(false);
|
||||
const basePayload = getEntityEventsOrLogsQueryPayload(
|
||||
timeRange.startTime,
|
||||
timeRange.endTime,
|
||||
filters,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const newRestFilters = filters.items.filter(
|
||||
(item) =>
|
||||
item.key?.key !== 'id' && !queryKeyFilters.includes(item.key?.key ?? ''),
|
||||
);
|
||||
|
||||
const areFiltersSame = isEqual(restFilters, newRestFilters);
|
||||
|
||||
if (!areFiltersSame) {
|
||||
setResetLogsList(true);
|
||||
}
|
||||
|
||||
setRestFilters(newRestFilters);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [filters]);
|
||||
|
||||
const queryPayload = useMemo(() => {
|
||||
const basePayload = getEntityEventsOrLogsQueryPayload(
|
||||
timeRange.startTime,
|
||||
timeRange.endTime,
|
||||
filters,
|
||||
);
|
||||
|
||||
basePayload.query.builder.queryData[0].pageSize = 100;
|
||||
basePayload.query.builder.queryData[0].orderBy = [
|
||||
{ columnName: 'timestamp', order: ORDERBY_FILTERS.DESC },
|
||||
];
|
||||
|
||||
return basePayload;
|
||||
}, [timeRange.startTime, timeRange.endTime, filters]);
|
||||
|
||||
const [isPaginating, setIsPaginating] = useState(false);
|
||||
|
||||
const { data, isLoading, isFetching, isError } = useQuery({
|
||||
queryKey: [queryKey, timeRange.startTime, timeRange.endTime, filters],
|
||||
queryFn: () => GetMetricQueryRange(queryPayload, DEFAULT_ENTITY_VERSION),
|
||||
enabled: !!queryPayload,
|
||||
keepPreviousData: isPaginating,
|
||||
const {
|
||||
logs,
|
||||
hasReachedEndOfLogs,
|
||||
isPaginating,
|
||||
currentPage,
|
||||
setIsPaginating,
|
||||
handleNewData,
|
||||
loadMoreLogs,
|
||||
queryPayload,
|
||||
} = useHandleLogsPagination({
|
||||
timeRange,
|
||||
filters,
|
||||
queryKeyFilters,
|
||||
basePayload,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (data?.payload?.data?.newResult?.data?.result) {
|
||||
const currentData = data.payload.data.newResult.data.result;
|
||||
|
||||
if (resetLogsList) {
|
||||
const currentLogs: ILog[] =
|
||||
currentData[0].list?.map((item) => ({
|
||||
...item.data,
|
||||
timestamp: item.timestamp,
|
||||
})) || [];
|
||||
|
||||
setLogs(currentLogs);
|
||||
|
||||
setResetLogsList(false);
|
||||
}
|
||||
|
||||
if (currentData.length > 0 && currentData[0].list) {
|
||||
const currentLogs: ILog[] =
|
||||
currentData[0].list.map((item) => ({
|
||||
...item.data,
|
||||
timestamp: item.timestamp,
|
||||
})) || [];
|
||||
|
||||
setLogs((prev) => [...prev, ...currentLogs]);
|
||||
} else {
|
||||
setHasReachedEndOfLogs(true);
|
||||
}
|
||||
}
|
||||
}, [data, restFilters, isPaginating, resetLogsList]);
|
||||
|
||||
const getItemContent = useCallback(
|
||||
(_: number, logToRender: ILog): JSX.Element => (
|
||||
<RawLogView
|
||||
@@ -149,38 +88,28 @@ function EntityLogs({
|
||||
[],
|
||||
);
|
||||
|
||||
const loadMoreLogs = useCallback(() => {
|
||||
if (!logs.length) return;
|
||||
const { data, isLoading, isFetching, isError } = useQuery({
|
||||
queryKey: [
|
||||
queryKey,
|
||||
timeRange.startTime,
|
||||
timeRange.endTime,
|
||||
filters,
|
||||
currentPage,
|
||||
],
|
||||
queryFn: () => GetMetricQueryRange(queryPayload, DEFAULT_ENTITY_VERSION),
|
||||
enabled: !!queryPayload,
|
||||
keepPreviousData: isPaginating,
|
||||
});
|
||||
|
||||
setIsPaginating(true);
|
||||
const lastLog = logs[logs.length - 1];
|
||||
|
||||
const newItems = [
|
||||
...filters.items.filter((item) => item.key?.key !== 'id'),
|
||||
{
|
||||
id: v4(),
|
||||
key: {
|
||||
key: 'id',
|
||||
type: '',
|
||||
dataType: DataTypes.String,
|
||||
isColumn: true,
|
||||
},
|
||||
op: '<',
|
||||
value: lastLog.id,
|
||||
},
|
||||
];
|
||||
|
||||
const newFilters = {
|
||||
op: 'AND',
|
||||
items: newItems,
|
||||
} as IBuilderQuery['filters'];
|
||||
|
||||
handleChangeLogFilters(newFilters);
|
||||
}, [logs, filters, handleChangeLogFilters]);
|
||||
useEffect(() => {
|
||||
if (data?.payload?.data?.newResult?.data?.result) {
|
||||
handleNewData(data.payload.data.newResult.data.result);
|
||||
}
|
||||
}, [data, handleNewData]);
|
||||
|
||||
useEffect(() => {
|
||||
setIsPaginating(false);
|
||||
}, [data]);
|
||||
}, [data, setIsPaginating]);
|
||||
|
||||
const renderFooter = useCallback(
|
||||
(): JSX.Element | null => (
|
||||
|
||||
@@ -96,7 +96,6 @@ function EntityLogsDetailedView({
|
||||
</div>
|
||||
<EntityLogs
|
||||
timeRange={timeRange}
|
||||
handleChangeLogFilters={handleChangeLogFilters}
|
||||
filters={logFilters}
|
||||
queryKey={queryKey}
|
||||
category={category}
|
||||
|
||||
@@ -11,7 +11,8 @@ import { defaultLogsSelectedColumns } from 'container/OptionsMenu/constants';
|
||||
import { FontSize } from 'container/OptionsMenu/types';
|
||||
import { ORDERBY_FILTERS } from 'container/QueryBuilder/filters/OrderByFilter/config';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { uniqBy } from 'lodash-es';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { Virtuoso } from 'react-virtuoso';
|
||||
import { ILog } from 'types/api/logs/log';
|
||||
import { Query, TagFilter } from 'types/api/queryBuilder/queryBuilderData';
|
||||
@@ -27,7 +28,6 @@ function ContextLogRenderer({
|
||||
}: ContextLogRendererProps): JSX.Element {
|
||||
const [prevLogPage, setPrevLogPage] = useState<number>(1);
|
||||
const [afterLogPage, setAfterLogPage] = useState<number>(1);
|
||||
const [logs, setLogs] = useState<ILog[]>([log]);
|
||||
|
||||
const { initialDataSource, stagedQuery } = useQueryBuilder();
|
||||
|
||||
@@ -73,20 +73,10 @@ function ContextLogRenderer({
|
||||
fontSize: options.fontSize,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setLogs((prev) => [...previousLogs, ...prev]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [previousLogs]);
|
||||
|
||||
useEffect(() => {
|
||||
setLogs((prev) => [...prev, ...afterLogs]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [afterLogs]);
|
||||
|
||||
useEffect(() => {
|
||||
setLogs([log]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [filters]);
|
||||
const logsToRender = useMemo(
|
||||
() => uniqBy([...previousLogs, log, ...afterLogs], 'id'),
|
||||
[previousLogs, log, afterLogs],
|
||||
);
|
||||
|
||||
const lengthMultipier = useMemo(() => {
|
||||
switch (options.fontSize) {
|
||||
@@ -137,9 +127,9 @@ function ContextLogRenderer({
|
||||
<Virtuoso
|
||||
className="virtuoso-list"
|
||||
initialTopMostItemIndex={0}
|
||||
data={logs}
|
||||
data={logsToRender}
|
||||
itemContent={getItemContent}
|
||||
style={{ height: `calc(${logs.length} * ${lengthMultipier}px)` }}
|
||||
style={{ height: `calc(${logsToRender.length} * ${lengthMultipier}px)` }}
|
||||
/>
|
||||
</OverlayScrollbar>
|
||||
{isAfterLogsFetching && (
|
||||
|
||||
@@ -40,7 +40,7 @@ import { useHandleExplorerTabChange } from 'hooks/useHandleExplorerTabChange';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import useUrlQueryData from 'hooks/useUrlQueryData';
|
||||
import { FlatLogData } from 'lib/logs/flatLogData';
|
||||
import { getPaginationQueryData } from 'lib/newQueryBuilder/getPaginationQueryData';
|
||||
import { getPaginationQueryDataV2 } from 'lib/newQueryBuilder/getPaginationQueryData';
|
||||
import {
|
||||
cloneDeep,
|
||||
defaultTo,
|
||||
@@ -94,7 +94,9 @@ function LogsExplorerViews({
|
||||
selectedView: SELECTED_VIEWS;
|
||||
showFrequencyChart: boolean;
|
||||
setIsLoadingQueries: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
listQueryKeyRef: MutableRefObject<any>;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
chartQueryKeyRef: MutableRefObject<any>;
|
||||
}): JSX.Element {
|
||||
const { notifications } = useNotifications();
|
||||
@@ -305,10 +307,7 @@ function LogsExplorerViews({
|
||||
): Query | null => {
|
||||
if (!query) return null;
|
||||
|
||||
const paginateData = getPaginationQueryData({
|
||||
filters: params.filters,
|
||||
listItemId: params.log ? params.log.id : null,
|
||||
orderByTimestamp,
|
||||
const paginateData = getPaginationQueryDataV2({
|
||||
page: params.page,
|
||||
pageSize: params.pageSize,
|
||||
});
|
||||
@@ -333,7 +332,7 @@ function LogsExplorerViews({
|
||||
|
||||
return data;
|
||||
},
|
||||
[orderByTimestamp, listQuery],
|
||||
[listQuery],
|
||||
);
|
||||
|
||||
const handleEndReached = useCallback(
|
||||
|
||||
@@ -10,7 +10,6 @@ import Controls from 'container/Controls';
|
||||
import { PER_PAGE_OPTIONS } from 'container/TracesExplorer/ListView/configs';
|
||||
import { tableStyles } from 'container/TracesExplorer/ListView/styles';
|
||||
import { useActiveLog } from 'hooks/logs/useActiveLog';
|
||||
import { Pagination } from 'hooks/queryPagination';
|
||||
import { useLogsData } from 'hooks/useLogsData';
|
||||
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
|
||||
import { FlatLogData } from 'lib/logs/flatLogData';
|
||||
@@ -21,46 +20,27 @@ import {
|
||||
HTMLAttributes,
|
||||
SetStateAction,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { UseQueryResult } from 'react-query';
|
||||
import { SuccessResponse } from 'types/api';
|
||||
import { Widgets } from 'types/api/dashboard/getAll';
|
||||
import { ILog } from 'types/api/logs/log';
|
||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||
|
||||
import { getLogPanelColumnsList, getNextOrPreviousItems } from './utils';
|
||||
import { getLogPanelColumnsList } from './utils';
|
||||
|
||||
function LogsPanelComponent({
|
||||
widget,
|
||||
setRequestData,
|
||||
queryResponse,
|
||||
}: LogsPanelComponentProps): JSX.Element {
|
||||
const [pagination, setPagination] = useState<Pagination>({
|
||||
offset: 0,
|
||||
limit: widget.query.builder.queryData[0].limit || 0,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setRequestData((prev) => ({
|
||||
...prev,
|
||||
tableParams: {
|
||||
pagination,
|
||||
},
|
||||
}));
|
||||
}, [pagination, setRequestData]);
|
||||
|
||||
const [pageSize, setPageSize] = useState<number>(10);
|
||||
const [offset, setOffset] = useState<number>(0);
|
||||
|
||||
const handleChangePageSize = (value: number): void => {
|
||||
setPagination({
|
||||
...pagination,
|
||||
limit: 0,
|
||||
offset: value,
|
||||
});
|
||||
setPageSize(value);
|
||||
setOffset(0);
|
||||
setRequestData((prev) => {
|
||||
const newQueryData = { ...prev.query };
|
||||
newQueryData.builder.queryData[0].pageSize = value;
|
||||
@@ -70,7 +50,7 @@ function LogsPanelComponent({
|
||||
tableParams: {
|
||||
pagination: {
|
||||
limit: 0,
|
||||
offset: value,
|
||||
offset: 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -88,22 +68,12 @@ function LogsPanelComponent({
|
||||
queryResponse.data?.payload?.data?.newResult?.data?.result[0]?.list?.length;
|
||||
const totalCount = useMemo(() => dataLength || 0, [dataLength]);
|
||||
|
||||
const [firstLog, setFirstLog] = useState<ILog>();
|
||||
const [lastLog, setLastLog] = useState<ILog>();
|
||||
|
||||
const { logs } = useLogsData({
|
||||
result: queryResponse.data?.payload?.data?.newResult?.data?.result,
|
||||
panelType: PANEL_TYPES.LIST,
|
||||
stagedQuery: widget.query,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (logs.length) {
|
||||
setFirstLog(logs[0]);
|
||||
setLastLog(logs[logs.length - 1]);
|
||||
}
|
||||
}, [logs]);
|
||||
|
||||
const flattenLogData = useMemo(
|
||||
() => logs.map((log) => FlatLogData(log) as RowData),
|
||||
[logs],
|
||||
@@ -127,84 +97,27 @@ function LogsPanelComponent({
|
||||
[logs, onSetActiveLog],
|
||||
);
|
||||
|
||||
const isOrderByTimeStamp =
|
||||
widget.query.builder.queryData[0].orderBy.length > 0 &&
|
||||
widget.query.builder.queryData[0].orderBy[0].columnName === 'timestamp';
|
||||
const handleRequestData = (newOffset: number): void => {
|
||||
setOffset(newOffset);
|
||||
setRequestData((prev) => ({
|
||||
...prev,
|
||||
tableParams: {
|
||||
pagination: {
|
||||
limit: widget.query.builder.queryData[0].limit || 0,
|
||||
offset: newOffset < 0 ? 0 : newOffset,
|
||||
},
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
const handlePreviousPagination = (): void => {
|
||||
if (isOrderByTimeStamp) {
|
||||
setRequestData((prev) => ({
|
||||
...prev,
|
||||
query: {
|
||||
...prev.query,
|
||||
builder: {
|
||||
...prev.query.builder,
|
||||
queryData: [
|
||||
{
|
||||
...prev.query.builder.queryData[0],
|
||||
filters: {
|
||||
...prev.query.builder.queryData[0].filters,
|
||||
items: [
|
||||
...getNextOrPreviousItems(
|
||||
prev.query.builder.queryData[0].filters.items,
|
||||
'PREV',
|
||||
firstLog,
|
||||
),
|
||||
],
|
||||
},
|
||||
limit: 0,
|
||||
offset: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}));
|
||||
}
|
||||
if (!isOrderByTimeStamp) {
|
||||
setPagination({
|
||||
...pagination,
|
||||
limit: 0,
|
||||
offset: pagination.offset - pageSize,
|
||||
});
|
||||
}
|
||||
const newOffset = offset - pageSize;
|
||||
handleRequestData(newOffset);
|
||||
};
|
||||
|
||||
const handleNextPagination = (): void => {
|
||||
if (isOrderByTimeStamp) {
|
||||
setRequestData((prev) => ({
|
||||
...prev,
|
||||
query: {
|
||||
...prev.query,
|
||||
builder: {
|
||||
...prev.query.builder,
|
||||
queryData: [
|
||||
{
|
||||
...prev.query.builder.queryData[0],
|
||||
filters: {
|
||||
...prev.query.builder.queryData[0].filters,
|
||||
items: [
|
||||
...getNextOrPreviousItems(
|
||||
prev.query.builder.queryData[0].filters.items,
|
||||
'NEXT',
|
||||
lastLog,
|
||||
),
|
||||
],
|
||||
},
|
||||
limit: 0,
|
||||
offset: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}));
|
||||
}
|
||||
if (!isOrderByTimeStamp) {
|
||||
setPagination({
|
||||
...pagination,
|
||||
limit: 0,
|
||||
offset: pagination.offset + pageSize,
|
||||
});
|
||||
}
|
||||
const newOffset = offset + pageSize;
|
||||
handleRequestData(newOffset);
|
||||
};
|
||||
|
||||
if (queryResponse.isError) {
|
||||
@@ -235,12 +148,11 @@ function LogsPanelComponent({
|
||||
totalCount={totalCount}
|
||||
perPageOptions={PER_PAGE_OPTIONS}
|
||||
isLoading={queryResponse.isFetching}
|
||||
offset={pagination.offset}
|
||||
offset={offset}
|
||||
countPerPage={pageSize}
|
||||
handleNavigatePrevious={handlePreviousPagination}
|
||||
handleNavigateNext={handleNextPagination}
|
||||
handleCountItemsPerPageChange={handleChangePageSize}
|
||||
isLogPanel={isOrderByTimeStamp}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
import { ColumnsType } from 'antd/es/table';
|
||||
import { Typography } from 'antd/lib';
|
||||
import { OPERATORS } from 'constants/queryBuilder';
|
||||
import { TimestampInput } from 'hooks/useTimezoneFormatter/useTimezoneFormatter';
|
||||
// import Typography from 'antd/es/typography/Typography';
|
||||
import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
||||
import { ReactNode } from 'react';
|
||||
import { Widgets } from 'types/api/dashboard/getAll';
|
||||
import { IField } from 'types/api/logs/fields';
|
||||
import { ILog } from 'types/api/logs/log';
|
||||
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
export const getLogPanelColumnsList = (
|
||||
selectedLogFields: Widgets['selectedLogFields'],
|
||||
@@ -55,49 +50,3 @@ export const getLogPanelColumnsList = (
|
||||
|
||||
return [...initialColumns, ...columns];
|
||||
};
|
||||
|
||||
export const getNextOrPreviousItems = (
|
||||
items: TagFilterItem[],
|
||||
direction: 'NEXT' | 'PREV',
|
||||
log?: ILog,
|
||||
): TagFilterItem[] => {
|
||||
const nextItem = {
|
||||
id: uuid(),
|
||||
key: {
|
||||
key: 'id',
|
||||
type: '',
|
||||
dataType: DataTypes.String,
|
||||
isColumn: true,
|
||||
},
|
||||
op: OPERATORS['<'],
|
||||
value: log?.id || '',
|
||||
};
|
||||
const prevItem = {
|
||||
id: uuid(),
|
||||
key: {
|
||||
key: 'id',
|
||||
type: '',
|
||||
dataType: DataTypes.String,
|
||||
isColumn: true,
|
||||
},
|
||||
op: OPERATORS['>'],
|
||||
value: log?.id || '',
|
||||
};
|
||||
let index = items.findIndex((item) => item.op === OPERATORS['<']);
|
||||
if (index === -1) {
|
||||
index = items.findIndex((item) => item.op === OPERATORS['>']);
|
||||
}
|
||||
if (index === -1) {
|
||||
if (direction === 'NEXT') {
|
||||
return [...items, nextItem];
|
||||
}
|
||||
return [...items, prevItem];
|
||||
}
|
||||
const newItems = [...items];
|
||||
if (direction === 'NEXT') {
|
||||
newItems[index] = nextItem;
|
||||
} else {
|
||||
newItems[index] = prevItem;
|
||||
}
|
||||
return newItems;
|
||||
};
|
||||
|
||||
181
frontend/src/hooks/infraMonitoring/useHandleLogsPagination.tsx
Normal file
181
frontend/src/hooks/infraMonitoring/useHandleLogsPagination.tsx
Normal file
@@ -0,0 +1,181 @@
|
||||
import { DEFAULT_PER_PAGE_VALUE } from 'container/Controls/config';
|
||||
import { ORDERBY_FILTERS } from 'container/QueryBuilder/filters/OrderByFilter/config';
|
||||
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
|
||||
import { isEqual } from 'lodash-es';
|
||||
import {
|
||||
Dispatch,
|
||||
SetStateAction,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { ILog } from 'types/api/logs/log';
|
||||
import {
|
||||
IBuilderQuery,
|
||||
TagFilterItem,
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
interface TimeRange {
|
||||
startTime: number;
|
||||
endTime: number;
|
||||
}
|
||||
|
||||
interface UsePaginatedLogsProps {
|
||||
timeRange: TimeRange;
|
||||
filters: IBuilderQuery['filters'];
|
||||
queryKeyFilters?: string[];
|
||||
excludeFilterKeys?: string[];
|
||||
basePayload: GetQueryResultsProps;
|
||||
}
|
||||
|
||||
interface UseHandleLogsPagination {
|
||||
logs: ILog[];
|
||||
hasReachedEndOfLogs: boolean;
|
||||
isPaginating: boolean;
|
||||
currentPage: number;
|
||||
resetLogsList: boolean;
|
||||
setIsPaginating: Dispatch<SetStateAction<boolean>>;
|
||||
handleNewData: (currentData: any) => void;
|
||||
loadMoreLogs: () => void;
|
||||
shouldResetPage: boolean;
|
||||
queryPayload: GetQueryResultsProps;
|
||||
}
|
||||
|
||||
export const useHandleLogsPagination = ({
|
||||
timeRange,
|
||||
filters,
|
||||
queryKeyFilters = [],
|
||||
excludeFilterKeys = [],
|
||||
basePayload,
|
||||
}: UsePaginatedLogsProps): UseHandleLogsPagination => {
|
||||
const [logs, setLogs] = useState<ILog[]>([]);
|
||||
const [hasReachedEndOfLogs, setHasReachedEndOfLogs] = useState(false);
|
||||
const [restFilters, setRestFilters] = useState<TagFilterItem[]>([]);
|
||||
const [resetLogsList, setResetLogsList] = useState<boolean>(false);
|
||||
const [page, setPage] = useState(1);
|
||||
const [prevTimeRange, setPrevTimeRange] = useState<TimeRange | null>(
|
||||
timeRange,
|
||||
);
|
||||
const [isPaginating, setIsPaginating] = useState(false);
|
||||
|
||||
const { shouldResetPage, newRestFilters } = useMemo(() => {
|
||||
const newRestFilters = filters.items.filter((item) => {
|
||||
const keyToCheck = item.key?.key ?? '';
|
||||
return (
|
||||
!queryKeyFilters.includes(keyToCheck) &&
|
||||
!excludeFilterKeys.includes(keyToCheck)
|
||||
);
|
||||
});
|
||||
|
||||
const areFiltersSame = isEqual(restFilters, newRestFilters);
|
||||
|
||||
const shouldResetPage =
|
||||
!areFiltersSame ||
|
||||
timeRange.startTime !== prevTimeRange?.startTime ||
|
||||
timeRange.endTime !== prevTimeRange?.endTime;
|
||||
|
||||
return { shouldResetPage, newRestFilters };
|
||||
}, [
|
||||
filters,
|
||||
timeRange,
|
||||
prevTimeRange,
|
||||
queryKeyFilters,
|
||||
excludeFilterKeys,
|
||||
restFilters,
|
||||
]);
|
||||
|
||||
const currentPage = useMemo(() => {
|
||||
if (shouldResetPage) {
|
||||
return 1;
|
||||
}
|
||||
return page;
|
||||
}, [shouldResetPage, page]);
|
||||
|
||||
// Handle data updates
|
||||
const handleNewData = useCallback(
|
||||
(currentData: any) => {
|
||||
if (!currentData[0].list) {
|
||||
setHasReachedEndOfLogs(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const currentLogs: ILog[] =
|
||||
currentData[0].list?.map((item: any) => ({
|
||||
...item.data,
|
||||
timestamp: item.timestamp,
|
||||
})) || [];
|
||||
|
||||
if (resetLogsList) {
|
||||
setLogs(currentLogs);
|
||||
setResetLogsList(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const newLogs = currentLogs.filter(
|
||||
(newLog) => !logs.some((existingLog) => isEqual(existingLog, newLog)),
|
||||
);
|
||||
|
||||
if (newLogs.length > 0) {
|
||||
setLogs((prev) => [...prev, ...newLogs]);
|
||||
}
|
||||
},
|
||||
[logs, resetLogsList],
|
||||
);
|
||||
|
||||
// Reset logic
|
||||
useEffect(() => {
|
||||
if (shouldResetPage) {
|
||||
setPage(1);
|
||||
setLogs([]);
|
||||
setResetLogsList(true);
|
||||
}
|
||||
|
||||
setPrevTimeRange(timeRange);
|
||||
setRestFilters(newRestFilters);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [shouldResetPage, timeRange]);
|
||||
|
||||
const loadMoreLogs = useCallback(() => {
|
||||
if (!logs.length) return;
|
||||
setPage((prev) => prev + 1);
|
||||
setIsPaginating(true);
|
||||
}, [logs]);
|
||||
|
||||
const queryPayload = useMemo(
|
||||
() => ({
|
||||
...basePayload,
|
||||
query: {
|
||||
...basePayload.query,
|
||||
builder: {
|
||||
...basePayload.query.builder,
|
||||
queryData: [
|
||||
{
|
||||
...basePayload.query.builder.queryData[0],
|
||||
pageSize: DEFAULT_PER_PAGE_VALUE,
|
||||
offset: (currentPage - 1) * DEFAULT_PER_PAGE_VALUE,
|
||||
orderBy: [
|
||||
{ columnName: 'timestamp', order: ORDERBY_FILTERS.DESC },
|
||||
{ columnName: 'id', order: ORDERBY_FILTERS.DESC },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}),
|
||||
[basePayload, currentPage],
|
||||
);
|
||||
|
||||
return {
|
||||
logs,
|
||||
hasReachedEndOfLogs,
|
||||
isPaginating,
|
||||
currentPage,
|
||||
resetLogsList,
|
||||
queryPayload,
|
||||
setIsPaginating,
|
||||
handleNewData,
|
||||
loadMoreLogs,
|
||||
shouldResetPage,
|
||||
};
|
||||
};
|
||||
@@ -22,16 +22,46 @@ export const useGetQueryRange: UseGetQueryRange = (
|
||||
options,
|
||||
headers,
|
||||
) => {
|
||||
const newRequestData: GetQueryResultsProps = useMemo(
|
||||
() => ({
|
||||
const newRequestData: GetQueryResultsProps = useMemo(() => {
|
||||
const isListWithSingleTimestampOrder =
|
||||
requestData.graphType === PANEL_TYPES.LIST &&
|
||||
requestData.query.builder?.queryData[0]?.orderBy?.length === 1 &&
|
||||
// exclude list with id filter (i.e. context logs)
|
||||
!requestData.query.builder?.queryData[0].filters.items.some(
|
||||
(filter) => filter.key?.key === 'id',
|
||||
) &&
|
||||
requestData.query.builder?.queryData[0].orderBy[0].columnName ===
|
||||
'timestamp';
|
||||
|
||||
const modifiedRequestData = {
|
||||
...requestData,
|
||||
graphType:
|
||||
requestData.graphType === PANEL_TYPES.BAR
|
||||
? PANEL_TYPES.TIME_SERIES
|
||||
: requestData.graphType,
|
||||
}),
|
||||
[requestData],
|
||||
);
|
||||
};
|
||||
|
||||
// If the query is a list with a single timestamp order, we need to add the id column to the order by clause
|
||||
if (isListWithSingleTimestampOrder) {
|
||||
modifiedRequestData.query.builder = {
|
||||
...requestData.query.builder,
|
||||
queryData: [
|
||||
{
|
||||
...requestData.query.builder.queryData[0],
|
||||
orderBy: [
|
||||
...requestData.query.builder.queryData[0].orderBy,
|
||||
{
|
||||
columnName: 'id',
|
||||
order: requestData.query.builder.queryData[0].orderBy[0].order,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
return modifiedRequestData;
|
||||
}, [requestData]);
|
||||
|
||||
const queryKey = useMemo(() => {
|
||||
if (options?.queryKey && Array.isArray(options.queryKey)) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
PANEL_TYPES,
|
||||
} from 'constants/queryBuilder';
|
||||
import { DEFAULT_PER_PAGE_VALUE } from 'container/Controls/config';
|
||||
import { getPaginationQueryData } from 'lib/newQueryBuilder/getPaginationQueryData';
|
||||
import { getPaginationQueryDataV2 } from 'lib/newQueryBuilder/getPaginationQueryData';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
@@ -100,10 +100,7 @@ export const useLogsData = ({
|
||||
): Query | null => {
|
||||
if (!query) return null;
|
||||
|
||||
const paginateData = getPaginationQueryData({
|
||||
filters: params.filters,
|
||||
listItemId: params.log ? params.log.id : null,
|
||||
orderByTimestamp,
|
||||
const paginateData = getPaginationQueryDataV2({
|
||||
page: params.page,
|
||||
pageSize: params.pageSize,
|
||||
});
|
||||
|
||||
@@ -8,6 +8,27 @@ import {
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
type SetupPaginationQueryDataParamsV2 = {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
};
|
||||
|
||||
type SetupPaginationQueryDataV2 = (
|
||||
params: SetupPaginationQueryDataParamsV2,
|
||||
) => Partial<IBuilderQuery>;
|
||||
|
||||
export const getPaginationQueryDataV2: SetupPaginationQueryDataV2 = ({
|
||||
page,
|
||||
pageSize,
|
||||
}) => {
|
||||
const offset = (page - 1) * pageSize;
|
||||
|
||||
return {
|
||||
offset,
|
||||
pageSize,
|
||||
};
|
||||
};
|
||||
|
||||
type SetupPaginationQueryDataParams = {
|
||||
filters: IBuilderQuery['filters'];
|
||||
listItemId: string | null;
|
||||
|
||||
Reference in New Issue
Block a user