Skip to content

Commit

Permalink
implement button and scrolling
Browse files Browse the repository at this point in the history
  • Loading branch information
svennergr committed Jun 13, 2023
1 parent f7b25c9 commit 54eb0fc
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 10 deletions.
46 changes: 46 additions & 0 deletions public/app/features/explore/Logs/Logs.tsx
Expand Up @@ -27,6 +27,8 @@ import {
EventBus,
LogRowContextOptions,
ExplorePanelsState,
serializeStateToUrlParam,
urlUtil,
} from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
import { DataQuery } from '@grafana/schema';
Expand All @@ -42,10 +44,14 @@ import {
} from '@grafana/ui';
import { dedupLogRows, filterLogLevels } from 'app/core/logsModel';
import store from 'app/core/store';
import { createAndCopyShortLink } from 'app/core/utils/shortLinks';
import { getState, dispatch } from 'app/store/store';
import { ExploreId } from 'app/types/explore';

import { LogRows } from '../../logs/components/LogRows';
import { LogRowContextModal } from '../../logs/components/log-context/LogRowContextModal';
import { changePanelState } from '../state/explorePane';
import { getUrlStateFromPaneState } from '../state/utils';

import { LogsMetaRow } from './LogsMetaRow';
import LogsNavigation from './LogsNavigation';
Expand Down Expand Up @@ -159,6 +165,18 @@ class UnthemedLogs extends PureComponent<Props, State> {
}
}

componentDidUpdate(prevProps: Readonly<Props>): void {
if (this.props.loading && !prevProps.loading && this.props.panelState?.logs?.id) {
// loading stopped, so we need to remove any permalinked log lines
delete this.props.panelState.logs.id;
dispatch(
changePanelState(this.props.exploreId, 'logs', {
...this.props.panelState,
})
);
}
}

