diff --git a/src/common/Pagination/Pagination.js b/src/common/Pagination/Pagination.js index 0f5006df0..4dcd57781 100644 --- a/src/common/Pagination/Pagination.js +++ b/src/common/Pagination/Pagination.js @@ -45,7 +45,12 @@ import './pagination.scss' const threeDotsString = '...' -const Pagination = ({ closeParamName = '', paginationConfig }) => { +const Pagination = ({ + closeParamName = '', + disableNextDoubleBtn = false, + disabledNextDoubleBtnTooltip = '', + paginationConfig +}) => { const [, setSearchParams] = useSearchParams() const navigate = useNavigate() const paginationPagesRef = useRef() @@ -63,11 +68,12 @@ const Pagination = ({ closeParamName = '', paginationConfig }) => { prevBtn: paginationConfig[FE_PAGE] === 1, prevDoubleBtn: paginationConfig[BE_PAGE] === 1, nextBtn: - paginationConfig[FE_PAGE] === paginationConfig[FE_PAGE_END] && - !paginationConfig.paginationResponse?.['page-token'], - nextDoubleBtn: !paginationConfig.paginationResponse?.['page-token'] + (paginationConfig[FE_PAGE] === paginationConfig[FE_PAGE_END] && disableNextDoubleBtn) || + (paginationConfig[FE_PAGE] === paginationConfig[FE_PAGE_END] && + !paginationConfig.paginationResponse?.['page-token']), + nextDoubleBtn: disableNextDoubleBtn || !paginationConfig.paginationResponse?.['page-token'] } - }, [paginationConfig]) + }, [disableNextDoubleBtn, paginationConfig]) const prevDoubleBtnTooltip = useMemo(() => { const visiblePagesCount = paginationConfig[BE_PAGE_SIZE] / paginationConfig[FE_PAGE_SIZE] @@ -289,9 +295,11 @@ const Pagination = ({ closeParamName = '', paginationConfig }) => { className="pagination-navigate-btn" onClick={() => goToNextBePage()} tooltipText={ - !navigationDisableState.nextDoubleBtn - ? `Load page ${paginationConfig[FE_PAGE_END] + 1}+` - : '' + navigationDisableState.nextDoubleBtn && disabledNextDoubleBtnTooltip + ? disabledNextDoubleBtnTooltip + : !navigationDisableState.nextDoubleBtn + ? `Load page ${paginationConfig[FE_PAGE_END] + 1}+` + : '' } disabled={navigationDisableState.nextDoubleBtn} > @@ -307,6 +315,8 @@ const Pagination = ({ closeParamName = '', paginationConfig }) => { Pagination.propTypes = { closeParamName: PropTypes.string, + disableNextDoubleBtn: PropTypes.bool, + disabledNextDoubleBtnTooltip: PropTypes.string, paginationConfig: PAGINATION_CONFIG.isRequired } diff --git a/src/components/ActionBar/ActionBar.js b/src/components/ActionBar/ActionBar.js index c5a6b62af..a8f0fe58b 100644 --- a/src/components/ActionBar/ActionBar.js +++ b/src/components/ActionBar/ActionBar.js @@ -39,13 +39,14 @@ import { DATES_FILTER, GROUP_BY_NAME, GROUP_BY_NONE, + INTERNAL_AUTO_REFRESH_ID, NAME_FILTER, REQUEST_CANCELED, TAG_FILTER_ALL_ITEMS } from '../../constants' import detailsActions from '../../actions/details' import { FILTERS_CONFIG } from '../../types' -import { setFilters } from '../../reducers/filtersReducer' +import { setFilters, toggleAutoRefresh } from '../../reducers/filtersReducer' import { setFieldState } from 'igz-controls/utils/form.util' import { CUSTOM_RANGE_DATE_OPTION } from '../../utils/datePicker.util' @@ -58,22 +59,31 @@ const ActionBar = ({ allRowsAreExpanded, autoRefreshIsEnabled = false, autoRefreshIsStopped = false, + autoRefreshStopTrigger = false, cancelRequest = null, children, filters, filtersConfig, + handleAutoRefreshPrevValueChange, handleRefresh, hidden = false, + internalAutoRefreshIsEnabled = false, navigateLink, removeSelectedItem = null, setSearchParams, setSelectedRowData = null, tab = '', toggleAllRows, + withAutoRefresh = false, + withInternalAutoRefresh = false, withRefreshButton = true, withoutExpandButton }) => { const [autoRefresh, setAutoRefresh] = useState(autoRefreshIsEnabled) + const [internalAutoRefresh, setInternalAutoRefresh] = useState(internalAutoRefreshIsEnabled) + const [internalAutoRefreshPrevValue, setInternalAutoRefreshPrevValue] = useState( + internalAutoRefreshIsEnabled + ) const filtersStore = useSelector(store => store.filtersStore) const changes = useSelector(store => store.detailsStore.changes) const dispatch = useDispatch() @@ -102,7 +112,8 @@ const ActionBar = ({ const formInitialValues = useMemo(() => { const initialValues = { - [AUTO_REFRESH_ID]: autoRefreshIsEnabled + [AUTO_REFRESH_ID]: autoRefreshIsEnabled, + [INTERNAL_AUTO_REFRESH_ID]: internalAutoRefreshIsEnabled } for (const [filterName, filterConfig] of Object.entries(filtersConfig)) { @@ -112,7 +123,7 @@ const ActionBar = ({ } return initialValues - }, [autoRefreshIsEnabled, filtersConfig]) + }, [autoRefreshIsEnabled, filtersConfig, internalAutoRefreshIsEnabled]) const formRef = React.useRef( createForm({ @@ -278,7 +289,7 @@ const ActionBar = ({ }, [filterMenu, filtersConfig]) useEffect(() => { - if (autoRefreshIsEnabled && autoRefresh && !hidden) { + if ((autoRefresh || internalAutoRefresh) && !hidden) { const intervalId = setInterval(() => { if (!autoRefreshIsStopped) { refresh(formRef.current.getState()) @@ -287,7 +298,35 @@ const ActionBar = ({ return () => clearInterval(intervalId) } - }, [autoRefresh, autoRefreshIsStopped, hidden, autoRefreshIsEnabled, refresh]) + }, [ + autoRefresh, + autoRefreshIsStopped, + hidden, + refresh, + internalAutoRefresh, + withInternalAutoRefresh + ]) + + useEffect(() => { + if (autoRefreshStopTrigger && internalAutoRefresh) { + formRef.current?.change(INTERNAL_AUTO_REFRESH_ID, false) + setInternalAutoRefreshPrevValue(true) + dispatch(toggleAutoRefresh(false)) + handleAutoRefreshPrevValueChange && handleAutoRefreshPrevValueChange(true) + } else if (!autoRefreshStopTrigger && internalAutoRefreshPrevValue) { + setInternalAutoRefreshPrevValue(false) + setInternalAutoRefresh(true) + dispatch(toggleAutoRefresh(true)) + formRef.current?.change(INTERNAL_AUTO_REFRESH_ID, true) + handleAutoRefreshPrevValueChange && handleAutoRefreshPrevValueChange(false) + } + }, [ + internalAutoRefreshPrevValue, + autoRefreshStopTrigger, + internalAutoRefresh, + handleAutoRefreshPrevValueChange, + dispatch + ]) useLayoutEffect(() => { formRef.current.reset(formInitialValues) @@ -361,14 +400,35 @@ const ActionBar = ({ /> )) )} - {autoRefreshIsEnabled && ( + {withAutoRefresh && !withInternalAutoRefresh && ( )} - + { + dispatch(toggleAutoRefresh(value)) + setAutoRefresh(value) + }} + name={AUTO_REFRESH_ID} + /> + {withInternalAutoRefresh && ( + + )} + { + setInternalAutoRefresh(value) + dispatch(toggleAutoRefresh(value)) + }} + name={INTERNAL_AUTO_REFRESH_ID} + /> {withRefreshButton && ( refresh(formState)} id="refresh"> @@ -425,4 +485,4 @@ ActionBar.propTypes = { withoutExpandButton: PropTypes.bool } -export default ActionBar +export default React.memo(ActionBar) diff --git a/src/components/Jobs/Jobs.js b/src/components/Jobs/Jobs.js index 51be0d51e..c2d6d6cb4 100755 --- a/src/components/Jobs/Jobs.js +++ b/src/components/Jobs/Jobs.js @@ -64,6 +64,7 @@ export const JobsContext = React.createContext({}) const Jobs = () => { const [confirmData, setConfirmData] = useState(null) const [selectedTab, setSelectedTab] = useState(null) + const [autoRefreshPrevValue, setAutoRefreshPrevValue] = useState(false) const [selectedJob, setSelectedJob] = useState({}) const params = useParams() const navigate = useNavigate() @@ -230,18 +231,19 @@ const Jobs = () => { onClick: () => handleMonitoring(selectedJob, true) } ]} - autoRefreshIsEnabled={selectedTab === MONITOR_JOBS_TAB} - autoRefreshIsStopped={ - jobWizardIsOpened || jobsStore.loading || !isEmpty(selectedJob) - } + autoRefreshIsStopped={jobWizardIsOpened || jobsStore.loading} + autoRefreshStopTrigger={!isEmpty(selectedJob)} filters={filters} filtersConfig={tabData[selectedTab].filtersConfig} handleRefresh={tabData[selectedTab].handleRefresh} + handleAutoRefreshPrevValueChange={setAutoRefreshPrevValue} hidden={Boolean(params.workflowId)} key={selectedTab} page={JOBS_MONITORING_PAGE} setSearchParams={setSearchParams} tab={selectedTab} + withAutoRefresh + withInternalAutoRefresh={params.jobName} withRefreshButton withoutExpandButton > @@ -259,6 +261,7 @@ const Jobs = () => { getWorkflows, handleMonitoring, handleRerunJob, + autoRefreshPrevValue, jobRuns, jobWizardIsOpened, jobWizardMode, diff --git a/src/components/Jobs/MonitorJobs/MonitorJobs.js b/src/components/Jobs/MonitorJobs/MonitorJobs.js index 586c0bd8a..0e619c196 100644 --- a/src/components/Jobs/MonitorJobs/MonitorJobs.js +++ b/src/components/Jobs/MonitorJobs/MonitorJobs.js @@ -41,6 +41,7 @@ const MonitorJobs = () => { abortJobRef, abortingJobs, fetchJobFunctionsPromiseRef, + autoRefreshPrevValue, jobRuns, jobs, jobsFiltersConfig, @@ -109,6 +110,7 @@ const MonitorJobs = () => { context={JobsContext} filters={filters} filtersConfig={jobsFiltersConfig} + autoRefreshPrevValue={autoRefreshPrevValue} jobRuns={jobRuns} jobs={jobs} navigateLink={getBackLink()} diff --git a/src/constants.js b/src/constants.js index fd210bf4d..fa1ecb4d8 100644 --- a/src/constants.js +++ b/src/constants.js @@ -530,6 +530,7 @@ export const SORT_BY = 'sortBy' export const STATUS_FILTER = 'state' export const TAG_FILTER = 'tag' export const AUTO_REFRESH_ID = 'auto-refresh' +export const INTERNAL_AUTO_REFRESH_ID = 'internal-auto-refresh' export const AUTO_REFRESH = 'Auto Refresh' export const ANY_TIME = 'Any time' export const STATUS_FILTER_NAME = 'state' diff --git a/src/elements/JobsTable/JobsTable.js b/src/elements/JobsTable/JobsTable.js index 4460dbd58..ce452fb40 100644 --- a/src/elements/JobsTable/JobsTable.js +++ b/src/elements/JobsTable/JobsTable.js @@ -59,6 +59,7 @@ const JobsTable = React.forwardRef( context, filters, filtersConfig, + autoRefreshPrevValue, paginatedJobs, refreshJobs, requestErrorMessage, @@ -373,6 +374,14 @@ const JobsTable = React.forwardRef( ) diff --git a/src/hooks/usePagination.hook.js b/src/hooks/usePagination.hook.js index 477119903..cd8b9f688 100644 --- a/src/hooks/usePagination.hook.js +++ b/src/hooks/usePagination.hook.js @@ -31,6 +31,7 @@ import { ITEMS_COUNT_END, ITEMS_COUNT_START } from '../constants' +import { useSelector } from 'react-redux' export const usePagination = ({ bePageSize = 1000, @@ -45,6 +46,7 @@ export const usePagination = ({ const [searchParams, setSearchParams] = useSearchParams() const [paginatedContent, setPaginatedContent] = useState([]) const resetPaginationTriggerRef = useRef(resetPaginationTrigger) + const filtersStore = useSelector(store => store.filtersStore) const refreshContentDebounced = useMemo(() => { return debounce(filters => refreshContent(filters)) @@ -190,6 +192,19 @@ export const usePagination = ({ } }, [paginationConfigRef, content, searchParams, setSearchParams, hidden]) + useEffect(() => { + if (filtersStore.autoRefresh && paginationConfigRef.current[BE_PAGE] > 1) { + setSearchParams( + prevSearchParams => { + prevSearchParams.set(BE_PAGE, 1) + prevSearchParams.set(FE_PAGE, 1) + return prevSearchParams + }, + { replace: true } + ) + } + }, [filtersStore.autoRefresh, paginationConfigRef, setSearchParams]) + const handleRefresh = (filters, filtersChange) => { if (filtersChange && (searchParams.get(BE_PAGE) !== '1' || searchParams.get(FE_PAGE) !== '1')) { resetPagination(true) diff --git a/src/reducers/filtersReducer.js b/src/reducers/filtersReducer.js index d48252153..b7326cb91 100644 --- a/src/reducers/filtersReducer.js +++ b/src/reducers/filtersReducer.js @@ -32,7 +32,7 @@ import { const initialState = { groupBy: GROUP_BY_NAME, iter: SHOW_ITERATIONS, - + autoRefresh: false, tagOptions: null, projectOptions: [], [FILTER_MENU_MODAL]: {} @@ -98,6 +98,9 @@ const filtersSlice = createSlice({ }, setFilterProjectOptions(state, action) { state.projectOptions = action.payload + }, + toggleAutoRefresh(state, action) { + state.autoRefresh = action.payload } }, extraReducers: builder => { @@ -115,7 +118,8 @@ export const { setFiltersValues, setModalFiltersValues, setModalFiltersInitialValues, - setFilterProjectOptions + setFilterProjectOptions, + toggleAutoRefresh } = filtersSlice.actions export default filtersSlice.reducer