Skip to content

Commit

Permalink
improve error visibility UX (#409)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dan Wilson committed Mar 2, 2022
1 parent b215907 commit 8092ea1
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 99 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -131,81 +131,8 @@ export default function LogViewConsoleManager(props) {
}
}, [stageError]);

if (state?.stepData?.status === STEP_STATES.ERROR) {
return (
<>
<NonLogsContainer className={cx('no-logs')}>
<div className={cx('error-wrapper')}>
<SystemMessage intent="danger">
{getLogsErrorContent({
buildStatus: state.buildStatus,
stageStatus: state.stageStatus,
stageName: state.stageName,
stepName: state.stepData.name,
stepError: state.stepData.error,
logsHookError: state.logsHookError,
})}
</SystemMessage>
</div>
</NonLogsContainer>
{state?.logs?.length
&& (
<Console
ref={dynamicHeightRef}
height={dynamicHeight}
shownLogsLimit={LOGS_LIMIT}
tmateLink={state.tmateLink}
logs={state.logs}
showLogsLoadingLine={state.compState === STATES.LOADING
|| (state.compState === STATES.STREAM_ON && !state.logs.length)}
areLogsLoading={state.compState === STATES.LOADING}
stepData={state.stepData}
showDownloadBtn={state.stepData?.stopped && state.compState === STATES.RESOLVED}
showFollowLogsBtn={state.compState === STATES.STREAM_ON}
logsBlobName={logsBlobName}
{...consoleProps}
/>
)}
</>
);
}
// render state switch statement
switch (state?.compState) {
case STATES.NO_LOGS_AVAILABLE:
return (
<>
<NonLogsContainer className={cx('no-logs')}>
<SystemMessage intent={getIntentFromStepStatus(state.stageStatus)}>
{getNoLogsContent({
buildStatus: state.buildStatus,
stageStatus: state.stageStatus,
stageName: state.stageName,
stepName: state.stepData.name,
stepStatus: state.stepData.status,
stageError: state.stageError,
})}
</SystemMessage>
</NonLogsContainer>
{state?.logs?.length
&& (
<Console
ref={dynamicHeightRef}
height={dynamicHeight}
shownLogsLimit={LOGS_LIMIT}
tmateLink={state.tmateLink}
logs={state.logs}
showLogsLoadingLine={state.compState === STATES.LOADING
|| (state.compState === STATES.STREAM_ON && !state.logs.length)}
areLogsLoading={state.compState === STATES.LOADING}
stepData={state.stepData}
showDownloadBtn={state.stepData?.stopped && state.compState === STATES.RESOLVED}
showFollowLogsBtn={state.compState === STATES.STREAM_ON}
logsBlobName={logsBlobName}
{...consoleProps}
/>
)}
</>
);
case STATES.IDLE:
return null;
case STATES.ERROR:
Expand All @@ -227,6 +154,8 @@ export default function LogViewConsoleManager(props) {
showDownloadBtn={state.stepData?.stopped && state.compState === STATES.RESOLVED}
showFollowLogsBtn={state.compState === STATES.STREAM_ON}
logsBlobName={logsBlobName}
stageError={stageError}
stageStatus={stageStatus}
{...consoleProps}
/>
);
Expand Down
35 changes: 22 additions & 13 deletions src/components/pages/build/log-view/stage-nav/stage-nav.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export default function StageNav(props) {
stopped: stageStopped,
steps,
number: stageNumber,
error,
}) => {
if (!steps?.length || [
'skipped',
Expand All @@ -66,6 +67,10 @@ export default function StageNav(props) {
stageStatus={stageStatus}
stageStarted={stageStarted}
stageStopped={stageStopped}
namespace={namespace}
name={name}
build={build}
stageNumber={stageNumber}
/>
);
}
Expand All @@ -83,6 +88,7 @@ export default function StageNav(props) {
name={name}
build={build}
stageInPath={stage}
error={error}
onStepClick={onStepClick}
/>
);
Expand All @@ -105,6 +111,7 @@ const StageDefault = (props) => {
build,
stageInPath,
onStepClick,
error,
} = props;
const [isExpanded, setIsExpanded] = useState(stageNumber == stageInPath);
const toggleIsExpanded = () => setIsExpanded((prev) => !prev);
Expand All @@ -129,14 +136,7 @@ const StageDefault = (props) => {
</li>
{steps.map(({
id: stepId, status, name: stepName, started, stopped,
}, stepIndex) => (status === 'skipped' ? (
<li key={stepId}>
<div className={cx('stage-step', 'stage-step-unselectable')}>
<Status className={cx('status')} status={status} />
<span className={cx('name')}>{stepName}</span>
</div>
</li>
) : (
}, stepIndex) => (
<li key={stepId}>
<NavLink
activeClassName={cx('stage-step-active')}
Expand All @@ -158,7 +158,7 @@ const StageDefault = (props) => {
<Elapsed className={cx('time')} started={started} finished={stopped} />
</NavLink>
</li>
)))}
))}
</ul>
)}
</div>
Expand All @@ -171,15 +171,24 @@ const StageEmpty = (props) => {
stageName,
stageStarted,
stageStopped,
namespace,
name,
build,
stageNumber,
} = props;
return (
<div className={cx('stage')}>
<h3 className={cx('stage-header', 'stage-header-unselectable')}>
<ChevronIcon className={cx('chevron', 'chevron-disabled')} />
<NavLink
activeClassName={cx('stage-active')}
className={cx('stage')}
to={`/${namespace}/${name}/${build}/${stageNumber}`}
exact
>
<h3 className={cx('stage-header')}>
<ChevronIcon className={cx('chevron-hidden')} />
<Status className={cx('stage-status')} status={stageStatus} />
<span className={cx('name')}>{stageName}</span>
<Elapsed className={cx('time')} started={stageStarted} finished={stageStopped} />
</h3>
</div>
</NavLink>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@
border-bottom: none;
}