onLogRowHover = (row?: LogRowModel) => {
if (!row) {
this.props.eventBus.publish(new DataHoverClearEvent());
Expand Down Expand Up @@ -333,6 +351,31 @@ class UnthemedLogs extends PureComponent<Props, State> {
};
};

onPermalinkClick = async (row: LogRowModel) => {
const urlState = getUrlStateFromPaneState(getState().explore.panes[this.props.exploreId]!);
urlState.panelsState = { ...this.props.panelState, logs: { id: row.uid } };
urlState.range = {
from: new Date(this.props.absoluteRange.from).toISOString(),
to: new Date(this.props.absoluteRange.to).toISOString(),
};

const serializedState = serializeStateToUrlParam(urlState);
const baseUrl = /.*(?=\/explore)/.exec(`${window.location.href}`)![0];
const url = urlUtil.renderUrl(`${baseUrl}/explore`, { left: serializedState });
await createAndCopyShortLink(url);
};

scrollIntoView = (element: HTMLElement) => {
const { scrollElement } = this.props;

if (scrollElement) {
scrollElement.scroll({
behavior: 'smooth',
top: scrollElement.scrollTop + element.getBoundingClientRect().top - window.innerHeight / 2,
});
}
};

checkUnescapedContent = memoizeOne((logRows: LogRowModel[]) => {
return !!logRows.some((r) => r.hasUnescapedContent);
});
Expand Down Expand Up @@ -558,6 +601,9 @@ class UnthemedLogs extends PureComponent<Props, State> {
app={CoreApp.Explore}
onLogRowHover={this.onLogRowHover}
onOpenContext={this.onOpenContext}
onPermalinkClick={this.onPermalinkClick}
permalinkedRowId={this.props.panelState?.logs?.id}
scrollIntoView={this.scrollIntoView}
/>
{!loading && !hasData && !scanning && (
<div className={styles.noData}>
Expand Down
54 changes: 47 additions & 7 deletions public/app/features/logs/components/LogRow.tsx
Expand Up @@ -38,11 +38,14 @@ interface Props extends Themeable2 {
onClickHideField?: (key: string) => void;
onLogRowHover?: (row?: LogRowModel) => void;
onOpenContext: (row: LogRowModel, onClose: () => void) => void;
onPermalinkClick?: (row: LogRowModel) => Promise<void>;
styles: LogRowStyles;
permalinkedRowId?: string;
scrollIntoView: (element: HTMLElement) => void;
}

interface State {
showContext: boolean;
highlightBackround: boolean;
showDetails: boolean;
}

Expand All @@ -55,17 +58,17 @@ interface State {
*/
class UnThemedLogRow extends PureComponent<Props, State> {
state: State = {
showContext: false,
highlightBackround: false,
showDetails: false,
};

// we are debouncing the state change by 3 seconds to highlight the logline after the context closed.
debouncedContextClose = debounce(() => {
this.setState({ showContext: false });
this.setState({ highlightBackround: false });
}, 3000);

onOpenContext = (row: LogRowModel) => {
this.setState({ showContext: true });
this.setState({ highlightBackround: true });
this.props.onOpenContext(row, this.debouncedContextClose);
};

Expand All @@ -87,6 +90,7 @@ class UnThemedLogRow extends PureComponent<Props, State> {
};
});
};
logLineRef: React.RefObject<HTMLTableRowElement>;

renderTimeStamp(epochMs: number) {
return dateTimeFormat(epochMs, {
Expand All @@ -107,6 +111,35 @@ class UnThemedLogRow extends PureComponent<Props, State> {
}
};

constructor(props: Props) {
super(props);
this.logLineRef = React.createRef();
}

componentDidMount() {
this.scrollToLogRow();
}

componentDidUpdate(prevProps: Readonly<Props>, prevState: Readonly<State>): void {
if (
this.props.permalinkedRowId !== prevProps.permalinkedRowId &&
this.props.permalinkedRowId !== this.props.row.uid
) {
this.setState({ highlightBackround: false });
} else if (this.props.permalinkedRowId === this.props.row.uid && !this.state.highlightBackround) {
this.scrollToLogRow();
}
}

scrollToLogRow = () => {
if (this.logLineRef.current && this.props.permalinkedRowId === this.props.row.uid) {
this.props.scrollIntoView(this.logLineRef.current);
this.setState({ highlightBackround: true });
} else {
this.setState({ highlightBackround: false });
}
};

render() {
const {
getRows,
Expand All @@ -129,12 +162,16 @@ class UnThemedLogRow extends PureComponent<Props, State> {
app,
styles,
} = this.props;
const { showDetails, showContext } = this.state;
const { showDetails, highlightBackround } = this.state;
const levelStyles = getLogLevelStyles(theme, row.logLevel);
const { errorMessage, hasError } = checkLogsError(row);
const logRowBackground = cx(styles.logsRow, {
[styles.errorLogRow]: hasError,
[styles.contextBackground]: showContext,
[styles.highlightBackground]: highlightBackround,
});
const logRowDetailsBackground = cx(styles.logsRow, {
[styles.errorLogRow]: hasError,
[styles.highlightBackground]: highlightBackround && !this.state.showDetails,
});

const processedRow =
Expand All @@ -145,6 +182,7 @@ class UnThemedLogRow extends PureComponent<Props, State> {
return (
<>
<tr
ref={this.logLineRef}
className={logRowBackground}
onClick={this.toggleDetails}
onMouseEnter={this.onMouseEnter}
Expand Down Expand Up @@ -187,14 +225,16 @@ class UnThemedLogRow extends PureComponent<Props, State> {
wrapLogMessage={wrapLogMessage}
prettifyLogMessage={prettifyLogMessage}
onOpenContext={this.onOpenContext}
onPermalinkClick={this.props.onPermalinkClick}
app={app}
styles={styles}
permalinkedRowId={this.props.permalinkedRowId}
/>
)}
</tr>
{this.state.showDetails && (
<LogDetails
className={logRowBackground}
className={logRowDetailsBackground}
showDuplicates={showDuplicates}
getFieldLinks={getFieldLinks}
onClickFilterLabel={onClickFilterLabel}
Expand Down
24 changes: 21 additions & 3 deletions public/app/features/logs/components/LogRowMessage.tsx
Expand Up @@ -18,7 +18,9 @@ interface Props {
app?: CoreApp;
showContextToggle?: (row?: LogRowModel) => boolean;
onOpenContext: (row: LogRowModel) => void;
onPermalinkClick?: (row: LogRowModel) => Promise<void>;
styles: LogRowStyles;
permalinkedRowId?: string;
}

function renderLogMessage(
Expand Down Expand Up @@ -58,7 +60,14 @@ const restructureLog = memoizeOne((line: string, prettifyLogMessage: boolean): s
return line;
});

interface State {
link: string;
}
export class LogRowMessage extends PureComponent<Props> {
state: State = {
link: '',
};

onShowContextClick = (e: React.SyntheticEvent<HTMLElement, Event>) => {
const { onOpenContext } = this.props;
e.stopPropagation();
Expand All @@ -76,7 +85,7 @@ export class LogRowMessage extends PureComponent<Props> {
};

render() {
const { row, wrapLogMessage, prettifyLogMessage, showContextToggle, styles } = this.props;
const { row, wrapLogMessage, prettifyLogMessage, showContextToggle, styles, onPermalinkClick } = this.props;
const { hasAnsi, raw } = row;
const restructuredEntry = restructureLog(raw, prettifyLogMessage);
const shouldShowContextToggle = showContextToggle ? showContextToggle(row) : false;
Expand All @@ -100,7 +109,7 @@ export class LogRowMessage extends PureComponent<Props> {
</div>
</td>
<td className={cx('log-row-menu-cell', styles.logRowMenuCell)}>
<span className={cx('log-row-menu', styles.rowMenu)} onClick={this.onLogRowClick}>
<span className={cx('log-row-menu', styles.rowMenu, styles.hidden)} onClick={this.onLogRowClick}>
{shouldShowContextToggle && (
<IconButton
tooltip="Show context"
Expand All @@ -117,9 +126,18 @@ export class LogRowMessage extends PureComponent<Props> {
fill="text"
size="md"
getText={this.getLogText}
tooltip="Copy"
tooltip="Copy logline to clipboard"
tooltipPlacement="top"
/>
{onPermalinkClick && row.uid && (
<IconButton
tooltip="Copy shortlink to logline"
tooltipPlacement="top"
size="md"
name="link"
onClick={() => onPermalinkClick(row)}
/>
)}
</span>
</td>
</>
Expand Down

0 comments on commit 54eb0fc

Please sign in to comment.