diff --git a/frontend/src/components/CustomTimePicker/CustomTimePicker.tsx b/frontend/src/components/CustomTimePicker/CustomTimePicker.tsx index 6b330b0127..12145413d5 100644 --- a/frontend/src/components/CustomTimePicker/CustomTimePicker.tsx +++ b/frontend/src/components/CustomTimePicker/CustomTimePicker.tsx @@ -7,9 +7,11 @@ import logEvent from 'api/common/logEvent'; import cx from 'classnames'; import { DateTimeRangeType } from 'container/TopNav/CustomDateTimeModal'; import { + CustomTimeType, FixedDurationSuggestionOptions, Options, RelativeDurationSuggestionOptions, + Time, } from 'container/TopNav/DateTimeSelectionV2/config'; import dayjs from 'dayjs'; import { isValidTimeFormat } from 'lib/getMinMax'; @@ -56,6 +58,10 @@ interface CustomTimePickerProps { setCustomDTPickerVisible?: Dispatch>; onCustomDateHandler?: (dateTimeRange: DateTimeRangeType) => void; handleGoLive?: () => void; + onTimeChange?: ( + interval: Time | CustomTimeType, + dateTimeRange?: [number, number], + ) => void; } function CustomTimePicker({ @@ -73,6 +79,7 @@ function CustomTimePicker({ setCustomDTPickerVisible, onCustomDateHandler, handleGoLive, + onTimeChange, }: CustomTimePickerProps): JSX.Element { const [ selectedTimePlaceholderValue, @@ -336,6 +343,7 @@ function CustomTimePicker({ setActiveView={setActiveView} setIsOpenedFromFooter={setIsOpenedFromFooter} isOpenedFromFooter={isOpenedFromFooter} + onTimeChange={onTimeChange} /> ) : ( content @@ -405,4 +413,5 @@ CustomTimePicker.defaultProps = { onCustomDateHandler: noop, handleGoLive: noop, onCustomTimeStatusUpdate: noop, + onTimeChange: undefined, }; diff --git a/frontend/src/components/CustomTimePicker/CustomTimePickerPopoverContent.tsx b/frontend/src/components/CustomTimePicker/CustomTimePickerPopoverContent.tsx index d5c4339bc7..6cfe2c8aac 100644 --- a/frontend/src/components/CustomTimePicker/CustomTimePickerPopoverContent.tsx +++ b/frontend/src/components/CustomTimePicker/CustomTimePickerPopoverContent.tsx @@ -7,9 +7,11 @@ import cx from 'classnames'; import ROUTES from 'constants/routes'; import { DateTimeRangeType } from 'container/TopNav/CustomDateTimeModal'; import { + CustomTimeType, LexicalContext, Option, RelativeDurationSuggestionOptions, + Time, } from 'container/TopNav/DateTimeSelectionV2/config'; import { Clock, PenLine } from 'lucide-react'; import { useTimezone } from 'providers/Timezone'; @@ -35,6 +37,10 @@ interface CustomTimePickerPopoverContentProps { setActiveView: Dispatch>; isOpenedFromFooter: boolean; setIsOpenedFromFooter: Dispatch>; + onTimeChange?: ( + interval: Time | CustomTimeType, + dateTimeRange?: [number, number], + ) => void; } // eslint-disable-next-line sonarjs/cognitive-complexity @@ -51,6 +57,7 @@ function CustomTimePickerPopoverContent({ setActiveView, isOpenedFromFooter, setIsOpenedFromFooter, + onTimeChange, }: CustomTimePickerPopoverContentProps): JSX.Element { const { pathname } = useLocation(); @@ -143,6 +150,7 @@ function CustomTimePickerPopoverContent({ setIsOpen={setIsOpen} onCustomDateHandler={onCustomDateHandler} selectedTime={selectedTime} + onTimeChange={onTimeChange} /> ) : (
@@ -181,4 +189,8 @@ function CustomTimePickerPopoverContent({ ); } +CustomTimePickerPopoverContent.defaultProps = { + onTimeChange: undefined, +}; + export default CustomTimePickerPopoverContent; diff --git a/frontend/src/components/CustomTimePicker/RangePickerModal.tsx b/frontend/src/components/CustomTimePicker/RangePickerModal.tsx index 53c4171b36..f236c0d189 100644 --- a/frontend/src/components/CustomTimePicker/RangePickerModal.tsx +++ b/frontend/src/components/CustomTimePicker/RangePickerModal.tsx @@ -1,9 +1,14 @@ +/* eslint-disable react/jsx-props-no-spreading */ import './RangePickerModal.styles.scss'; import { DatePicker } from 'antd'; import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats'; import { DateTimeRangeType } from 'container/TopNav/CustomDateTimeModal'; -import { LexicalContext } from 'container/TopNav/DateTimeSelectionV2/config'; +import { + CustomTimeType, + LexicalContext, + Time, +} from 'container/TopNav/DateTimeSelectionV2/config'; import dayjs, { Dayjs } from 'dayjs'; import { useTimezone } from 'providers/Timezone'; import { Dispatch, SetStateAction, useMemo } from 'react'; @@ -19,6 +24,10 @@ interface RangePickerModalProps { lexicalContext?: LexicalContext | undefined, ) => void; selectedTime: string; + onTimeChange?: ( + interval: Time | CustomTimeType, + dateTimeRange?: [number, number], + ) => void; } function RangePickerModal(props: RangePickerModalProps): JSX.Element { @@ -27,6 +36,7 @@ function RangePickerModal(props: RangePickerModalProps): JSX.Element { setIsOpen, onCustomDateHandler, selectedTime, + onTimeChange, } = props; const { RangePicker } = DatePicker; const { maxTime, minTime } = useSelector( @@ -74,13 +84,22 @@ function RangePickerModal(props: RangePickerModalProps): JSX.Element { date.tz(timezone.value).format(DATE_TIME_FORMATS.ISO_DATETIME) } onOk={onModalOkHandler} - // eslint-disable-next-line react/jsx-props-no-spreading - {...(selectedTime === 'custom' && { - value: rangeValue, - })} + {...(selectedTime === 'custom' && + !onTimeChange && { + value: rangeValue, + })} + // use default value if onTimeChange is provided + {...(selectedTime === 'custom' && + onTimeChange && { + defaultValue: rangeValue, + })} />
); } +RangePickerModal.defaultProps = { + onTimeChange: undefined, +}; + export default RangePickerModal; diff --git a/frontend/src/components/HostMetricsDetail/HostMetricTraces/HostMetricTraces.tsx b/frontend/src/components/HostMetricsDetail/HostMetricTraces/HostMetricTraces.tsx index 0072c3dc26..e5a75cc9b0 100644 --- a/frontend/src/components/HostMetricsDetail/HostMetricTraces/HostMetricTraces.tsx +++ b/frontend/src/components/HostMetricsDetail/HostMetricTraces/HostMetricTraces.tsx @@ -26,6 +26,7 @@ import { useQuery } from 'react-query'; import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; import { DataSource } from 'types/common/queryBuilder'; +import { VIEWS } from '../constants'; import { getHostTracesQueryPayload, selectedColumns } from './constants'; import { getListColumns } from './utils'; @@ -39,7 +40,10 @@ interface Props { interval: Time | CustomTimeType, dateTimeRange?: [number, number], ) => void; - handleChangeTracesFilters: (value: IBuilderQuery['filters']) => void; + handleChangeTracesFilters: ( + value: IBuilderQuery['filters'], + view: VIEWS, + ) => void; tracesFilters: IBuilderQuery['filters']; selectedInterval: Time; } @@ -70,14 +74,16 @@ function HostMetricTraces({ ...currentQuery.builder.queryData[0].aggregateAttribute, }, filters: { - items: [], + items: tracesFilters.items.filter( + (item) => item.key?.key !== 'host.name', + ), op: 'AND', }, }, ], }, }), - [currentQuery], + [currentQuery, tracesFilters.items], ); const query = updatedCurrentQuery?.builder?.queryData[0] || null; @@ -153,14 +159,16 @@ function HostMetricTraces({ {query && ( + handleChangeTracesFilters(value, VIEWS.TRACES) + } disableNavigationShortcuts /> )}
({ + const initialFilters = useMemo(() => { + const urlView = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.VIEW); + const queryKey = + urlView === VIEW_TYPES.LOGS + ? INFRA_MONITORING_K8S_PARAMS_KEYS.LOG_FILTERS + : INFRA_MONITORING_K8S_PARAMS_KEYS.TRACES_FILTERS; + const filters = getFiltersFromParams(searchParams, queryKey); + if (filters) { + return filters; + } + + return { op: 'AND', items: [ { @@ -111,9 +123,8 @@ function HostMetricsDetails({ value: host?.hostName || '', }, ], - }), - [host?.hostName], - ); + }; + }, [host?.hostName, searchParams]); const [logFilters, setLogFilters] = useState( initialFilters, @@ -154,7 +165,13 @@ function HostMetricsDetails({ const handleTabChange = (e: RadioChangeEvent): void => { setSelectedView(e.target.value); if (host?.hostName) { - setSearchParams({ hostName: host?.hostName, view: e.target.value }); + setSelectedView(e.target.value); + setSearchParams({ + ...Object.fromEntries(searchParams.entries()), + [INFRA_MONITORING_K8S_PARAMS_KEYS.VIEW]: e.target.value, + [INFRA_MONITORING_K8S_PARAMS_KEYS.LOG_FILTERS]: JSON.stringify(null), + [INFRA_MONITORING_K8S_PARAMS_KEYS.TRACES_FILTERS]: JSON.stringify(null), + }); } logEvent(InfraMonitoringEvents.TabChanged, { entity: InfraMonitoringEvents.HostEntity, @@ -191,7 +208,7 @@ function HostMetricsDetails({ ); const handleChangeLogFilters = useCallback( - (value: IBuilderQuery['filters']) => { + (value: IBuilderQuery['filters'], view: VIEWS) => { setLogFilters((prevFilters) => { const hostNameFilter = prevFilters.items.find( (item) => item.key?.key === 'host.name', @@ -209,7 +226,7 @@ function HostMetricsDetails({ }); } - return { + const updatedFilters = { op: 'AND', items: [ hostNameFilter, @@ -217,6 +234,15 @@ function HostMetricsDetails({ ...(paginationFilter ? [paginationFilter] : []), ].filter((item): item is TagFilterItem => item !== undefined), }; + + setSearchParams({ + ...Object.fromEntries(searchParams.entries()), + [INFRA_MONITORING_K8S_PARAMS_KEYS.LOG_FILTERS]: JSON.stringify( + updatedFilters, + ), + [INFRA_MONITORING_K8S_PARAMS_KEYS.VIEW]: view, + }); + return updatedFilters; }); }, // eslint-disable-next-line react-hooks/exhaustive-deps @@ -224,7 +250,7 @@ function HostMetricsDetails({ ); const handleChangeTracesFilters = useCallback( - (value: IBuilderQuery['filters']) => { + (value: IBuilderQuery['filters'], view: VIEWS) => { setTracesFilters((prevFilters) => { const hostNameFilter = prevFilters.items.find( (item) => item.key?.key === 'host.name', @@ -238,13 +264,23 @@ function HostMetricsDetails({ }); } - return { + const updatedFilters = { op: 'AND', items: [ hostNameFilter, ...value.items.filter((item) => item.key?.key !== 'host.name'), ].filter((item): item is TagFilterItem => item !== undefined), }; + + setSearchParams({ + ...Object.fromEntries(searchParams.entries()), + [INFRA_MONITORING_K8S_PARAMS_KEYS.TRACES_FILTERS]: JSON.stringify( + updatedFilters, + ), + [INFRA_MONITORING_K8S_PARAMS_KEYS.VIEW]: view, + }); + + return updatedFilters; }); }, // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/frontend/src/components/HostMetricsDetail/HostMetricsLogs/HostMetricLogsDetailedView.tsx b/frontend/src/components/HostMetricsDetail/HostMetricsLogs/HostMetricLogsDetailedView.tsx index 611295f8f3..7fe06a641e 100644 --- a/frontend/src/components/HostMetricsDetail/HostMetricsLogs/HostMetricLogsDetailedView.tsx +++ b/frontend/src/components/HostMetricsDetail/HostMetricsLogs/HostMetricLogsDetailedView.tsx @@ -11,6 +11,7 @@ import { useMemo } from 'react'; import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; import { DataSource } from 'types/common/queryBuilder'; +import { VIEWS } from '../constants'; import HostMetricsLogs from './HostMetricsLogs'; interface Props { @@ -23,7 +24,7 @@ interface Props { interval: Time | CustomTimeType, dateTimeRange?: [number, number], ) => void; - handleChangeLogFilters: (value: IBuilderQuery['filters']) => void; + handleChangeLogFilters: (value: IBuilderQuery['filters'], view: VIEWS) => void; logFilters: IBuilderQuery['filters']; selectedInterval: Time; } @@ -51,14 +52,14 @@ function HostMetricLogsDetailedView({ ...currentQuery.builder.queryData[0].aggregateAttribute, }, filters: { - items: [], + items: logFilters.items.filter((item) => item.key?.key !== 'host.name'), op: 'AND', }, }, ], }, }), - [currentQuery], + [currentQuery, logFilters.items], ); const query = updatedCurrentQuery?.builder?.queryData[0] || null; @@ -70,14 +71,14 @@ function HostMetricLogsDetailedView({ {query && ( handleChangeLogFilters(value, VIEWS.LOGS)} disableNavigationShortcuts /> )}
( + new Array(queries.length).fill({ + start: timeRange.startTime, + end: timeRange.endTime, + }), + ); + + useEffect(() => { + setGraphTimeIntervals( + new Array(queries.length).fill({ + start: timeRange.startTime, + end: timeRange.endTime, + }), + ); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [timeRange]); + + const onDragSelect = useCallback( + (start: number, end: number, graphIndex: number) => { + const startTimestamp = Math.trunc(start); + const endTimestamp = Math.trunc(end); + + setGraphTimeIntervals((prev) => { + const newIntervals = [...prev]; + newIntervals[graphIndex] = { + start: Math.floor(startTimestamp / 1000), + end: Math.floor(endTimestamp / 1000), + }; + return newIntervals; + }); + }, + [], + ); + const options = useMemo( () => queries.map(({ data }, idx) => @@ -78,12 +117,12 @@ function Metrics({ yAxisUnit: hostWidgetInfo[idx].yAxisUnit, softMax: null, softMin: null, - minTimeScale: timeRange.startTime, - maxTimeScale: timeRange.endTime, - enableZoom: true, + minTimeScale: graphTimeIntervals[idx].start, + maxTimeScale: graphTimeIntervals[idx].end, + onDragSelect: (start, end) => onDragSelect(start, end, idx), }), ), - [queries, isDarkMode, dimensions, timeRange.startTime, timeRange.endTime], + [queries, isDarkMode, dimensions, graphTimeIntervals, onDragSelect], ); const renderCardContent = ( diff --git a/frontend/src/container/InfraMonitoringHosts/HostsListControls.tsx b/frontend/src/container/InfraMonitoringHosts/HostsListControls.tsx index ca0e85e752..8b4f7b1a3b 100644 --- a/frontend/src/container/InfraMonitoringHosts/HostsListControls.tsx +++ b/frontend/src/container/InfraMonitoringHosts/HostsListControls.tsx @@ -58,7 +58,7 @@ function HostsListControls({
diff --git a/frontend/src/container/InfraMonitoringK8s/Clusters/K8sClustersList.tsx b/frontend/src/container/InfraMonitoringK8s/Clusters/K8sClustersList.tsx index 6732d018dc..aef7bb491a 100644 --- a/frontend/src/container/InfraMonitoringK8s/Clusters/K8sClustersList.tsx +++ b/frontend/src/container/InfraMonitoringK8s/Clusters/K8sClustersList.tsx @@ -59,11 +59,26 @@ function K8sClustersList({ (state) => state.globalTime, ); - const [currentPage, setCurrentPage] = useState(1); - - const [expandedRowKeys, setExpandedRowKeys] = useState([]); const [searchParams, setSearchParams] = useSearchParams(); + const [currentPage, setCurrentPage] = useState(() => { + const page = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.CURRENT_PAGE); + if (page) { + return parseInt(page, 10); + } + return 1; + }); + const [filtersInitialised, setFiltersInitialised] = useState(false); + const [expandedRowKeys, setExpandedRowKeys] = useState([]); + + useEffect(() => { + setSearchParams({ + ...Object.fromEntries(searchParams.entries()), + [INFRA_MONITORING_K8S_PARAMS_KEYS.CURRENT_PAGE]: currentPage.toString(), + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [currentPage]); + const [orderBy, setOrderBy] = useState<{ columnName: string; order: 'asc' | 'desc'; @@ -115,7 +130,9 @@ function K8sClustersList({ // Reset pagination every time quick filters are changed useEffect(() => { - setCurrentPage(1); + if (quickFiltersLastUpdated !== -1) { + setCurrentPage(1); + } }, [quickFiltersLastUpdated]); const createFiltersForSelectedRowData = ( @@ -309,7 +326,11 @@ function K8sClustersList({ const handleFiltersChange = useCallback( (value: IBuilderQuery['filters']): void => { handleChangeQueryData('filters', value); - setCurrentPage(1); + if (filtersInitialised) { + setCurrentPage(1); + } else { + setFiltersInitialised(true); + } if (value.items.length > 0) { logEvent(InfraMonitoringEvents.FilterApplied, { @@ -319,7 +340,8 @@ function K8sClustersList({ }); } }, - [handleChangeQueryData], + // eslint-disable-next-line react-hooks/exhaustive-deps + [], ); useEffect(() => { diff --git a/frontend/src/container/InfraMonitoringK8s/DaemonSets/K8sDaemonSetsList.tsx b/frontend/src/container/InfraMonitoringK8s/DaemonSets/K8sDaemonSetsList.tsx index a104144e52..767b175347 100644 --- a/frontend/src/container/InfraMonitoringK8s/DaemonSets/K8sDaemonSetsList.tsx +++ b/frontend/src/container/InfraMonitoringK8s/DaemonSets/K8sDaemonSetsList.tsx @@ -61,11 +61,26 @@ function K8sDaemonSetsList({ (state) => state.globalTime, ); - const [currentPage, setCurrentPage] = useState(1); const [searchParams, setSearchParams] = useSearchParams(); + const [currentPage, setCurrentPage] = useState(() => { + const page = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.CURRENT_PAGE); + if (page) { + return parseInt(page, 10); + } + return 1; + }); + const [filtersInitialised, setFiltersInitialised] = useState(false); const [expandedRowKeys, setExpandedRowKeys] = useState([]); + useEffect(() => { + setSearchParams({ + ...Object.fromEntries(searchParams.entries()), + [INFRA_MONITORING_K8S_PARAMS_KEYS.CURRENT_PAGE]: currentPage.toString(), + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [currentPage]); + const [orderBy, setOrderBy] = useState<{ columnName: string; order: 'asc' | 'desc'; @@ -117,7 +132,9 @@ function K8sDaemonSetsList({ // Reset pagination every time quick filters are changed useEffect(() => { - setCurrentPage(1); + if (quickFiltersLastUpdated !== -1) { + setCurrentPage(1); + } }, [quickFiltersLastUpdated]); const createFiltersForSelectedRowData = ( @@ -313,7 +330,11 @@ function K8sDaemonSetsList({ const handleFiltersChange = useCallback( (value: IBuilderQuery['filters']): void => { handleChangeQueryData('filters', value); - setCurrentPage(1); + if (filtersInitialised) { + setCurrentPage(1); + } else { + setFiltersInitialised(true); + } if (value.items.length > 0) { logEvent(InfraMonitoringEvents.FilterApplied, { @@ -323,7 +344,8 @@ function K8sDaemonSetsList({ }); } }, - [handleChangeQueryData], + // eslint-disable-next-line react-hooks/exhaustive-deps + [], ); useEffect(() => { diff --git a/frontend/src/container/InfraMonitoringK8s/Deployments/K8sDeploymentsList.tsx b/frontend/src/container/InfraMonitoringK8s/Deployments/K8sDeploymentsList.tsx index b4294226bc..1bbb58bb1a 100644 --- a/frontend/src/container/InfraMonitoringK8s/Deployments/K8sDeploymentsList.tsx +++ b/frontend/src/container/InfraMonitoringK8s/Deployments/K8sDeploymentsList.tsx @@ -61,10 +61,26 @@ function K8sDeploymentsList({ (state) => state.globalTime, ); - const [currentPage, setCurrentPage] = useState(1); + const [searchParams, setSearchParams] = useSearchParams(); + + const [currentPage, setCurrentPage] = useState(() => { + const page = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.CURRENT_PAGE); + if (page) { + return parseInt(page, 10); + } + return 1; + }); + const [filtersInitialised, setFiltersInitialised] = useState(false); + + useEffect(() => { + setSearchParams({ + ...Object.fromEntries(searchParams.entries()), + [INFRA_MONITORING_K8S_PARAMS_KEYS.CURRENT_PAGE]: currentPage.toString(), + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [currentPage]); const [expandedRowKeys, setExpandedRowKeys] = useState([]); - const [searchParams, setSearchParams] = useSearchParams(); const [orderBy, setOrderBy] = useState<{ columnName: string; @@ -117,7 +133,9 @@ function K8sDeploymentsList({ // Reset pagination every time quick filters are changed useEffect(() => { - setCurrentPage(1); + if (quickFiltersLastUpdated !== -1) { + setCurrentPage(1); + } }, [quickFiltersLastUpdated]); const createFiltersForSelectedRowData = ( @@ -315,7 +333,11 @@ function K8sDeploymentsList({ const handleFiltersChange = useCallback( (value: IBuilderQuery['filters']): void => { handleChangeQueryData('filters', value); - setCurrentPage(1); + if (filtersInitialised) { + setCurrentPage(1); + } else { + setFiltersInitialised(true); + } if (value.items.length > 0) { logEvent(InfraMonitoringEvents.FilterApplied, { @@ -325,7 +347,8 @@ function K8sDeploymentsList({ }); } }, - [handleChangeQueryData], + // eslint-disable-next-line react-hooks/exhaustive-deps + [], ); useEffect(() => { diff --git a/frontend/src/container/InfraMonitoringK8s/EntityDetailsUtils/EntityEvents/EntityEvents.tsx b/frontend/src/container/InfraMonitoringK8s/EntityDetailsUtils/EntityEvents/EntityEvents.tsx index 97808f2d29..20037b8956 100644 --- a/frontend/src/container/InfraMonitoringK8s/EntityDetailsUtils/EntityEvents/EntityEvents.tsx +++ b/frontend/src/container/InfraMonitoringK8s/EntityDetailsUtils/EntityEvents/EntityEvents.tsx @@ -259,7 +259,7 @@ export default function Events({
({ [queries], ); + const [graphTimeIntervals, setGraphTimeIntervals] = useState< + { + start: number; + end: number; + }[] + >( + new Array(queries.length).fill({ + start: timeRange.startTime, + end: timeRange.endTime, + }), + ); + + useEffect(() => { + setGraphTimeIntervals( + new Array(queries.length).fill({ + start: timeRange.startTime, + end: timeRange.endTime, + }), + ); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [timeRange]); + + const onDragSelect = useCallback( + (start: number, end: number, graphIndex: number) => { + const startTimestamp = Math.trunc(start); + const endTimestamp = Math.trunc(end); + + setGraphTimeIntervals((prev) => { + const newIntervals = [...prev]; + newIntervals[graphIndex] = { + start: Math.floor(startTimestamp / 1000), + end: Math.floor(endTimestamp / 1000), + }; + return newIntervals; + }); + }, + [], + ); + const options = useMemo( () => queries.map(({ data }, idx) => { @@ -108,9 +147,9 @@ function EntityMetrics({ yAxisUnit: entityWidgetInfo[idx].yAxisUnit, softMax: null, softMin: null, - minTimeScale: timeRange.startTime, - maxTimeScale: timeRange.endTime, - enableZoom: true, + minTimeScale: graphTimeIntervals[idx].start, + maxTimeScale: graphTimeIntervals[idx].end, + onDragSelect: (start, end) => onDragSelect(start, end, idx), }); }), [ @@ -118,8 +157,8 @@ function EntityMetrics({ isDarkMode, dimensions, entityWidgetInfo, - timeRange.startTime, - timeRange.endTime, + graphTimeIntervals, + onDragSelect, ], ); diff --git a/frontend/src/container/InfraMonitoringK8s/EntityDetailsUtils/EntityTraces/EntityTraces.tsx b/frontend/src/container/InfraMonitoringK8s/EntityDetailsUtils/EntityTraces/EntityTraces.tsx index 925fa0e545..e0c367bf0c 100644 --- a/frontend/src/container/InfraMonitoringK8s/EntityDetailsUtils/EntityTraces/EntityTraces.tsx +++ b/frontend/src/container/InfraMonitoringK8s/EntityDetailsUtils/EntityTraces/EntityTraces.tsx @@ -177,7 +177,7 @@ function EntityTraces({
( (state) => state.globalTime, ); + const [searchParams, setSearchParams] = useSearchParams(); - const [currentPage, setCurrentPage] = useState(1); + const [currentPage, setCurrentPage] = useState(() => { + const page = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.CURRENT_PAGE); + if (page) { + return parseInt(page, 10); + } + return 1; + }); + const [filtersInitialised, setFiltersInitialised] = useState(false); + + useEffect(() => { + setSearchParams({ + ...Object.fromEntries(searchParams.entries()), + [INFRA_MONITORING_K8S_PARAMS_KEYS.CURRENT_PAGE]: currentPage.toString(), + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [currentPage]); const [expandedRowKeys, setExpandedRowKeys] = useState([]); - const [searchParams, setSearchParams] = useSearchParams(); const [orderBy, setOrderBy] = useState<{ columnName: string; @@ -112,7 +127,9 @@ function K8sJobsList({ // Reset pagination every time quick filters are changed useEffect(() => { - setCurrentPage(1); + if (quickFiltersLastUpdated !== -1) { + setCurrentPage(1); + } }, [quickFiltersLastUpdated]); const createFiltersForSelectedRowData = ( @@ -300,7 +317,11 @@ function K8sJobsList({ const handleFiltersChange = useCallback( (value: IBuilderQuery['filters']): void => { handleChangeQueryData('filters', value); - setCurrentPage(1); + if (filtersInitialised) { + setCurrentPage(1); + } else { + setFiltersInitialised(true); + } if (value.items.length > 0) { logEvent(InfraMonitoringEvents.FilterApplied, { @@ -310,7 +331,8 @@ function K8sJobsList({ }); } }, - [handleChangeQueryData], + // eslint-disable-next-line react-hooks/exhaustive-deps + [], ); useEffect(() => { diff --git a/frontend/src/container/InfraMonitoringK8s/K8sHeader.tsx b/frontend/src/container/InfraMonitoringK8s/K8sHeader.tsx index fa9eaf2d6f..f22519285f 100644 --- a/frontend/src/container/InfraMonitoringK8s/K8sHeader.tsx +++ b/frontend/src/container/InfraMonitoringK8s/K8sHeader.tsx @@ -136,7 +136,7 @@ function K8sHeader({
diff --git a/frontend/src/container/InfraMonitoringK8s/Namespaces/K8sNamespacesList.tsx b/frontend/src/container/InfraMonitoringK8s/Namespaces/K8sNamespacesList.tsx index 6f076132cf..4d2cc2a847 100644 --- a/frontend/src/container/InfraMonitoringK8s/Namespaces/K8sNamespacesList.tsx +++ b/frontend/src/container/InfraMonitoringK8s/Namespaces/K8sNamespacesList.tsx @@ -60,11 +60,26 @@ function K8sNamespacesList({ (state) => state.globalTime, ); - const [currentPage, setCurrentPage] = useState(1); - const [expandedRowKeys, setExpandedRowKeys] = useState([]); const [searchParams, setSearchParams] = useSearchParams(); + const [currentPage, setCurrentPage] = useState(() => { + const page = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.CURRENT_PAGE); + if (page) { + return parseInt(page, 10); + } + return 1; + }); + const [filtersInitialised, setFiltersInitialised] = useState(false); + + useEffect(() => { + setSearchParams({ + ...Object.fromEntries(searchParams.entries()), + [INFRA_MONITORING_K8S_PARAMS_KEYS.CURRENT_PAGE]: currentPage.toString(), + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [currentPage]); + const [orderBy, setOrderBy] = useState<{ columnName: string; order: 'asc' | 'desc'; @@ -116,7 +131,9 @@ function K8sNamespacesList({ // Reset pagination every time quick filters are changed useEffect(() => { - setCurrentPage(1); + if (quickFiltersLastUpdated !== -1) { + setCurrentPage(1); + } }, [quickFiltersLastUpdated]); const createFiltersForSelectedRowData = ( @@ -312,7 +329,11 @@ function K8sNamespacesList({ const handleFiltersChange = useCallback( (value: IBuilderQuery['filters']): void => { handleChangeQueryData('filters', value); - setCurrentPage(1); + if (filtersInitialised) { + setCurrentPage(1); + } else { + setFiltersInitialised(true); + } if (value.items.length > 0) { logEvent(InfraMonitoringEvents.FilterApplied, { @@ -322,7 +343,8 @@ function K8sNamespacesList({ }); } }, - [handleChangeQueryData], + // eslint-disable-next-line react-hooks/exhaustive-deps + [], ); useEffect(() => { diff --git a/frontend/src/container/InfraMonitoringK8s/Nodes/K8sNodesList.tsx b/frontend/src/container/InfraMonitoringK8s/Nodes/K8sNodesList.tsx index 441346980f..107a13454a 100644 --- a/frontend/src/container/InfraMonitoringK8s/Nodes/K8sNodesList.tsx +++ b/frontend/src/container/InfraMonitoringK8s/Nodes/K8sNodesList.tsx @@ -59,12 +59,26 @@ function K8sNodesList({ const { maxTime, minTime } = useSelector( (state) => state.globalTime, ); - - const [currentPage, setCurrentPage] = useState(1); - - const [expandedRowKeys, setExpandedRowKeys] = useState([]); const [searchParams, setSearchParams] = useSearchParams(); + const [currentPage, setCurrentPage] = useState(() => { + const page = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.CURRENT_PAGE); + if (page) { + return parseInt(page, 10); + } + return 1; + }); + const [filtersInitialised, setFiltersInitialised] = useState(false); + + useEffect(() => { + setSearchParams({ + ...Object.fromEntries(searchParams.entries()), + [INFRA_MONITORING_K8S_PARAMS_KEYS.CURRENT_PAGE]: currentPage.toString(), + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [currentPage]); + + const [expandedRowKeys, setExpandedRowKeys] = useState([]); const [orderBy, setOrderBy] = useState<{ columnName: string; order: 'asc' | 'desc'; @@ -111,7 +125,9 @@ function K8sNodesList({ // Reset pagination every time quick filters are changed useEffect(() => { - setCurrentPage(1); + if (quickFiltersLastUpdated !== -1) { + setCurrentPage(1); + } }, [quickFiltersLastUpdated]); const createFiltersForSelectedRowData = ( @@ -299,7 +315,11 @@ function K8sNodesList({ const handleFiltersChange = useCallback( (value: IBuilderQuery['filters']): void => { handleChangeQueryData('filters', value); - setCurrentPage(1); + if (filtersInitialised) { + setCurrentPage(1); + } else { + setFiltersInitialised(true); + } if (value.items.length > 0) { logEvent(InfraMonitoringEvents.FilterApplied, { @@ -309,7 +329,8 @@ function K8sNodesList({ }); } }, - [handleChangeQueryData], + // eslint-disable-next-line react-hooks/exhaustive-deps + [], ); useEffect(() => { diff --git a/frontend/src/container/InfraMonitoringK8s/Pods/K8sPodLists.tsx b/frontend/src/container/InfraMonitoringK8s/Pods/K8sPodLists.tsx index f6bc79171e..acbb003925 100644 --- a/frontend/src/container/InfraMonitoringK8s/Pods/K8sPodLists.tsx +++ b/frontend/src/container/InfraMonitoringK8s/Pods/K8sPodLists.tsx @@ -64,7 +64,22 @@ function K8sPodsList({ ); const [searchParams, setSearchParams] = useSearchParams(); - const [currentPage, setCurrentPage] = useState(1); + const [currentPage, setCurrentPage] = useState(() => { + const page = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.CURRENT_PAGE); + if (page) { + return parseInt(page, 10); + } + return 1; + }); + const [filtersInitialised, setFiltersInitialised] = useState(false); + + useEffect(() => { + setSearchParams({ + ...Object.fromEntries(searchParams.entries()), + [INFRA_MONITORING_K8S_PARAMS_KEYS.CURRENT_PAGE]: currentPage.toString(), + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [currentPage]); const [addedColumns, setAddedColumns] = useState([]); @@ -123,7 +138,9 @@ function K8sPodsList({ // Reset pagination every time quick filters are changed useEffect(() => { - setCurrentPage(1); + if (quickFiltersLastUpdated !== -1) { + setCurrentPage(1); + } }, [quickFiltersLastUpdated]); useEffect(() => { @@ -314,7 +331,11 @@ function K8sPodsList({ const handleFiltersChange = useCallback( (value: IBuilderQuery['filters']): void => { handleChangeQueryData('filters', value); - setCurrentPage(1); + if (filtersInitialised) { + setCurrentPage(1); + } else { + setFiltersInitialised(true); + } if (value.items.length > 0) { logEvent(InfraMonitoringEvents.FilterApplied, { @@ -324,7 +345,8 @@ function K8sPodsList({ }); } }, - [handleChangeQueryData], + // eslint-disable-next-line react-hooks/exhaustive-deps + [], ); const handleGroupByChange = useCallback( diff --git a/frontend/src/container/InfraMonitoringK8s/StatefulSets/K8sStatefulSetsList.tsx b/frontend/src/container/InfraMonitoringK8s/StatefulSets/K8sStatefulSetsList.tsx index ba2b14f8de..e2dae778f6 100644 --- a/frontend/src/container/InfraMonitoringK8s/StatefulSets/K8sStatefulSetsList.tsx +++ b/frontend/src/container/InfraMonitoringK8s/StatefulSets/K8sStatefulSetsList.tsx @@ -60,10 +60,26 @@ function K8sStatefulSetsList({ (state) => state.globalTime, ); - const [currentPage, setCurrentPage] = useState(1); + const [searchParams, setSearchParams] = useSearchParams(); + + const [currentPage, setCurrentPage] = useState(() => { + const page = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.CURRENT_PAGE); + if (page) { + return parseInt(page, 10); + } + return 1; + }); + const [filtersInitialised, setFiltersInitialised] = useState(false); + + useEffect(() => { + setSearchParams({ + ...Object.fromEntries(searchParams.entries()), + [INFRA_MONITORING_K8S_PARAMS_KEYS.CURRENT_PAGE]: currentPage.toString(), + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [currentPage]); const [expandedRowKeys, setExpandedRowKeys] = useState([]); - const [searchParams, setSearchParams] = useSearchParams(); const [orderBy, setOrderBy] = useState<{ columnName: string; @@ -116,7 +132,9 @@ function K8sStatefulSetsList({ // Reset pagination every time quick filters are changed useEffect(() => { - setCurrentPage(1); + if (quickFiltersLastUpdated !== -1) { + setCurrentPage(1); + } }, [quickFiltersLastUpdated]); const createFiltersForSelectedRowData = ( @@ -314,7 +332,11 @@ function K8sStatefulSetsList({ const handleFiltersChange = useCallback( (value: IBuilderQuery['filters']): void => { handleChangeQueryData('filters', value); - setCurrentPage(1); + if (filtersInitialised) { + setCurrentPage(1); + } else { + setFiltersInitialised(true); + } if (value.items.length > 0) { logEvent(InfraMonitoringEvents.FilterApplied, { @@ -324,7 +346,8 @@ function K8sStatefulSetsList({ }); } }, - [handleChangeQueryData], + // eslint-disable-next-line react-hooks/exhaustive-deps + [], ); useEffect(() => { diff --git a/frontend/src/container/InfraMonitoringK8s/Volumes/K8sVolumesList.tsx b/frontend/src/container/InfraMonitoringK8s/Volumes/K8sVolumesList.tsx index 9ba4a75448..aa9a1c69dd 100644 --- a/frontend/src/container/InfraMonitoringK8s/Volumes/K8sVolumesList.tsx +++ b/frontend/src/container/InfraMonitoringK8s/Volumes/K8sVolumesList.tsx @@ -60,10 +60,26 @@ function K8sVolumesList({ (state) => state.globalTime, ); - const [currentPage, setCurrentPage] = useState(1); + const [searchParams, setSearchParams] = useSearchParams(); + + const [currentPage, setCurrentPage] = useState(() => { + const page = searchParams.get(INFRA_MONITORING_K8S_PARAMS_KEYS.CURRENT_PAGE); + if (page) { + return parseInt(page, 10); + } + return 1; + }); + const [filtersInitialised, setFiltersInitialised] = useState(false); + + useEffect(() => { + setSearchParams({ + ...Object.fromEntries(searchParams.entries()), + [INFRA_MONITORING_K8S_PARAMS_KEYS.CURRENT_PAGE]: currentPage.toString(), + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [currentPage]); const [expandedRowKeys, setExpandedRowKeys] = useState([]); - const [searchParams, setSearchParams] = useSearchParams(); const [orderBy, setOrderBy] = useState<{ columnName: string; @@ -116,7 +132,9 @@ function K8sVolumesList({ // Reset pagination every time quick filters are changed useEffect(() => { - setCurrentPage(1); + if (quickFiltersLastUpdated !== -1) { + setCurrentPage(1); + } }, [quickFiltersLastUpdated]); const createFiltersForSelectedRowData = ( @@ -304,7 +322,11 @@ function K8sVolumesList({ const handleFiltersChange = useCallback( (value: IBuilderQuery['filters']): void => { handleChangeQueryData('filters', value); - setCurrentPage(1); + if (filtersInitialised) { + setCurrentPage(1); + } else { + setFiltersInitialised(true); + } if (value.items.length > 0) { logEvent(InfraMonitoringEvents.FilterApplied, { @@ -314,7 +336,8 @@ function K8sVolumesList({ }); } }, - [handleChangeQueryData], + // eslint-disable-next-line react-hooks/exhaustive-deps + [], ); useEffect(() => { diff --git a/frontend/src/container/InfraMonitoringK8s/constants.ts b/frontend/src/container/InfraMonitoringK8s/constants.ts index a8bc29351f..d182922421 100644 --- a/frontend/src/container/InfraMonitoringK8s/constants.ts +++ b/frontend/src/container/InfraMonitoringK8s/constants.ts @@ -538,4 +538,5 @@ export const INFRA_MONITORING_K8S_PARAMS_KEYS = { TRACES_FILTERS: 'tracesFilters', EVENTS_FILTERS: 'eventsFilters', HOSTS_FILTERS: 'hostsFilters', + CURRENT_PAGE: 'currentPage', }; diff --git a/frontend/src/container/TopNav/DateTimeSelectionV2/index.tsx b/frontend/src/container/TopNav/DateTimeSelectionV2/index.tsx index e4c764ea3e..b390798bab 100644 --- a/frontend/src/container/TopNav/DateTimeSelectionV2/index.tsx +++ b/frontend/src/container/TopNav/DateTimeSelectionV2/index.tsx @@ -835,6 +835,7 @@ function DateTimeSelection({ onCustomDateHandler={onCustomDateHandler} customDateTimeVisible={customDateTimeVisible} setCustomDTPickerVisible={setCustomDTPickerVisible} + onTimeChange={onTimeChange} /> {showAutoRefresh && selectedTime !== 'custom' && (