Skip to content

Commit

Permalink
UX updates for pipeline logs
Browse files Browse the repository at this point in the history
  • Loading branch information
DaoDaoNoCode committed Oct 10, 2024
1 parent 355fbf7 commit 756383f
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 31 deletions.
2 changes: 1 addition & 1 deletion frontend/src/concepts/dashboard/DashboardLogViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const DashboardLogViewer: React.FC<{
data: string;
logViewerRef: React.MutableRefObject<{ scrollToBottom: () => void } | undefined>;
toolbar: JSX.Element | boolean;
footer: JSX.Element | false;
footer?: JSX.Element | false;
onScroll: React.ComponentProps<typeof LogViewer>['onScroll'];
height?: number | string;
isTextWrapped?: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,14 @@ import {
Tooltip,
Truncate,
} from '@patternfly/react-core';
import { OutlinedPlayCircleIcon } from '@patternfly/react-icons/dist/esm/icons/outlined-play-circle-icon';
import { PauseIcon } from '@patternfly/react-icons/dist/esm/icons/pause-icon';
import { PlayIcon } from '@patternfly/react-icons/dist/esm/icons/play-icon';
import { DownloadIcon } from '@patternfly/react-icons/dist/esm/icons/download-icon';
import { LogViewer, LogViewerSearch } from '@patternfly/react-log-viewer';
import {
CompressIcon,
EllipsisVIcon,
ExpandIcon,
OutlinedPauseCircleIcon,
OutlinedPlayCircleIcon,
OutlinedWindowRestoreIcon,
} from '@patternfly/react-icons';
import DashboardLogViewer from '~/concepts/dashboard/DashboardLogViewer';
Expand Down Expand Up @@ -97,6 +96,7 @@ const LogsTab: React.FC<LogsTabProps> = ({ task, isCached }) => {
};
}, [dispatchResizeEvent]);

