diff --git a/awx/ui_next/src/screens/Inventory/InventoryList/InventoryList.jsx b/awx/ui_next/src/screens/Inventory/InventoryList/InventoryList.jsx index e0aa888f97..65d7bed75a 100644 --- a/awx/ui_next/src/screens/Inventory/InventoryList/InventoryList.jsx +++ b/awx/ui_next/src/screens/Inventory/InventoryList/InventoryList.jsx @@ -57,7 +57,16 @@ function InventoryList({ i18n }) { fetchInventories(); }, [fetchInventories]); - const inventories = useWsInventories(results); + const fetchInventoriesById = useCallback( + async ids => { + const params = parseQueryString(QS_CONFIG, location.search); + params.id__in = ids.join(','); + const { data } = await InventoriesAPI.read(params); + return data.results; + }, + [location.search] // eslint-disable-line react-hooks/exhaustive-deps + ); + const inventories = useWsInventories(results, fetchInventoriesById); const isAllSelected = selected.length === inventories.length && selected.length > 0; diff --git a/awx/ui_next/src/screens/Inventory/InventoryList/InventoryListItem.jsx b/awx/ui_next/src/screens/Inventory/InventoryList/InventoryListItem.jsx index eb091495c7..9070656bba 100644 --- a/awx/ui_next/src/screens/Inventory/InventoryList/InventoryListItem.jsx +++ b/awx/ui_next/src/screens/Inventory/InventoryList/InventoryListItem.jsx @@ -54,7 +54,9 @@ function InventoryListItem({ const labelId = `check-action-${inventory.id}`; let syncStatus = 'disabled'; - if (inventory.has_inventory_sources) { + if (inventory.isSourceSyncRunning) { + syncStatus = 'syncing'; + } else if (inventory.has_inventory_sources) { syncStatus = inventory.inventory_sources_with_failures > 0 ? 'error' : 'success'; } diff --git a/awx/ui_next/src/screens/Inventory/InventoryList/useWsInventories.js b/awx/ui_next/src/screens/Inventory/InventoryList/useWsInventories.js index 29d438d3bf..d9886c29c4 100644 --- a/awx/ui_next/src/screens/Inventory/InventoryList/useWsInventories.js +++ b/awx/ui_next/src/screens/Inventory/InventoryList/useWsInventories.js @@ -1,50 +1,88 @@ import { useState, useEffect, useRef } from 'react'; +import useThrottle from '../../../util/useThrottle'; -export default function useWsProjects(initialInventories) { +export default function useWsProjects( + initialInventories, + fetchInventoriesById +) { const [inventories, setInventories] = useState(initialInventories); const [lastMessage, setLastMessage] = useState(null); + const [inventoriesToFetch, setInventoriesToFetch] = useState([]); + const throttledInventoriesToFetch = useThrottle(inventoriesToFetch, 5000); const ws = useRef(null); useEffect(() => { setInventories(initialInventories); }, [initialInventories]); - // const messageExample = { - // unified_job_id: 533, - // status: 'pending', - // type: 'inventory_update', - // inventory_source_id: 53, - // inventory_id: 5, - // group_name: 'jobs', - // unified_job_template_id: 53, - // }; - useEffect(() => { - if (!lastMessage?.unified_job_id || lastMessage.type !== 'project_update') { - return; - } - const index = inventories.findIndex(p => p.id === lastMessage.project_id); - if (index === -1) { - return; + const enqueueId = id => { + if (!inventoriesToFetch.includes(id)) { + setInventoriesToFetch(ids => ids.concat(id)); } + }; + useEffect( + function fetchUpdatedInventories() { + (async () => { + if (!throttledInventoriesToFetch.length) { + return; + } + setInventoriesToFetch([]); + const newInventories = await fetchInventoriesById( + throttledInventoriesToFetch + ); + let updated = inventories; + newInventories.forEach(inventory => { + const index = inventories.findIndex(i => i.id === inventory.id); + if (index === -1) { + return; + } + updated = [ + ...updated.slice(0, index), + inventory, + ...updated.slice(index + 1), + ]; + }); + setInventories(updated); + })(); + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [throttledInventoriesToFetch, fetchInventoriesById] + ); - const inventory = inventories[index]; - const updatedProject = { - ...inventory, - summary_fields: { - ...inventory.summary_fields, - // last_job: { - // id: lastMessage.unified_job_id, - // status: lastMessage.status, - // finished: lastMessage.finished, - // }, - }, - }; - setInventories([ - ...inventories.slice(0, index), - updatedProject, - ...inventories.slice(index + 1), - ]); - }, [lastMessage]); // eslint-disable-line react-hooks/exhaustive-deps + useEffect( + function processWsMessage() { + if ( + !lastMessage?.inventory_id || + lastMessage.type !== 'inventory_update' + ) { + return; + } + const index = inventories.findIndex( + p => p.id === lastMessage.inventory_id + ); + if (index === -1) { + return; + } + + if (!['pending', 'waiting', 'running'].includes(lastMessage.status)) { + enqueueId(lastMessage.inventory_id); + return; + } + + const inventory = inventories[index]; + const updatedInventory = { + ...inventory, + isSourceSyncRunning: true, + }; + setInventories([ + ...inventories.slice(0, index), + updatedInventory, + ...inventories.slice(index + 1), + ]); + }, + // eslint-disable-next-line react-hooks/exhaustive-deps, + [lastMessage] + ); useEffect(() => { ws.current = new WebSocket(`wss://${window.location.host}/websocket/`);