.time {
margin-left: auto;
font-weight: 400;
font-size: 12px;
line-height: 13px;
flex: 0 0 auto;
user-select: none;
color: #9293ab;
}

&-header {
padding-top: 14px;
padding-bottom: 14px;
Expand Down Expand Up @@ -91,6 +101,9 @@
&-disabled {
stroke: #96a5be;
}
&-hidden {
visibility: hidden;
}
}
&-expanded {
padding-bottom: 7px;
Expand All @@ -102,6 +115,19 @@
cursor: not-allowed;
}
}

&-active {
background: #e6faff;
font-weight: 600;
.time {
color: #0278d5;
}
.stage-header {
color: #0278d5;
font-weight: 600;
}
}

&-status {
width: 16px;
height: 16px;
Expand Down Expand Up @@ -136,15 +162,6 @@
}
}

.time {
margin-left: auto;
font-weight: 400;
font-size: 12px;
line-height: 13px;
flex: 0 0 auto;
user-select: none;
color: #9293ab;
}
.steps-header {
margin-left: 16px;
margin-top: 12px;
Expand Down
30 changes: 26 additions & 4 deletions src/components/shared/console/console.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,20 +97,22 @@ const ConsoleFooter = (props) => {
stepError,
stepExitCode,
tmateLink,
stageError,
stageStatus,
} = props;
return (
<footer className={cx('footer')}>
<div className={cx('summary')}>
<div className={cx('summary-info')}>
{stepStatus && (
{(stepStatus || stageStatus) && (
<Status
className={cx('summary-status')}
status={stepStatus}
status={stepStatus || stageStatus}
/>
)}
{getStepSummary(
stepStatus,
stepError,
stepStatus || stageStatus,
stepError || stageError,
stepExitCode,
)}
</div>
Expand Down Expand Up @@ -209,6 +211,17 @@ LogsLine.propTypes = {
time: PropTypes.number.isRequired,
};

const StageError = ({ error }) => (
<div className={cx('stage-error')}>
<Status className={cx('status')} status="error" />
<span className={cx('text')}>{error}</span>
</div>
);

StageError.propTypes = {
error: PropTypes.string.isRequired,
};

const Console = React.forwardRef((props, ref) => {
const {
className,
Expand All @@ -226,6 +239,8 @@ const Console = React.forwardRef((props, ref) => {
logsBlobName,
showCloseBtn,
onCloseBtnClick,
stageError,
stageStatus,
} = props;

const [showAllLogs, setShowAllLogs] = useState(false);
Expand Down Expand Up @@ -277,6 +292,7 @@ const Console = React.forwardRef((props, ref) => {
}
handleShowAllLogsClick={handleShowAllLogsClick}
/>
{stageError && <StageError error={stageError} />}
<code className={classNames('ansi-hook', cx('output'))}>
<LogsLoadingLine
shouldShow={showLogsLoadingLine}
Expand All @@ -295,6 +311,8 @@ const Console = React.forwardRef((props, ref) => {
stepError={stepData.error}
stepExitCode={stepData.exit_code}
tmateLink={tmateLink}
stageError={stageError}
stageStatus={stageStatus}
/>
)}
</div>
Expand Down Expand Up @@ -327,6 +345,8 @@ Console.propTypes = {
showFollowLogsBtn: PropTypes.bool,
logsBlobName: PropTypes.string,
onCloseBtnClick: PropTypes.func,
stageError: PropTypes.string,
stageStatus: PropTypes.string,
};

Console.defaultProps = {
Expand All @@ -343,6 +363,8 @@ Console.defaultProps = {
showCloseBtn: false,
onCloseBtnClick: undefined,
logsBlobName: 'step_logs',
stageError: null,
stageStatus: null,
};

export default Console;
16 changes: 16 additions & 0 deletions src/components/shared/console/console.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,19 @@
text-align: center;
margin-bottom: 5px;
}

.stage-error {
background: #22222a;
padding: 1rem;
margin-bottom: 1rem;
border-radius: 0.25rem;
display: flex;
align-items: center;
width: 100%;
.status {
margin-right: 15px;
}
.text {
white-space: pre-wrap;
}
}
2 changes: 2 additions & 0 deletions src/components/shared/console/console.utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export const getStepSummary = (status, error, exitCode) => {
return 'Step is pending';
case 'killed':
return 'Step is killed (canceled)';
case 'skipped':
return error ? 'Skipped due to error' : 'Skipped';
default:
return 'Loading...';
}
Expand Down

0 comments on commit 8092ea1

Please sign in to comment.