From 4080007ced23c2734cd44d408be2c3d32a280f36 Mon Sep 17 00:00:00 2001 From: "Keith J. Grant" Date: Mon, 7 Mar 2022 10:04:11 -0800 Subject: [PATCH] JobOutput: add 'waiting for job' and 'no results found' messages --- .../components/ContentEmpty/ContentEmpty.js | 12 ++- .../src/screens/Job/JobOutput/EmptyOutput.js | 36 +++++++++ awx/ui/src/screens/Job/JobOutput/JobEvent.js | 8 +- awx/ui/src/screens/Job/JobOutput/JobOutput.js | 81 ++++++++++++------- 4 files changed, 101 insertions(+), 36 deletions(-) create mode 100644 awx/ui/src/screens/Job/JobOutput/EmptyOutput.js diff --git a/awx/ui/src/components/ContentEmpty/ContentEmpty.js b/awx/ui/src/components/ContentEmpty/ContentEmpty.js index a1d88be425..d74ee46dc6 100644 --- a/awx/ui/src/components/ContentEmpty/ContentEmpty.js +++ b/awx/ui/src/components/ContentEmpty/ContentEmpty.js @@ -1,6 +1,5 @@ import React from 'react'; import { t } from '@lingui/macro'; - import { Title, EmptyState, @@ -9,9 +8,14 @@ import { } from '@patternfly/react-core'; import { CubesIcon } from '@patternfly/react-icons'; -const ContentEmpty = ({ title = '', message = '' }) => ( - - +const ContentEmpty = ({ + title = '', + message = '', + icon = CubesIcon, + className = '', +}) => ( + + {title || t`No items found.`} diff --git a/awx/ui/src/screens/Job/JobOutput/EmptyOutput.js b/awx/ui/src/screens/Job/JobOutput/EmptyOutput.js new file mode 100644 index 0000000000..69e21eba5c --- /dev/null +++ b/awx/ui/src/screens/Job/JobOutput/EmptyOutput.js @@ -0,0 +1,36 @@ +import React, { useEffect } from 'react'; +import 'styled-components/macro'; +import { t } from '@lingui/macro'; +import { SearchIcon } from '@patternfly/react-icons'; +import ContentEmpty from 'components/ContentEmpty'; + +export default function EmptyOutput({ + hasQueryParams, + isJobRunning, + onUnmount, +}) { + let title; + let message; + let icon; + + useEffect(() => onUnmount); + + if (hasQueryParams) { + title = t`The search filter did not produce any results…`; + message = t`Please try another search using the filter above`; + icon = SearchIcon; + } else if (isJobRunning) { + title = t`Waiting for job output…`; + } else { + title = t`No output found for this job.`; + } + + return ( + + ); +} diff --git a/awx/ui/src/screens/Job/JobOutput/JobEvent.js b/awx/ui/src/screens/Job/JobOutput/JobEvent.js index 3516f24749..8f3dd81f8e 100644 --- a/awx/ui/src/screens/Job/JobOutput/JobEvent.js +++ b/awx/ui/src/screens/Job/JobOutput/JobEvent.js @@ -17,11 +17,15 @@ function JobEvent({ isCollapsed, onToggleCollapsed, hasChildren, + jobStatus, }) { const numOutputLines = lineTextHtml?.length || 0; useEffect(() => { - measure(); - }, [numOutputLines, isCollapsed, measure]); + const timeout = setTimeout(measure, 0); + return () => { + clearTimeout(timeout); + }; + }, [numOutputLines, isCollapsed, measure, jobStatus]); let toggleLineIndex = -1; if (hasChildren) { diff --git a/awx/ui/src/screens/Job/JobOutput/JobOutput.js b/awx/ui/src/screens/Job/JobOutput/JobOutput.js index 1173da6c80..c5eb8ca217 100644 --- a/awx/ui/src/screens/Job/JobOutput/JobOutput.js +++ b/awx/ui/src/screens/Job/JobOutput/JobOutput.js @@ -30,6 +30,7 @@ import JobEventSkeleton from './JobEventSkeleton'; import PageControls from './PageControls'; import HostEventModal from './HostEventModal'; import JobOutputSearch from './JobOutputSearch'; +import EmptyOutput from './EmptyOutput'; import { HostStatusBar, OutputToolbar } from './shared'; import getLineTextHtml from './getLineTextHtml'; import connectJobSocket, { closeWebSocket } from './connectJobSocket'; @@ -220,6 +221,7 @@ function JobOutput({ job, eventRelatedSearchableKeys, eventSearchableKeys }) { ...Object.values(siblingRequests.current || {}), ...Object.values(numEventsRequests.current || {}), ]; + setHasContentLoading(true); // prevents "no content found" screen from flashing Promise.all(pendingRequests).then(() => { setRemoteRowCount(0); clearLoadedEvents(); @@ -509,6 +511,7 @@ function JobOutput({ job, eventRelatedSearchableKeys, eventSearchableKeys }) { onToggleCollapsed={() => { toggleNodeIsCollapsed(event.uuid, !node.isCollapsed); }} + jobStatus={jobStatus} /> ) : ( - {({ onRowsRendered, registerChild }) => ( - - {({ width, height }) => ( - <> - {hasContentLoading ? ( -
- -
- ) : ( - { - registerChild(ref); - listRef.current = ref; - }} - deferredMeasurementCache={cache} - height={height || 1} - onRowsRendered={onRowsRendered} - rowCount={totalNonCollapsedRows + wsEvents.length} - rowHeight={cache.rowHeight} - rowRenderer={rowRenderer} - scrollToAlignment="start" - width={width || 1} - overscanRowCount={20} - onScroll={handleScroll} - /> - )} - - )} -
- )} + {({ onRowsRendered, registerChild }) => { + if ( + !hasContentLoading && + remoteRowCount + wsEvents.length === 0 + ) { + return ( + 1} + isJobRunning={isJobRunning(jobStatus)} + onUnmount={() => { + if (listRef.current?.recomputeRowHeights) { + listRef.current.recomputeRowHeights(); + } + }} + /> + ); + } + return ( + + {({ width, height }) => ( + <> + {hasContentLoading ? ( +
+ +
+ ) : ( + { + registerChild(ref); + listRef.current = ref; + }} + deferredMeasurementCache={cache} + height={height || 1} + onRowsRendered={onRowsRendered} + rowCount={totalNonCollapsedRows + wsEvents.length} + rowHeight={cache.rowHeight} + rowRenderer={rowRenderer} + scrollToAlignment="start" + width={width || 1} + overscanRowCount={20} + onScroll={handleScroll} + /> + )} + + )} +
+ ); + }}