// Scroll to bottom when log refreshes and streaming
React.useEffect(() => {
if (!isPaused && logs) {
if (logViewerRef.current) {
Expand All @@ -105,6 +105,16 @@ const LogsTab: React.FC<LogsTabProps> = ({ task, isCached }) => {
}
}, [isPaused, logs]);

React.useEffect(() => {
const logWindowElement = document.querySelector(
'#dashboard-logviewer .pf-v5-c-log-viewer__main',
);
if (logWindowElement) {
logWindowElement.addEventListener('mousedown', () => setIsPaused(true));
}
return logWindowElement?.removeEventListener('mousedown', () => setIsPaused(true));
}, []);

const onScroll: React.ComponentProps<typeof LogViewer>['onScroll'] = ({
scrollOffsetToBottom,
scrollUpdateWasRequested,
Expand Down Expand Up @@ -195,6 +205,8 @@ const LogsTab: React.FC<LogsTabProps> = ({ task, isCached }) => {
data = 'No logs available';
}

const rawLogsLink = `${location.origin}/api/k8s/api/v1/namespaces/${namespace}/pods/${podName}/log?container=${containerName}`;

return (
<Stack hasGutter>
<StackItem>
Expand All @@ -208,19 +220,18 @@ const LogsTab: React.FC<LogsTabProps> = ({ task, isCached }) => {
isCached={isCached}
isFailedPod={isFailedPod}
isLogsAvailable={podContainers.length !== 1 && !!logs}
onDownload={onDownloadAll}
onDownload={onDownload}
onDownloadAll={onDownloadAll}
rawLogsLink={rawLogsLink}
/>
)}
</StackItem>
<StackItem isFilled id="dashboard-logviewer" style={{ position: 'relative' }}>
{/* -33 to make room for the footer to pop in*/}
<div
style={{ position: 'absolute', left: 0, right: 0, top: 0, bottom: -33 }}
style={{ position: 'absolute', left: 0, right: 0, top: 0, bottom: 0 }}
ref={logsTabRef}
>
{/* 33 for the toolbar, 33 for the footer, and 1 because browser layout calculations sometimes go over by a fraction of a pixel */}
<DashboardLogViewer
height="calc(100% - 75px)"
data={data}
logViewerRef={logViewerRef}
isTextWrapped={isTextWrapped}
Expand Down Expand Up @@ -314,7 +325,7 @@ const LogsTab: React.FC<LogsTabProps> = ({ task, isCached }) => {
}}
/>
</ToolbarItem>
{(!podStatus?.completed || isPaused) && (
{!podStatus?.completed && (
<ToolbarItem spacer={{ default: 'spacerNone' }}>
<Button
variant={!logsLoaded ? 'plain' : isPaused ? 'plain' : 'link'}
Expand All @@ -323,16 +334,16 @@ const LogsTab: React.FC<LogsTabProps> = ({ task, isCached }) => {
data-testid="logs-pause-refresh-button"
>
{isPaused ? (
<Tooltip content="Resume refreshing">
<PlayIcon />
<Tooltip content="Resume log streaming.">
<OutlinedPlayCircleIcon />
</Tooltip>
) : !logsLoaded || podStatus?.podInitializing ? (
<Tooltip content="Loading log">
<Spinner size="sm" />
</Tooltip>
) : (
<Tooltip content="Pause refreshing">
<PauseIcon />
<Tooltip content="Pause log streaming.">
<OutlinedPauseCircleIcon />
</Tooltip>
)}
</Button>
Expand Down Expand Up @@ -394,7 +405,7 @@ const LogsTab: React.FC<LogsTabProps> = ({ task, isCached }) => {
<DropdownList>
<DropdownItem
isDisabled={!logs}
to={`${location.origin}/api/k8s/api/v1/namespaces/${namespace}/pods/${podName}/log?container=${containerName}`}
to={rawLogsLink}
target="_blank"
rel="noopener noreferrer"
icon={<OutlinedWindowRestoreIcon />}
Expand All @@ -418,19 +429,6 @@ const LogsTab: React.FC<LogsTabProps> = ({ task, isCached }) => {
</Toolbar>
)
}
footer={
logsLoaded &&
isPaused &&
!podStatus?.completed && (
<Button
onClick={() => setIsPaused(false)}
isBlock
icon={<OutlinedPlayCircleIcon />}
>
Resume refreshing log
</Button>
)
}
onScroll={onScroll}
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ type LogsTabStatusProps = {
isFailedPod?: boolean;
loaded: boolean;
onDownload: () => void;
onDownloadAll: () => void;
rawLogsLink: string;
};

const LogsTabStatus: React.FC<LogsTabStatusProps> = ({
Expand All @@ -28,6 +30,8 @@ const LogsTabStatus: React.FC<LogsTabStatusProps> = ({
loaded,
isFailedPod,
onDownload,
onDownloadAll,
rawLogsLink,
}) => {
if (isCached) {
return (
Expand Down Expand Up @@ -85,11 +89,28 @@ const LogsTabStatus: React.FC<LogsTabStatusProps> = ({
>
<p>
The log refreshes every {Math.floor(LOG_REFRESH_RATE / 1000)} seconds and displays the
latest {LOG_TAIL_LINES} lines. To view the full log for this task, you can{' '}
latest {LOG_TAIL_LINES} lines, with exceptionally long lines abridged. To view the full log
for this step,{' '}
<Button
isDisabled={!isLogsAvailable}
variant="link"
component="a"
href={rawLogsLink}
target="_blank"
rel="noopener noreferrer"
isInline
>
view its raw log
</Button>{' '}
or{' '}
<Button isDisabled={!isLogsAvailable} variant="link" isInline onClick={onDownload}>
download all step logs
download
</Button>{' '}
associated with it.
it. To view the full log for this task,{' '}
<Button isDisabled={!isLogsAvailable} variant="link" isInline onClick={onDownloadAll}>
download all of its associated step logs
</Button>
.
</p>
</Alert>
);
Expand Down

0 comments on commit 756383f

Please sign in to comment.