Skip to content

Commit a0a5daa

Browse files
authored
Merge pull request #1289 from GnsP/error-classification-ui
fix logviewer styles
2 parents 5f674d8 + fea9972 commit a0a5daa

File tree

7 files changed

+62
-31
lines changed

7 files changed

+62
-31
lines changed

app/cdap/components/LogViewer/LogRow.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { ILogResponse, LogLevel } from 'components/LogViewer/types';
2020
import moment from 'moment';
2121
import { logsTableGridStyle } from 'components/LogViewer';
2222
import classnames from 'classnames';
23+
import LoadingSVG from 'components/shared/LoadingSVG';
2324

2425
const styles = (theme): StyleRules => {
2526
const tableStyle = logsTableGridStyle(theme);
@@ -43,11 +44,20 @@ const styles = (theme): StyleRules => {
4344

4445
interface ILogRowProps extends WithStyles<typeof styles> {
4546
logObj: ILogResponse;
47+
loading?: boolean;
4648
}
4749

4850
const TIMESTAMP_FORMAT = 'L H:mm:ss';
4951

50-
const LogRowView: React.FC<ILogRowProps> = ({ classes, logObj }) => {
52+
const LogRowView: React.FC<ILogRowProps> = ({ classes, logObj, loading = false }) => {
53+
if (loading) {
54+
return (
55+
<div className={classes.root} data-cy="log-viewer-row" data-testid="log-viewer-row">
56+
<LoadingSVG />
57+
</div>
58+
);
59+
}
60+
5161
const timeDate = new Date(logObj.log.timestamp);
5262
const displayTime = moment(timeDate).format(TIMESTAMP_FORMAT);
5363

app/cdap/components/LogViewer/index.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ interface ILogViewerState {
9393
isPolling: boolean;
9494
error?: string;
9595
initLoading: boolean;
96+
isFetchingPrev: boolean;
97+
isFetchingNext: boolean;
9698
}
9799

98100
const MAX_LOG_ROWS = 100;
@@ -120,6 +122,8 @@ class LogViewerView extends React.PureComponent<ILogViewerProps, ILogViewerState
120122
isPolling: true,
121123
error: null,
122124
initLoading: true,
125+
isFetchingPrev: false,
126+
isFetchingNext: false,
123127
};
124128

125129
public componentDidMount() {
@@ -270,7 +274,7 @@ class LogViewerView extends React.PureComponent<ILogViewerProps, ILogViewerState
270274
if (this.state.isFetching || this.state.isPolling) {
271275
return;
272276
}
273-
this.setState({ isFetching: true });
277+
this.setState({ isFetching: true, isFetchingPrev: true });
274278

275279
const logsContainer = this.logsContainer.current;
276280
const currentScrollHeight = logsContainer.scrollHeight;
@@ -284,6 +288,7 @@ class LogViewerView extends React.PureComponent<ILogViewerProps, ILogViewerState
284288
this.setState(
285289
{
286290
isFetching: false,
291+
isFetchingPrev: false,
287292
},
288293
() => {
289294
// maintaining scroll position
@@ -309,7 +314,7 @@ class LogViewerView extends React.PureComponent<ILogViewerProps, ILogViewerState
309314
if (this.state.isFetching || this.state.isPolling) {
310315
return;
311316
}
312-
this.setState({ isFetching: true });
317+
this.setState({ isFetching: true, isFetchingNext: true });
313318

314319
this.props.dataFetcher.getNext().subscribe((res) => {
315320
if (res.length > 0) {
@@ -320,6 +325,7 @@ class LogViewerView extends React.PureComponent<ILogViewerProps, ILogViewerState
320325
this.setState(
321326
{
322327
isFetching: false,
328+
isFetchingNext: false,
323329
},
324330
this.trimTopExcessLogs
325331
);
@@ -431,9 +437,11 @@ class LogViewerView extends React.PureComponent<ILogViewerProps, ILogViewerState
431437

432438
return (
433439
<React.Fragment>
440+
{this.state.isFetchingPrev && <LogRow loading logObj={null} />}
434441
{this.state.logs.map((logObj, i) => {
435442
return <LogRow key={`${logObj.offset}-${i}`} logObj={logObj} />;
436443
})}
444+
{this.state.isFetchingNext && <LogRow loading logObj={null} />}
437445
</React.Fragment>
438446
);
439447
}
@@ -448,7 +456,7 @@ class LogViewerView extends React.PureComponent<ILogViewerProps, ILogViewerState
448456
getLatestLogs={this.getLatestLogs}
449457
setSystemLogs={this.setIncludeSystemLogs}
450458
onClose={this.props.onClose}
451-
loading={this.state.isFetching}
459+
loading={this.state.initLoading}
452460
showStats={this.props.showStats}
453461
/>
454462
<div className={classes.logsTableHeader}>

app/cdap/components/PipelineCanvasActions/ActionButtons/PipelineCanvasActionBtns.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,20 @@
1414
* the License.
1515
*/
1616

17+
import React from 'react';
18+
import { Provider, useSelector } from 'react-redux';
19+
1720
import ZoomInIcon from '@material-ui/icons/ZoomIn';
1821
import ZoomOutIcon from '@material-ui/icons/ZoomOut';
1922
import UndoIcon from '@material-ui/icons/Undo';
2023
import RedoIcon from '@material-ui/icons/Redo';
2124
import AspectRatioIcon from '@material-ui/icons/AspectRatio';
2225
import OpenWithIcon from '@material-ui/icons/OpenWith';
2326
import DragIndicatorIcon from '@material-ui/icons/DragIndicator';
24-
import React from 'react';
2527
import PipelineCommentsActionBtn from '../PipelineCommentsActionBtn';
2628
import { ActionButton, ActionButtonGroup, CanvasButtonTooltip } from './styles';
29+
import PipelineDetailStore from 'components/PipelineDetails/store';
30+
import { isErrorClassificationBannerDisplayed } from 'components/PipelineDetails/PipelineDetailsTopPanel/PipelineRunErrorDetails';
2731

2832
interface IPipelineCanvasActionBtnsProps {
2933
setPipelineComments: () => void;
@@ -41,7 +45,7 @@ interface IPipelineCanvasActionBtnsProps {
4145
zoomIn: () => void;
4246
}
4347

44-
export const PipelineCanvasActionBtns = ({
48+
export const PipelineCanvasActionBtnsView = ({
4549
setPipelineComments,
4650
pipelineComments,
4751
isDisabled,
@@ -56,8 +60,10 @@ export const PipelineCanvasActionBtns = ({
5660
zoomOut,
5761
zoomIn,
5862
}: IPipelineCanvasActionBtnsProps) => {
63+
const isErrorBannerDisplayed = useSelector(isErrorClassificationBannerDisplayed);
64+
5965
return (
60-
<ActionButtonGroup>
66+
<ActionButtonGroup isErrorBannerDisplayed={isErrorBannerDisplayed}>
6167
{!disableNodeClick && (
6268
<>
6369
<CanvasButtonTooltip title="Zoom In">
@@ -143,3 +149,9 @@ export const PipelineCanvasActionBtns = ({
143149
</ActionButtonGroup>
144150
);
145151
};
152+
153+
export const PipelineCanvasActionBtns = (props: IPipelineCanvasActionBtnsProps) => (
154+
<Provider store={PipelineDetailStore}>
155+
<PipelineCanvasActionBtnsView {...props} />
156+
</Provider>
157+
);

app/cdap/components/PipelineCanvasActions/ActionButtons/styles.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export const ActionButtonGroup = styled.div`
3333
position: fixed;
3434
width: 37px;
3535
right: 15px;
36-
top: 170px;
36+
top: ${(props) => (props.isErrorBannerDisplayed ? '202px' : '170px')};
3737
vertical-align: middle;
3838
z-index: 998;
3939
> * {

app/cdap/components/PipelineDetails/PipelineDetailsTopPanel/PipelineRunErrorDetails/ErrorDetailsBanner.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import React, { useEffect, useState } from 'react';
1818
import T from 'i18n-react';
1919
import { useSelector, Provider, useDispatch } from 'react-redux';
2020
import styled from 'styled-components';
21+
import _uniq from 'lodash/uniq';
2122

2223
import LaunchIcon from '@material-ui/icons/Launch';
2324
import GetAppIcon from '@material-ui/icons/GetApp';
@@ -232,7 +233,7 @@ function ErrorDetailsBannerView({
232233
<ShortErrorMessage>
233234
<PipelineErrorCountMessage
234235
classifiedErrorCount={errorDetails?.length}
235-
stages={errorDetails?.map((err) => err.stageName)}
236+
stages={_uniq(errorDetails?.map((err) => err.stageName)?.filter(Boolean) || [])}
236237
/>
237238
{canExapndErrorDetails ? (
238239
<Button
@@ -335,7 +336,7 @@ function ErrorDetailsBannerView({
335336
/>
336337
) : (
337338
<Provider store={PipelineDetailStore}>
338-
<PipelineLogViewer toggleLogViewer={toggleLogs} withErrorBanner={true} />
339+
<PipelineLogViewer toggleLogViewer={toggleLogs} />
339340
</Provider>
340341
))}
341342
</ThemeWrapper>

app/cdap/components/PipelineDetails/PipelineDetailsTopPanel/PipelineRunErrorDetails/index.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import React, { useEffect } from 'react';
1818
import { useSelector, useDispatch } from 'react-redux';
1919

20-
import { ACTIONS } from '../../store';
20+
import PipelineDetailStore, { ACTIONS } from '../../store';
2121
import { MyPipelineApi } from 'api/pipeline';
2222
import { getCurrentNamespace } from 'services/NamespaceStore';
2323
import ProgramDataFetcher from 'components/LogViewer/DataFetcher/ProgramDataFetcher';
@@ -27,6 +27,13 @@ import { IErrorEntry } from './types';
2727
import { RETRY_DELAY_MS } from './constants';
2828
import ErrorDetailsBanner from './ErrorDetailsBanner';
2929

30+
export function isErrorClassificationBannerDisplayed(pipelineDetailsState) {
31+
const { currentRun, runErrorDetailsLoading } = pipelineDetailsState;
32+
const runid = currentRun?.runid;
33+
const loading = runErrorDetailsLoading[runid] || false;
34+
return currentRun?.status === 'FAILED' && !loading;
35+
}
36+
3037
export default function PipelineRunErrorDetails() {
3138
const appId = useSelector((state) => state.name);
3239
const artifactName = useSelector((state) => state.artifact.name);

app/cdap/components/PipelineDetails/RunLevelInfo/PipelineLogViewer/index.tsx

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,42 +26,38 @@ import { GLOBALS } from 'services/global-constants';
2626
import ProgramDataFetcher from 'components/LogViewer/DataFetcher/ProgramDataFetcher';
2727
import LogViewer from 'components/LogViewer';
2828
import { PIPELINE_LOGS_FILTER } from 'services/global-constants';
29+
import { isErrorClassificationBannerDisplayed } from 'components/PipelineDetails/PipelineDetailsTopPanel/PipelineRunErrorDetails';
2930

30-
const PIPELINE_TOP_PANEL_OFFSET = '160px';
31+
const LOGVIEWER_TOP_OFFSET = '110px';
3132
const FOOTER_HEIGHT = '54px';
32-
33-
const ERROR_BANNER_OFFSET = '20px'; // to align the top of the logs viewer when the error banner is present
34-
const LOGS_PORTAL_OFFSET = '50px'; // to remove the unnecessary page scroll
33+
const HEADER_HEIGHT = '48px';
34+
const ERROR_BANNER_OFFSET = '32px'; // to align the top of the logs viewer when the error banner is present
3535

3636
const styles = (theme): StyleRules => {
3737
const portalContainerBase = {
38-
position: 'absolute',
39-
top: 0,
38+
position: 'fixed',
39+
top: HEADER_HEIGHT,
4040
left: 0,
41-
height: '100vh',
41+
height: `calc(100vh - ${HEADER_HEIGHT} - ${FOOTER_HEIGHT})`,
4242
width: '100vw',
4343
zIndex: 1301,
4444
};
4545

4646
const logsContainerBase = {
4747
position: 'absolute',
48-
top: PIPELINE_TOP_PANEL_OFFSET,
49-
height: `calc(100% - ${PIPELINE_TOP_PANEL_OFFSET} - ${FOOTER_HEIGHT})`,
48+
top: LOGVIEWER_TOP_OFFSET,
49+
height: `calc(100% - ${LOGVIEWER_TOP_OFFSET})`,
5050
width: '100%',
5151
backgroundColor: theme.palette.white[50],
5252
};
5353

5454
return {
5555
portalContainer: portalContainerBase as CreateCSSProperties<{}>,
5656
logsContainer: logsContainerBase as CreateCSSProperties<{}>,
57-
portalContainerWithErrorBanner: {
58-
...portalContainerBase,
59-
height: `calc(100vh - ${LOGS_PORTAL_OFFSET})`,
60-
} as CreateCSSProperties<{}>,
6157
logsContainerWithErrorBanner: {
6258
...logsContainerBase,
63-
height: `calc(100% - ${PIPELINE_TOP_PANEL_OFFSET} - ${FOOTER_HEIGHT} - ${ERROR_BANNER_OFFSET})`,
64-
top: `calc(${PIPELINE_TOP_PANEL_OFFSET} - ${ERROR_BANNER_OFFSET})`,
59+
height: `calc(100% - ${LOGVIEWER_TOP_OFFSET} - ${ERROR_BANNER_OFFSET})`,
60+
top: `calc(${LOGVIEWER_TOP_OFFSET} + ${ERROR_BANNER_OFFSET})`,
6561
} as CreateCSSProperties<{}>,
6662
};
6763
};
@@ -107,11 +103,7 @@ const LogViewerContainer: React.FC<ILogViewerProps> = ({
107103
}
108104

109105
return (
110-
<div
111-
className={withErrorBanner ? classes.portalContainerWithErrorBanner : classes.portalContainer}
112-
ref={backgroundElem}
113-
onClick={handleBackgroundClick}
114-
>
106+
<div className={classes.portalContainer} ref={backgroundElem} onClick={handleBackgroundClick}>
115107
<div
116108
className={withErrorBanner ? classes.logsContainerWithErrorBanner : classes.logsContainer}
117109
>
@@ -128,6 +120,7 @@ const mapStateToProps = (state) => {
128120
currentRun: state.currentRun,
129121
appId: state.name,
130122
artifactName: state.artifact.name,
123+
withErrorBanner: isErrorClassificationBannerDisplayed(state),
131124
};
132125
};
133126

0 commit comments

Comments
 (0)