From 1f18af5e004049f93236a1feaaf0f0169cddf0c7 Mon Sep 17 00:00:00 2001 From: Taras Hlukhovetskyi Date: Fri, 10 Apr 2026 16:51:27 +0300 Subject: [PATCH 1/4] [UI] Date picker not synced with 'no data' message time --- src/common/DatePicker/DatePicker.jsx | 6 +-- src/components/ActionBar/ActionBar.jsx | 49 ++++++++++++++++--- src/components/Alerts/Alerts.jsx | 3 +- src/components/FunctionsPage/Functions.jsx | 3 +- .../FunctionsPageOld/FunctionsOld.jsx | 3 +- src/components/Jobs/Jobs.jsx | 3 +- .../MonitoringApplicationsPage.jsx | 3 +- src/hooks/useFiltersFromSearchParams.hook.js | 24 +++++++-- src/reducers/filtersReducer.js | 3 +- 9 files changed, 77 insertions(+), 20 deletions(-) diff --git a/src/common/DatePicker/DatePicker.jsx b/src/common/DatePicker/DatePicker.jsx index 85c006f2e7..dd27fcc8ad 100644 --- a/src/common/DatePicker/DatePicker.jsx +++ b/src/common/DatePicker/DatePicker.jsx @@ -54,14 +54,14 @@ import { isTargetElementInContainerElement } from '../../utils/checkElementsPosi const defaultProps = { date: new Date(), - dateTo: null + setExternalInvalid: () => {} } const DatePicker = ({ className = '', customOptions = null, date = defaultProps.date, - dateTo = defaultProps.dateTo, + dateTo = null, disabled = false, excludeCustomRange = false, externalInvalid = null, @@ -72,7 +72,7 @@ const DatePicker = ({ required = false, requiredText = 'This field is required', selectedOptionId = '', - setExternalInvalid = () => {}, + setExternalInvalid = defaultProps.setExternalInvalid, timeFrameLimit = Infinity, tip = '', type = 'date', diff --git a/src/components/ActionBar/ActionBar.jsx b/src/components/ActionBar/ActionBar.jsx index 92c0b6b68d..16d1e1cc52 100644 --- a/src/components/ActionBar/ActionBar.jsx +++ b/src/components/ActionBar/ActionBar.jsx @@ -44,7 +44,13 @@ import { REQUEST_CANCELED, TAG_FILTER_ALL_ITEMS } from '../../constants' -import { CUSTOM_RANGE_DATE_OPTION } from '../../utils/datePicker.util' +import { + ANY_TIME_DATE_OPTION, + CUSTOM_RANGE_DATE_OPTION, + datePickerFutureOptions, + datePickerPastOptions, + getDatePickerFilterValue +} from '../../utils/datePicker.util' import { FILTERS_CONFIG } from '../../types' import { getCloseDetailsLink } from '../../utils/link-helper.util' import { setFieldState } from 'igz-controls/utils/form.util' @@ -189,13 +195,36 @@ const ActionBar = ({ [filtersConfig, setSearchParams, withoutSearchParams] ) + const updateRelativeTimeValue = useCallback( + filters => { + if ( + filters[DATES_FILTER]?.initialSelectedOptionId && + filters[DATES_FILTER].initialSelectedOptionId !== CUSTOM_RANGE_DATE_OPTION && + filters[DATES_FILTER].initialSelectedOptionId !== ANY_TIME_DATE_OPTION + ) { + const isFuture = filtersConfig[DATES_FILTER]?.isFuture + const options = isFuture ? datePickerFutureOptions : datePickerPastOptions + + filters[DATES_FILTER] = getDatePickerFilterValue( + options, + filters[DATES_FILTER].initialSelectedOptionId, + isFuture + ) + formRef.current.change(DATES_FILTER, filters[DATES_FILTER]) + dispatch(setFilters({ relativeDateChange: Date.now() })) + } + }, + [dispatch, filtersConfig] + ) + const applyFilters = useCallback( async (formValues, filters, actionCanBePerformedChecked) => { const actionCanBePerformed = actionCanBePerformedChecked || (await performDetailsActionHelper(changes, dispatch, true)) - const newFilters = { ...filters, ...formValues } if (actionCanBePerformed) { + const newFilters = { ...filters, ...formValues } + if (closeParamName) { navigate(getCloseDetailsLink(closeParamName, true, selectedItemName), { replace: true }) } @@ -216,6 +245,7 @@ const ActionBar = ({ if (withoutSearchParams) { setLocalFilters(newFilters) } else { + updateRelativeTimeValue(newFilters) saveFilters(newFilters) } @@ -228,17 +258,18 @@ const ActionBar = ({ [ changes, dispatch, + updateRelativeTimeValue, closeParamName, filtersStore.groupBy, - saveFilters, + withoutSearchParams, removeSelectedItem, setSelectedRowData, toggleAllRows, handleRefresh, navigate, selectedItemName, - withoutSearchParams, - setLocalFilters + setLocalFilters, + saveFilters ] ) @@ -258,6 +289,7 @@ const ActionBar = ({ if (withoutSearchParams) { setLocalFilters(newFilters) } else { + updateRelativeTimeValue(newFilters) saveFilters(formState.values) } @@ -269,11 +301,12 @@ const ActionBar = ({ changes, dispatch, cancelRequest, - saveFilters, - handleRefresh, filters, + updateRelativeTimeValue, withoutSearchParams, - setLocalFilters + handleRefresh, + setLocalFilters, + saveFilters ] ) diff --git a/src/components/Alerts/Alerts.jsx b/src/components/Alerts/Alerts.jsx index 6324c2a856..21ea34a68f 100644 --- a/src/components/Alerts/Alerts.jsx +++ b/src/components/Alerts/Alerts.jsx @@ -53,7 +53,8 @@ const Alerts = () => { const params = useParams() const isCrossProjects = useMemo(() => projectId === '*', [projectId]) - const alertsFiltersConfig = useMemo(() => getAlertsFiltersConfig(), []) + // eslint-disable-next-line react-hooks/exhaustive-deps + const alertsFiltersConfig = useMemo(() => getAlertsFiltersConfig(), [params.projectName]) const alertsFilters = useFiltersFromSearchParams( alertsFiltersConfig, diff --git a/src/components/FunctionsPage/Functions.jsx b/src/components/FunctionsPage/Functions.jsx index d86b0fc179..3f0cac10f1 100644 --- a/src/components/FunctionsPage/Functions.jsx +++ b/src/components/FunctionsPage/Functions.jsx @@ -121,7 +121,8 @@ const Functions = ({ isAllVersions = false }) => { hidden: !isAllVersions } } - }, [isAllVersions]) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isAllVersions, params.projectName]) const detailsFormInitialValues = useMemo(() => { return { diff --git a/src/components/FunctionsPageOld/FunctionsOld.jsx b/src/components/FunctionsPageOld/FunctionsOld.jsx index 830a168e00..93aade803d 100644 --- a/src/components/FunctionsPageOld/FunctionsOld.jsx +++ b/src/components/FunctionsPageOld/FunctionsOld.jsx @@ -121,7 +121,8 @@ const Functions = () => { }, [SHOW_UNTAGGED_FILTER]: { label: 'Show untagged:', initialValue: false, isModal: true } } - }, []) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [params.projectName]) const functionsFilters = useFiltersFromSearchParams(functionsFiltersConfig) diff --git a/src/components/Jobs/Jobs.jsx b/src/components/Jobs/Jobs.jsx index 89655da763..554fec7c7d 100644 --- a/src/components/Jobs/Jobs.jsx +++ b/src/components/Jobs/Jobs.jsx @@ -92,7 +92,8 @@ const Jobs = () => { parseQueryParamsCallback: parseScheduledQueryParamsCallback } } - }, [params.jobName]) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [params.jobName, params.projectName, selectedTab]) const { abortControllerRef, diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx index 6e295b3c89..a66df8df7e 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx @@ -48,7 +48,8 @@ const MonitoringApplicationsPage = () => { const dispatch = useDispatch() const params = useParams() const navigate = useNavigate() - const filtersConfig = useMemo(() => getFiltersConfig(), []) + // eslint-disable-next-line react-hooks/exhaustive-deps + const filtersConfig = useMemo(() => getFiltersConfig(), [params.projectName]) const filters = useFiltersFromSearchParams(filtersConfig) const [, setSearchParams] = useSearchParams() const contentRef = useRef(null) diff --git a/src/hooks/useFiltersFromSearchParams.hook.js b/src/hooks/useFiltersFromSearchParams.hook.js index 4e0d8aea21..97b45054ed 100644 --- a/src/hooks/useFiltersFromSearchParams.hook.js +++ b/src/hooks/useFiltersFromSearchParams.hook.js @@ -19,13 +19,15 @@ such restriction. */ import { useMemo } from 'react' import { mapValues, isNil, pickBy } from 'lodash' +import { useSelector } from 'react-redux' +import { useSearchParams } from 'react-router-dom' + import { DATES_FILTER, ITERATIONS_FILTER, SHOW_ITERATIONS, SHOW_UNTAGGED_FILTER } from '../constants' -import { useSearchParams } from 'react-router-dom' import { datePickerFutureOptions, datePickerPastOptions, @@ -42,7 +44,19 @@ const getFiltersFromSearchParams = (filtersConfig, searchParams, paramsParsingCa return mapValues(filtersConfigToApply, (filterConfig, filterName) => { const searchParamValue = searchParams.get(filterName)?.trim?.() - if (isNil(searchParamValue)) return filterConfig.initialValue + if (isNil(searchParamValue)) { + if (filterName === DATES_FILTER) { + return ( + getDatePickerFilterValue( + filterConfig.isFuture ? datePickerFutureOptions : datePickerPastOptions, + filterConfig.initialValue.initialSelectedOptionId, + filterConfig.isFuture + ) ?? filterConfig.initialValue + ) + } + + return filterConfig.initialValue + } let parsedValue = paramsParsingCallback(filterName, searchParamValue) @@ -80,10 +94,14 @@ export const useFiltersFromSearchParams = ( filtersConfig = null, paramsParsingCallback = defaultParamsParsingCallback ) => { + const relativeDateChange = useSelector(store => store.filtersStore.relativeDateChange) const [searchParams] = useSearchParams() const filters = useMemo(() => { return getFiltersFromSearchParams(filtersConfig, searchParams, paramsParsingCallback) - }, [filtersConfig, paramsParsingCallback, searchParams]) + // relativeDateChange is a signal-only dep: it forces re-execution so that relative date + // options (e.g. "Last week") are recalculated with fresh timestamps on each apply. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [filtersConfig, paramsParsingCallback, searchParams, relativeDateChange]) return filters } diff --git a/src/reducers/filtersReducer.js b/src/reducers/filtersReducer.js index e86a6feb98..93e6e46ea8 100644 --- a/src/reducers/filtersReducer.js +++ b/src/reducers/filtersReducer.js @@ -29,7 +29,8 @@ const initialState = { internalAutoRefresh: false, tagOptions: null, projectOptions: [], - [FILTER_MENU_MODAL]: {} + [FILTER_MENU_MODAL]: {}, + relativeDateChange: null } export const getFilterTagOptions = createAsyncThunk( From a8a4523cc00e710f648a2c93142a3019db4e1167 Mon Sep 17 00:00:00 2001 From: Taras Hlukhovetskyi Date: Fri, 10 Apr 2026 16:53:59 +0300 Subject: [PATCH 2/4] formatting --- src/components/ActionBar/ActionBar.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ActionBar/ActionBar.jsx b/src/components/ActionBar/ActionBar.jsx index 16d1e1cc52..2a265731d4 100644 --- a/src/components/ActionBar/ActionBar.jsx +++ b/src/components/ActionBar/ActionBar.jsx @@ -204,7 +204,7 @@ const ActionBar = ({ ) { const isFuture = filtersConfig[DATES_FILTER]?.isFuture const options = isFuture ? datePickerFutureOptions : datePickerPastOptions - + filters[DATES_FILTER] = getDatePickerFilterValue( options, filters[DATES_FILTER].initialSelectedOptionId, From 08057395b096be375845f8e94c4354ca0d434458 Mon Sep 17 00:00:00 2001 From: Taras Hlukhovetskyi Date: Tue, 14 Apr 2026 17:32:52 +0300 Subject: [PATCH 3/4] fix PR comments --- src/components/Alerts/Alerts.jsx | 6 +++--- src/components/FunctionsPage/Functions.jsx | 9 ++++++--- .../FunctionsPageOld/FunctionsOld.jsx | 9 ++++++--- src/components/Jobs/Jobs.jsx | 3 ++- .../MonitoringApplicationsPage.jsx | 5 ++--- src/hooks/useFiltersFromSearchParams.hook.js | 17 +++++++++++------ 6 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/components/Alerts/Alerts.jsx b/src/components/Alerts/Alerts.jsx index 21ea34a68f..1e39b22153 100644 --- a/src/components/Alerts/Alerts.jsx +++ b/src/components/Alerts/Alerts.jsx @@ -53,12 +53,12 @@ const Alerts = () => { const params = useParams() const isCrossProjects = useMemo(() => projectId === '*', [projectId]) - // eslint-disable-next-line react-hooks/exhaustive-deps - const alertsFiltersConfig = useMemo(() => getAlertsFiltersConfig(), [params.projectName]) + const alertsFiltersConfig = useMemo(() => getAlertsFiltersConfig(), []) const alertsFilters = useFiltersFromSearchParams( alertsFiltersConfig, - parseAlertsQueryParamsCallback + parseAlertsQueryParamsCallback, + params.projectName ) const { diff --git a/src/components/FunctionsPage/Functions.jsx b/src/components/FunctionsPage/Functions.jsx index 3f0cac10f1..19ebe69555 100644 --- a/src/components/FunctionsPage/Functions.jsx +++ b/src/components/FunctionsPage/Functions.jsx @@ -121,8 +121,7 @@ const Functions = ({ isAllVersions = false }) => { hidden: !isAllVersions } } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isAllVersions, params.projectName]) + }, [isAllVersions]) const detailsFormInitialValues = useMemo(() => { return { @@ -132,7 +131,11 @@ const Functions = ({ isAllVersions = false }) => { } }, [selectedFunction.node_selector]) - const functionsFilters = useFiltersFromSearchParams(functionsFiltersConfig) + const functionsFilters = useFiltersFromSearchParams( + functionsFiltersConfig, + undefined, + params.projectName + ) const terminateDeleteTasksPolling = useCallback(() => { terminatePollRef?.current?.() diff --git a/src/components/FunctionsPageOld/FunctionsOld.jsx b/src/components/FunctionsPageOld/FunctionsOld.jsx index 93aade803d..b56b64d580 100644 --- a/src/components/FunctionsPageOld/FunctionsOld.jsx +++ b/src/components/FunctionsPageOld/FunctionsOld.jsx @@ -121,10 +121,13 @@ const Functions = () => { }, [SHOW_UNTAGGED_FILTER]: { label: 'Show untagged:', initialValue: false, isModal: true } } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [params.projectName]) + }, []) - const functionsFilters = useFiltersFromSearchParams(functionsFiltersConfig) + const functionsFilters = useFiltersFromSearchParams( + functionsFiltersConfig, + undefined, + params.projectName + ) const terminateDeleteTasksPolling = useCallback(() => { terminatePollRef?.current?.() diff --git a/src/components/Jobs/Jobs.jsx b/src/components/Jobs/Jobs.jsx index 554fec7c7d..ee7fb31042 100644 --- a/src/components/Jobs/Jobs.jsx +++ b/src/components/Jobs/Jobs.jsx @@ -198,7 +198,8 @@ const Jobs = () => { const filters = useFiltersFromSearchParams( initialTabData[selectedTab]?.filtersConfig, - initialTabData[selectedTab]?.parseQueryParamsCallback + initialTabData[selectedTab]?.parseQueryParamsCallback, + `${params.projectName}+${selectedTab}` ) return ( diff --git a/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx b/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx index a66df8df7e..12e61c9919 100644 --- a/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx +++ b/src/components/MonitoringApplicationsPage/MonitoringApplicationsPage.jsx @@ -48,9 +48,8 @@ const MonitoringApplicationsPage = () => { const dispatch = useDispatch() const params = useParams() const navigate = useNavigate() - // eslint-disable-next-line react-hooks/exhaustive-deps - const filtersConfig = useMemo(() => getFiltersConfig(), [params.projectName]) - const filters = useFiltersFromSearchParams(filtersConfig) + const filtersConfig = useMemo(() => getFiltersConfig(), []) + const filters = useFiltersFromSearchParams(filtersConfig, undefined, params.projectName) const [, setSearchParams] = useSearchParams() const contentRef = useRef(null) diff --git a/src/hooks/useFiltersFromSearchParams.hook.js b/src/hooks/useFiltersFromSearchParams.hook.js index 97b45054ed..5277923ba9 100644 --- a/src/hooks/useFiltersFromSearchParams.hook.js +++ b/src/hooks/useFiltersFromSearchParams.hook.js @@ -92,16 +92,21 @@ export const getInitialFiltersByConfig = (filtersConfig = {}) => { export const useFiltersFromSearchParams = ( filtersConfig = null, - paramsParsingCallback = defaultParamsParsingCallback + paramsParsingCallback = defaultParamsParsingCallback, + triggerKey = '' ) => { const relativeDateChange = useSelector(store => store.filtersStore.relativeDateChange) const [searchParams] = useSearchParams() const filters = useMemo(() => { - return getFiltersFromSearchParams(filtersConfig, searchParams, paramsParsingCallback) - // relativeDateChange is a signal-only dep: it forces re-execution so that relative date - // options (e.g. "Last week") are recalculated with fresh timestamps on each apply. - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [filtersConfig, paramsParsingCallback, searchParams, relativeDateChange]) + // triggerKey and relativeDateChange are added to dependencies to trigger date (timestamp for relative time) filter recalculation + return getFiltersFromSearchParams( + filtersConfig, + searchParams, + paramsParsingCallback, + triggerKey, + relativeDateChange + ) + }, [filtersConfig, paramsParsingCallback, searchParams, relativeDateChange, triggerKey]) return filters } From dad2895770d4c7c72106bec67b20b1d008019f16 Mon Sep 17 00:00:00 2001 From: Taras Hlukhovetskyi Date: Tue, 14 Apr 2026 17:34:25 +0300 Subject: [PATCH 4/4] formatting --- src/hooks/useFiltersFromSearchParams.hook.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useFiltersFromSearchParams.hook.js b/src/hooks/useFiltersFromSearchParams.hook.js index 5277923ba9..4ae07395ef 100644 --- a/src/hooks/useFiltersFromSearchParams.hook.js +++ b/src/hooks/useFiltersFromSearchParams.hook.js @@ -98,7 +98,7 @@ export const useFiltersFromSearchParams = ( const relativeDateChange = useSelector(store => store.filtersStore.relativeDateChange) const [searchParams] = useSearchParams() const filters = useMemo(() => { - // triggerKey and relativeDateChange are added to dependencies to trigger date (timestamp for relative time) filter recalculation + // triggerKey and relativeDateChange are added to dependencies to trigger date (timestamp for relative time) filter recalculation return getFiltersFromSearchParams( filtersConfig, searchParams,