diff --git a/awx/ui/src/screens/Inventory/ConstructedInventoryDetail/ConstructedInventoryDetail.js b/awx/ui/src/screens/Inventory/ConstructedInventoryDetail/ConstructedInventoryDetail.js index d8e136646b..6108dc2330 100644 --- a/awx/ui/src/screens/Inventory/ConstructedInventoryDetail/ConstructedInventoryDetail.js +++ b/awx/ui/src/screens/Inventory/ConstructedInventoryDetail/ConstructedInventoryDetail.js @@ -5,6 +5,8 @@ import { t } from '@lingui/macro'; import { Button, Chip, + Label, + LabelGroup, TextList, TextListItem, TextListItemVariants, @@ -114,6 +116,10 @@ function ConstructedInventoryDetail({ inventory }) { wsInventorySource.summary_fields?.current_job || wsInventorySource.summary_fields?.last_job || null; + const wsInventory = { + ...inventory, + ...wsInventorySource?.summary_fields?.inventory, + }; const { request: deleteInventory, error: deleteError } = useRequest( useCallback(async () => { @@ -180,19 +186,19 @@ function ConstructedInventoryDetail({ inventory }) { /> @@ -204,7 +210,7 @@ function ConstructedInventoryDetail({ inventory }) { /> @@ -266,22 +272,25 @@ function ConstructedInventoryDetail({ inventory }) { fullWidth label={t`Input Inventories`} value={ - + {inputInventories?.map((inputInventory) => ( - ( + + {content} + + )} > - - {inputInventory.name} - - + {inputInventory.name} + ))} - + } isEmpty={inputInventories?.length === 0} /> diff --git a/awx/ui/src/screens/Inventory/shared/useWsInventorySourcesDetails.js b/awx/ui/src/screens/Inventory/shared/useWsInventorySourcesDetails.js index e93f28f58b..e010b8916a 100644 --- a/awx/ui/src/screens/Inventory/shared/useWsInventorySourcesDetails.js +++ b/awx/ui/src/screens/Inventory/shared/useWsInventorySourcesDetails.js @@ -1,16 +1,17 @@ import { useState, useEffect } from 'react'; import useWebsocket from 'hooks/useWebsocket'; +import { InventorySourcesAPI } from 'api'; -export default function useWsInventorySourcesDetails(initialSources) { - const [sources, setSources] = useState(initialSources); +export default function useWsInventorySourcesDetails(initialSource) { + const [source, setSource] = useState(initialSource); const lastMessage = useWebsocket({ jobs: ['status_changed'], control: ['limit_reached_1'], }); useEffect(() => { - setSources(initialSources); - }, [initialSources]); + setSource(initialSource); + }, [initialSource]); useEffect( () => { @@ -21,22 +22,37 @@ export default function useWsInventorySourcesDetails(initialSources) { ) { return; } - const updateSource = { - ...sources, - summary_fields: { - ...sources.summary_fields, - current_job: { - id: lastMessage.unified_job_id, - status: lastMessage.status, - finished: lastMessage.finished, - }, - }, - }; - setSources(updateSource); + if ( + ['successful', 'failed', 'error', 'cancelled'].includes( + lastMessage.status + ) + ) { + fetchSource(); + } + setSource(updateSource(source, lastMessage)); }, [lastMessage] // eslint-disable-line react-hooks/exhaustive-deps ); - return sources; + async function fetchSource() { + const { data } = await InventorySourcesAPI.readDetail(source.id); + setSource(data); + } + + return source; +} + +function updateSource(source, message) { + return { + ...source, + summary_fields: { + ...source.summary_fields, + current_job: { + id: message.unified_job_id, + status: message.status, + finished: message.finished, + }, + }, + }; } diff --git a/awx/ui/src/screens/Inventory/shared/useWsInventorySourcesDetails.test.js b/awx/ui/src/screens/Inventory/shared/useWsInventorySourcesDetails.test.js index 25fb97850b..d1f1e17009 100644 --- a/awx/ui/src/screens/Inventory/shared/useWsInventorySourcesDetails.test.js +++ b/awx/ui/src/screens/Inventory/shared/useWsInventorySourcesDetails.test.js @@ -1,9 +1,12 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; import WS from 'jest-websocket-mock'; +import { InventorySourcesAPI } from 'api'; import { mountWithContexts } from '../../../../testUtils/enzymeHelpers'; import useWsInventorySourceDetails from './useWsInventorySourcesDetails'; +jest.mock('../../../api/models/InventorySources'); + function TestInner() { return
; } @@ -111,6 +114,27 @@ describe('useWsProject', () => { status: 'running', finished: null, }); + + expect(InventorySourcesAPI.readDetail).toHaveBeenCalledTimes(0); + InventorySourcesAPI.readDetail.mockResolvedValue({ + data: {}, + }); + await act(async () => { + mockServer.send( + JSON.stringify({ + group_name: 'jobs', + inventory_id: 1, + status: 'successful', + type: 'inventory_update', + unified_job_id: 2, + unified_job_template_id: 1, + inventory_source_id: 1, + }) + ); + }); + expect(InventorySourcesAPI.readDetail).toHaveBeenCalledTimes(1); + + jest.clearAllMocks(); WS.clean(); }); });