diff --git a/src/components/InventoryTable/EntityTableToolbar.js b/src/components/InventoryTable/EntityTableToolbar.js index 8db2fc7b8..7e69f513d 100644 --- a/src/components/InventoryTable/EntityTableToolbar.js +++ b/src/components/InventoryTable/EntityTableToolbar.js @@ -220,7 +220,7 @@ const EntityTableToolbar = ({ * @param {*} debounced if debounce function should be used. */ const onSetTextFilter = (value, debounced = true) => { - const trimmedValue = value.trim(); + const trimmedValue = value?.trim(); const textualFilter = filters?.find(oneFilter => oneFilter.value === TEXT_FILTER); if (textualFilter) { diff --git a/src/components/InventoryTable/InventoryTable.js b/src/components/InventoryTable/InventoryTable.js index 1565553a8..6dca45f4b 100644 --- a/src/components/InventoryTable/InventoryTable.js +++ b/src/components/InventoryTable/InventoryTable.js @@ -11,6 +11,7 @@ import AccessDenied from '../../Utilities/AccessDenied'; import { loadSystems } from '../../Utilities/sharedFunctions'; import isEqual from 'lodash/isEqual'; import { entitiesLoading } from '../../store/actions'; +import cloneDeep from 'lodash/cloneDeep'; /** * A helper function to store props and to always return the latest state. @@ -18,14 +19,17 @@ import { entitiesLoading } from '../../store/actions'; * to get the latest props and not the props at the time of when the function is * being wrapped in callback. */ -const propsCache = () => { +const inventoryCache = () => { let cache = {}; - const updateProps = (props) => { cache = props; }; + const updateProps = (props) => { cache = cloneDeep({ ...cache, props }); }; - const getProps = () => cache; + const updateParams = (params) => { cache = cloneDeep({ ...cache, params }); }; - return { updateProps, getProps }; + const getProps = () => cache.props; + const getParams = () => cache.params; + + return { updateProps, updateParams, getProps, getParams }; }; /** @@ -71,12 +75,10 @@ const InventoryTable = forwardRef(({ // eslint-disable-line react/display-name )); const page = useSelector(({ entities: { page: invPage } }) => ( hasItems ? propsPage : (invPage || 1) - ) - , shallowEqual); + ), shallowEqual); const perPage = useSelector(({ entities: { perPage: invPerPage } }) => ( hasItems ? propsPerPage : (invPerPage || 50) - ) - , shallowEqual); + ), shallowEqual); const total = useSelector(({ entities: { total: invTotal } }) => { if (hasItems) { return propsTotal !== undefined ? propsTotal : items?.length; @@ -112,7 +114,7 @@ const InventoryTable = forwardRef(({ // eslint-disable-line react/display-name const dispatch = useDispatch(); const store = useStore(); - const cache = useRef(propsCache()); + const cache = useRef(inventoryCache()); cache.current.updateProps({ page, perPage, @@ -134,7 +136,7 @@ const InventoryTable = forwardRef(({ // eslint-disable-line react/display-name const cachedProps = cache.current?.getProps() || {}; const currPerPage = options?.per_page || options?.perPage || cachedProps.perPage; - const params = { + const newParams = { page: cachedProps.page, per_page: currPerPage, items: cachedProps.items, @@ -146,25 +148,29 @@ const InventoryTable = forwardRef(({ // eslint-disable-line react/display-name ...options }; - if (onRefresh && !disableOnRefresh) { - dispatch(entitiesLoading()); - onRefresh(params, (options) => { + const cachedParams = cache.current.getParams(); + if (!isEqual(cachedParams, newParams)) { + cache.current.updateParams(newParams); + if (onRefresh && !disableOnRefresh) { + dispatch(entitiesLoading()); + onRefresh(newParams, (options) => { + dispatch( + loadSystems( + { ...newParams, ...options }, + cachedProps.showTags, + cachedProps.getEntities + ) + ); + }); + } else { dispatch( loadSystems( - { ...params, ...options }, + newParams, cachedProps.showTags, cachedProps.getEntities ) ); - }); - } else { - dispatch( - loadSystems( - params, - cachedProps.showTags, - cachedProps.getEntities - ) - ); + } } }; diff --git a/src/components/filters/useTextFilter.js b/src/components/filters/useTextFilter.js index ca71d4e3e..f5dbb8558 100644 --- a/src/components/filters/useTextFilter.js +++ b/src/components/filters/useTextFilter.js @@ -23,7 +23,7 @@ export const useTextFilter = ([state, dispatch] = [textFilterState]) => { onChange: (_e, value) => setValue(value) } }; - const chip = value.length > 0 ? [{ + const chip = value?.length > 0 ? [{ category: 'Display name', type: TEXTUAL_CHIP, chips: [ diff --git a/src/routes/InventoryTable.js b/src/routes/InventoryTable.js index 82630215f..5df03787f 100644 --- a/src/routes/InventoryTable.js +++ b/src/routes/InventoryTable.js @@ -167,6 +167,10 @@ const Inventory = ({ Array.isArray(perPage) ? perPage[0] : perPage )); } + + return () => { + dispatch(actions.clearEntitiesAction()); + }; }, []); const calculateSelected = () => selected ? selected.size : 0; @@ -236,6 +240,7 @@ const Inventory = ({ onRefresh={onRefresh} hasCheckbox={writePermissions} autoRefresh + ignoreRefresh initialLoading={initialLoading} tableProps={ (writePermissions && { diff --git a/src/store/action-types.js b/src/store/action-types.js index a3911afcf..779b1cceb 100644 --- a/src/store/action-types.js +++ b/src/store/action-types.js @@ -67,3 +67,4 @@ export const CLEAR_FILTERS = 'CLEAR_FILTERS'; export const TOGGLE_TAG_MODAL = 'TOGGLE_TAG_MODAL'; export const CONFIG_CHANGED = 'CONFIG_CHANGED'; export const TOGGLE_DRAWER = 'TOGGLE_INVENTORY_DRAWER'; +export const CLEAR_ENTITIES = 'CLEAR_ENTITIES'; diff --git a/src/store/actions.js b/src/store/actions.js index 0167d550b..202699fbe 100644 --- a/src/store/actions.js +++ b/src/store/actions.js @@ -1,4 +1,5 @@ -import { ACTION_TYPES, CLEAR_NOTIFICATIONS, SET_INVENTORY_FILTER, SET_PAGINATION } from './action-types'; +import { ACTION_TYPES, CLEAR_NOTIFICATIONS, SET_INVENTORY_FILTER, SET_PAGINATION, + CLEAR_ENTITIES } from './action-types'; import { hosts, getEntitySystemProfile } from '../api'; export * from './system-issues-actions'; export * from './inventory-actions'; @@ -77,3 +78,8 @@ export const editAnsibleHost = (id, value, origValue) => ({ } } }); + +export const clearEntitiesAction = () => ({ + type: CLEAR_ENTITIES, + payload: [] +}); diff --git a/src/store/entities.js b/src/store/entities.js index e319e9e8c..8e16d9f2d 100644 --- a/src/store/entities.js +++ b/src/store/entities.js @@ -9,7 +9,8 @@ import { ENTITIES_LOADING, CLEAR_FILTERS, TOGGLE_TAG_MODAL, - CONFIG_CHANGED + CONFIG_CHANGED, + CLEAR_ENTITIES } from './action-types'; import { mergeArraysByKey } from '@redhat-cloud-services/frontend-components-utilities/helpers'; import { DateFormat } from '@redhat-cloud-services/frontend-components/DateFormat'; @@ -123,6 +124,10 @@ function clearFilters(state) { }; } +const clearEntities = () => { + return defaultState; +}; + // eslint-disable-next-line camelcase function entitiesLoaded(state, { payload: { results, per_page: perPage, page, count, total, loaded, filters }, meta }) { // Older requests should not rewrite the state @@ -305,5 +310,6 @@ export default { [CLEAR_FILTERS]: clearFilters, [ENTITIES_LOADING]: (state, { payload: { isLoading } }) => ({ ...state, loaded: !isLoading }), [TOGGLE_TAG_MODAL]: toggleTagModalReducer, - [CONFIG_CHANGED]: (state, { payload }) => ({ ...state, invConfig: payload }) + [CONFIG_CHANGED]: (state, { payload }) => ({ ...state, invConfig: payload }), + [CLEAR_ENTITIES]: clearEntities };