Logs Panel: Refactor style generation to improve rendering performance (#62599)

* Log row: move level styles to its own provider

* Log row message: remove unnecessary extra param from styles

* Log rows: parse and pass styles to children

* Log row: receive parsed styles props from parent

* Log details: receive styles from parent

* Revert "Log details: receive styles from parent"

This reverts commit 8487482a6f4fdcf5e26896182c5ad3982774eea2.

* Log row message: receive styles from parent

* Chore: remove unnecessary comment

* Log level styles: move common styles out of getLogLevelStyles

* Chore: fix TimeZone deprecated import

* Log Details: inverse ternary operator for readability

Co-authored-by: Sven Grossmann <sven.grossmann@grafana.com>

* Log Details: inverse ternary operator for readability

Co-authored-by: Sven Grossmann <sven.grossmann@grafana.com>

* Chore: apply prettier formatting

---------

Co-authored-by: Sven Grossmann <sven.grossmann@grafana.com>
pull/62700/head
Matias Chomicki 2 years ago committed by GitHub
parent 42f8f5a9ea
commit c139768e3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 19
      public/app/features/logs/components/LogDetails.tsx
  2. 51
      public/app/features/logs/components/LogRow.tsx
  3. 102
      public/app/features/logs/components/LogRowMessage.tsx
  4. 6
      public/app/features/logs/components/LogRows.tsx
  5. 127
      public/app/features/logs/components/getLogRowStyles.ts

@ -7,11 +7,9 @@ import { Themeable2, withTheme2 } from '@grafana/ui';
import { calculateLogsLabelStats, calculateStats } from '../utils'; import { calculateLogsLabelStats, calculateStats } from '../utils';
import { LogDetailsRow } from './LogDetailsRow'; import { LogDetailsRow } from './LogDetailsRow';
import { getLogRowStyles } from './getLogRowStyles'; import { getLogLevelStyles, getLogRowStyles } from './getLogRowStyles';
import { getAllFields } from './logParser'; import { getAllFields } from './logParser';
//Components
export interface Props extends Themeable2 { export interface Props extends Themeable2 {
row: LogRowModel; row: LogRowModel;
showDuplicates: boolean; showDuplicates: boolean;
@ -66,7 +64,8 @@ class UnThemedLogDetails extends PureComponent<Props> {
getFieldLinks, getFieldLinks,
wrapLogMessage, wrapLogMessage,
} = this.props; } = this.props;
const style = getLogRowStyles(theme, row.logLevel); const rowStyles = getLogRowStyles(theme);
const levelStyles = getLogLevelStyles(theme, row.logLevel);
const styles = getStyles(theme); const styles = getStyles(theme);
const labels = row.labels ? row.labels : {}; const labels = row.labels ? row.labels : {};
const labelsAvailable = Object.keys(labels).length > 0; const labelsAvailable = Object.keys(labels).length > 0;
@ -77,19 +76,21 @@ class UnThemedLogDetails extends PureComponent<Props> {
const linksAvailable = links && links.length > 0; const linksAvailable = links && links.length > 0;
// If logs with error, we are not showing the level color // If logs with error, we are not showing the level color
const levelClassName = cx(!hasError && [style.logsRowLevel, styles.logsRowLevelDetails]); const levelClassName = hasError
? ''
: `${levelStyles.logsRowLevelColor} ${rowStyles.logsRowLevel} ${styles.logsRowLevelDetails}`;
return ( return (
<tr className={cx(className, styles.logDetails)}> <tr className={cx(className, styles.logDetails)}>
{showDuplicates && <td />} {showDuplicates && <td />}
<td className={levelClassName} aria-label="Log level" /> <td className={levelClassName} aria-label="Log level" />
<td colSpan={4}> <td colSpan={4}>
<div className={style.logDetailsContainer}> <div className={rowStyles.logDetailsContainer}>
<table className={style.logDetailsTable}> <table className={rowStyles.logDetailsTable}>
<tbody> <tbody>
{(labelsAvailable || fieldsAvailable) && ( {(labelsAvailable || fieldsAvailable) && (
<tr> <tr>
<td colSpan={100} className={style.logDetailsHeading} aria-label="Fields"> <td colSpan={100} className={rowStyles.logDetailsHeading} aria-label="Fields">
Fields Fields
</td> </td>
</tr> </tr>
@ -138,7 +139,7 @@ class UnThemedLogDetails extends PureComponent<Props> {
{linksAvailable && ( {linksAvailable && (
<tr> <tr>
<td colSpan={100} className={style.logDetailsHeading} aria-label="Data Links"> <td colSpan={100} className={rowStyles.logDetailsHeading} aria-label="Data Links">
Links Links
</td> </td>
</tr> </tr>

@ -1,4 +1,4 @@
import { cx, css } from '@emotion/css'; import { cx } from '@emotion/css';
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { import {
@ -6,16 +6,15 @@ import {
LinkModel, LinkModel,
LogRowModel, LogRowModel,
LogsSortOrder, LogsSortOrder,
TimeZone,
DataQueryResponse, DataQueryResponse,
dateTimeFormat, dateTimeFormat,
GrafanaTheme2,
CoreApp, CoreApp,
DataFrame, DataFrame,
DataSourceWithLogsContextSupport, DataSourceWithLogsContextSupport,
} from '@grafana/data'; } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime'; import { reportInteraction } from '@grafana/runtime';
import { styleMixins, withTheme2, Themeable2, Icon, Tooltip } from '@grafana/ui'; import { TimeZone } from '@grafana/schema';
import { withTheme2, Themeable2, Icon, Tooltip } from '@grafana/ui';
import { checkLogsError, escapeUnescapedString } from '../utils'; import { checkLogsError, escapeUnescapedString } from '../utils';
@ -30,9 +29,7 @@ import {
} from './LogRowContextProvider'; } from './LogRowContextProvider';
import { LogRowMessage } from './LogRowMessage'; import { LogRowMessage } from './LogRowMessage';
import { LogRowMessageDisplayedFields } from './LogRowMessageDisplayedFields'; import { LogRowMessageDisplayedFields } from './LogRowMessageDisplayedFields';
import { getLogRowStyles } from './getLogRowStyles'; import { getLogLevelStyles, LogRowStyles } from './getLogRowStyles';
//Components
interface Props extends Themeable2 { interface Props extends Themeable2 {
row: LogRowModel; row: LogRowModel;
@ -61,6 +58,7 @@ interface Props extends Themeable2 {
onClickHideField?: (key: string) => void; onClickHideField?: (key: string) => void;
onLogRowHover?: (row?: LogRowModel) => void; onLogRowHover?: (row?: LogRowModel) => void;
toggleContextIsOpen?: () => void; toggleContextIsOpen?: () => void;
styles: LogRowStyles;
} }
interface State { interface State {
@ -68,24 +66,6 @@ interface State {
showDetails: boolean; showDetails: boolean;
} }
const getStyles = (theme: GrafanaTheme2) => {
return {
topVerticalAlign: css`
label: topVerticalAlign;
margin-top: -${theme.spacing(0.9)};
margin-left: -${theme.spacing(0.25)};
`,
detailsOpen: css`
&:hover {
background-color: ${styleMixins.hoverColor(theme.colors.background.primary, theme)};
}
`,
errorLogRow: css`
label: erroredLogRow;
color: ${theme.colors.text.secondary};
`,
};
};
/** /**
* Renders a log line. * Renders a log line.
* *
@ -171,14 +151,14 @@ class UnThemedLogRow extends PureComponent<Props, State> {
onLogRowHover, onLogRowHover,
app, app,
scrollElement, scrollElement,
styles,
} = this.props; } = this.props;
const { showDetails, showContext } = this.state; const { showDetails, showContext } = this.state;
const style = getLogRowStyles(theme, row.logLevel); const levelStyles = getLogLevelStyles(theme, row.logLevel);
const styles = getStyles(theme);
const { errorMessage, hasError } = checkLogsError(row); const { errorMessage, hasError } = checkLogsError(row);
const logRowBackground = cx(style.logsRow, { const logRowBackground = cx(styles.logsRow, {
[styles.errorLogRow]: hasError, [styles.errorLogRow]: hasError,
[style.contextBackground]: showContext, [styles.contextBackground]: showContext,
}); });
const processedRow = const processedRow =
@ -199,25 +179,25 @@ class UnThemedLogRow extends PureComponent<Props, State> {
}} }}
> >
{showDuplicates && ( {showDuplicates && (
<td className={style.logsRowDuplicates}> <td className={styles.logsRowDuplicates}>
{processedRow.duplicates && processedRow.duplicates > 0 ? `${processedRow.duplicates + 1}x` : null} {processedRow.duplicates && processedRow.duplicates > 0 ? `${processedRow.duplicates + 1}x` : null}
</td> </td>
)} )}
<td className={cx({ [style.logsRowLevel]: !hasError })}> <td className={hasError ? '' : `${levelStyles.logsRowLevelColor} ${styles.logsRowLevel}`}>
{hasError && ( {hasError && (
<Tooltip content={`Error: ${errorMessage}`} placement="right" theme="error"> <Tooltip content={`Error: ${errorMessage}`} placement="right" theme="error">
<Icon className={style.logIconError} name="exclamation-triangle" size="xs" /> <Icon className={styles.logIconError} name="exclamation-triangle" size="xs" />
</Tooltip> </Tooltip>
)} )}
</td> </td>
{enableLogDetails && ( {enableLogDetails && (
<td title={showDetails ? 'Hide log details' : 'See log details'} className={style.logsRowToggleDetails}> <td title={showDetails ? 'Hide log details' : 'See log details'} className={styles.logsRowToggleDetails}>
<Icon className={styles.topVerticalAlign} name={showDetails ? 'angle-down' : 'angle-right'} /> <Icon className={styles.topVerticalAlign} name={showDetails ? 'angle-down' : 'angle-right'} />
</td> </td>
)} )}
{showTime && <td className={style.logsRowLocalTime}>{this.renderTimeStamp(row.timeEpochMs)}</td>} {showTime && <td className={styles.logsRowLocalTime}>{this.renderTimeStamp(row.timeEpochMs)}</td>}
{showLabels && processedRow.uniqueLabels && ( {showLabels && processedRow.uniqueLabels && (
<td className={style.logsRowLabels}> <td className={styles.logsRowLabels}>
<LogLabels labels={processedRow.uniqueLabels} /> <LogLabels labels={processedRow.uniqueLabels} />
</td> </td>
)} )}
@ -247,6 +227,7 @@ class UnThemedLogRow extends PureComponent<Props, State> {
app={app} app={app}
scrollElement={scrollElement} scrollElement={scrollElement}
logsSortOrder={logsSortOrder} logsSortOrder={logsSortOrder}
styles={styles}
/> />
)} )}
</tr> </tr>

@ -1,27 +1,25 @@
import { css, cx } from '@emotion/css'; import { cx } from '@emotion/css';
import memoizeOne from 'memoize-one'; import memoizeOne from 'memoize-one';
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import Highlighter from 'react-highlight-words'; import Highlighter from 'react-highlight-words';
import tinycolor from 'tinycolor2';
import { import {
LogRowModel, LogRowModel,
findHighlightChunksInText, findHighlightChunksInText,
GrafanaTheme2,
LogsSortOrder, LogsSortOrder,
CoreApp, CoreApp,
DataSourceWithLogsContextSupport, DataSourceWithLogsContextSupport,
} from '@grafana/data'; } from '@grafana/data';
import { withTheme2, Themeable2, IconButton, Tooltip } from '@grafana/ui'; import { IconButton, Tooltip } from '@grafana/ui';
import { LogMessageAnsi } from './LogMessageAnsi'; import { LogMessageAnsi } from './LogMessageAnsi';
import { LogRowContext } from './LogRowContext'; import { LogRowContext } from './LogRowContext';
import { LogRowContextQueryErrors, HasMoreContextRows, LogRowContextRows } from './LogRowContextProvider'; import { LogRowContextQueryErrors, HasMoreContextRows, LogRowContextRows } from './LogRowContextProvider';
import { getLogRowStyles } from './getLogRowStyles'; import { LogRowStyles } from './getLogRowStyles';
export const MAX_CHARACTERS = 100000; export const MAX_CHARACTERS = 100000;
interface Props extends Themeable2 { interface Props {
row: LogRowModel; row: LogRowModel;
hasMoreContextRows?: HasMoreContextRows; hasMoreContextRows?: HasMoreContextRows;
contextIsOpen: boolean; contextIsOpen: boolean;
@ -39,67 +37,9 @@ interface Props extends Themeable2 {
updateLimit?: () => void; updateLimit?: () => void;
runContextQuery?: () => void; runContextQuery?: () => void;
logsSortOrder?: LogsSortOrder | null; logsSortOrder?: LogsSortOrder | null;
styles: LogRowStyles;
} }
const getStyles = (theme: GrafanaTheme2, showContextButton: boolean, isInExplore: boolean) => {
const outlineColor = tinycolor(theme.components.dashboard.background).setAlpha(0.7).toRgbString();
return {
positionRelative: css`
label: positionRelative;
position: relative;
`,
rowWithContext: css`
label: rowWithContext;
z-index: 1;
outline: 9999px solid ${outlineColor};
display: inherit;
`,
horizontalScroll: css`
label: horizontalScroll;
white-space: pre;
`,
contextNewline: css`
display: block;
margin-left: 0px;
`,
rowMenu: css`
display: flex;
flex-wrap: nowrap;
flex-direction: row;
align-content: flex-end;
justify-content: space-evenly;
align-items: center;
position: absolute;
top: 0;
bottom: auto;
height: ${theme.spacing(4.5)};
background: ${theme.colors.background.primary};
box-shadow: ${theme.shadows.z3};
padding: ${theme.spacing(0, 0, 0, 0.5)};
z-index: 100;
visibility: hidden;
width: ${showContextButton ? theme.spacing(10) : theme.spacing(5)};
`,
logRowMenuCell: css`
position: absolute;
right: ${!isInExplore ? '40px' : `calc(75px + ${theme.spacing()} + ${showContextButton ? '80px' : '40px'})`};
margin-top: -${theme.spacing(0.125)};
`,
logLine: css`
background-color: transparent;
border: none;
diplay: inline;
font-family: ${theme.typography.fontFamilyMonospace};
font-size: ${theme.typography.bodySmall.fontSize};
letter-spacing: ${theme.typography.bodySmall.letterSpacing};
text-align: left;
padding: 0;
user-select: text;
`,
};
};
function renderLogMessage( function renderLogMessage(
hasAnsi: boolean, hasAnsi: boolean,
entry: string, entry: string,
@ -137,7 +77,7 @@ const restructureLog = memoizeOne((line: string, prettifyLogMessage: boolean): s
return line; return line;
}); });
class UnThemedLogRowMessage extends PureComponent<Props> { export class LogRowMessage extends PureComponent<Props> {
logRowRef: React.RefObject<HTMLTableCellElement> = React.createRef(); logRowRef: React.RefObject<HTMLTableCellElement> = React.createRef();
onContextToggle = (e: React.SyntheticEvent<HTMLElement>) => { onContextToggle = (e: React.SyntheticEvent<HTMLElement>) => {
@ -159,7 +99,6 @@ class UnThemedLogRowMessage extends PureComponent<Props> {
render() { render() {
const { const {
row, row,
theme,
errors, errors,
hasMoreContextRows, hasMoreContextRows,
updateLimit, updateLimit,
@ -174,24 +113,23 @@ class UnThemedLogRowMessage extends PureComponent<Props> {
logsSortOrder, logsSortOrder,
showContextToggle, showContextToggle,
getLogRowContextUi, getLogRowContextUi,
styles,
} = this.props; } = this.props;
const style = getLogRowStyles(theme, row.logLevel);
const { hasAnsi, raw } = row; const { hasAnsi, raw } = row;
const restructuredEntry = restructureLog(raw, prettifyLogMessage); const restructuredEntry = restructureLog(raw, prettifyLogMessage);
const shouldShowContextToggle = showContextToggle ? showContextToggle(row) : false; const shouldShowContextToggle = showContextToggle ? showContextToggle(row) : false;
const styles = getStyles(theme, shouldShowContextToggle, app === CoreApp.Explore); const inExplore = app === CoreApp.Explore;
return ( return (
<> <>
{ {
// When context is open, the position has to be NOT relative. // Setting the postion as inline-style to // When context is open, the position has to be NOT relative. // Setting the postion as inline-style to
// overwrite the more sepecific style definition from `style.logsRowMessage`. // overwrite the more sepecific style definition from `styles.logsRowMessage`.
} }
<td <td
ref={this.logRowRef} ref={this.logRowRef}
style={contextIsOpen ? { position: 'unset' } : undefined} style={contextIsOpen ? { position: 'unset' } : undefined}
className={style.logsRowMessage} className={styles.logsRowMessage}
> >
<div <div
className={cx( className={cx(
@ -218,13 +156,24 @@ class UnThemedLogRowMessage extends PureComponent<Props> {
/> />
)} )}
<button className={cx(styles.logLine, styles.positionRelative, { [styles.rowWithContext]: contextIsOpen })}> <button className={cx(styles.logLine, styles.positionRelative, { [styles.rowWithContext]: contextIsOpen })}>
{renderLogMessage(hasAnsi, restructuredEntry, row.searchWords, style.logsRowMatchHighLight)} {renderLogMessage(hasAnsi, restructuredEntry, row.searchWords, styles.logsRowMatchHighLight)}
</button> </button>
</div> </div>
</td> </td>
{showRowMenu && ( {showRowMenu && (
<td className={cx('log-row-menu-cell', styles.logRowMenuCell)}> <td
<span className={cx('log-row-menu', styles.rowMenu)} onClick={(e) => e.stopPropagation()}> className={cx('log-row-menu-cell', styles.logRowMenuCell, {
[styles.logRowMenuCellDefaultPosition]: !inExplore,
[styles.logRowMenuCellExplore]: inExplore && !shouldShowContextToggle,
[styles.logRowMenuCellExploreWithContextButton]: inExplore && shouldShowContextToggle,
})}
>
<span
className={cx('log-row-menu', styles.rowMenu, {
[styles.rowMenuWithContextButton]: shouldShowContextToggle,
})}
onClick={(e) => e.stopPropagation()}
>
{shouldShowContextToggle && ( {shouldShowContextToggle && (
<Tooltip placement="top" content={'Show context'}> <Tooltip placement="top" content={'Show context'}>
<IconButton size="md" name="gf-show-context" onClick={this.onShowContextClick} /> <IconButton size="md" name="gf-show-context" onClick={this.onShowContextClick} />
@ -240,6 +189,3 @@ class UnThemedLogRowMessage extends PureComponent<Props> {
); );
} }
} }
export const LogRowMessage = withTheme2(UnThemedLogRowMessage);
LogRowMessage.displayName = 'LogRowMessage';

@ -133,7 +133,7 @@ class UnThemedLogRows extends PureComponent<Props, State> {
getLogRowContextUi, getLogRowContextUi,
} = this.props; } = this.props;
const { renderAll, contextIsOpen } = this.state; const { renderAll, contextIsOpen } = this.state;
const { logsRowsTable } = getLogRowStyles(theme); const styles = getLogRowStyles(theme);
const dedupedRows = deduplicatedRows ? deduplicatedRows : logRows; const dedupedRows = deduplicatedRows ? deduplicatedRows : logRows;
const hasData = logRows && logRows.length > 0; const hasData = logRows && logRows.length > 0;
const dedupCount = dedupedRows const dedupCount = dedupedRows
@ -151,7 +151,7 @@ class UnThemedLogRows extends PureComponent<Props, State> {
const getRowContext = this.props.getRowContext ? this.props.getRowContext : () => Promise.resolve([]); const getRowContext = this.props.getRowContext ? this.props.getRowContext : () => Promise.resolve([]);
return ( return (
<table className={logsRowsTable}> <table className={styles.logsRowsTable}>
<tbody> <tbody>
{hasData && {hasData &&
firstRows.map((row, index) => ( firstRows.map((row, index) => (
@ -182,6 +182,7 @@ class UnThemedLogRows extends PureComponent<Props, State> {
onLogRowHover={onLogRowHover} onLogRowHover={onLogRowHover}
app={app} app={app}
scrollElement={scrollElement} scrollElement={scrollElement}
styles={styles}
/> />
))} ))}
{hasData && {hasData &&
@ -214,6 +215,7 @@ class UnThemedLogRows extends PureComponent<Props, State> {
onLogRowHover={onLogRowHover} onLogRowHover={onLogRowHover}
app={app} app={app}
scrollElement={scrollElement} scrollElement={scrollElement}
styles={styles}
/> />
))} ))}
{hasData && !renderAll && ( {hasData && !renderAll && (

@ -1,12 +1,11 @@
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import tinycolor from 'tinycolor2';
import { GrafanaTheme2, LogLevel } from '@grafana/data'; import { GrafanaTheme2, LogLevel } from '@grafana/data';
import { styleMixins } from '@grafana/ui'; import { styleMixins } from '@grafana/ui';
export const getLogRowStyles = (theme: GrafanaTheme2, logLevel?: LogLevel) => { export const getLogLevelStyles = (theme: GrafanaTheme2, logLevel?: LogLevel) => {
let logColor = theme.isLight ? theme.v1.palette.gray5 : theme.v1.palette.gray2; let logColor = theme.isLight ? theme.v1.palette.gray5 : theme.v1.palette.gray2;
const hoverBgColor = styleMixins.hoverColor(theme.colors.background.secondary, theme);
switch (logLevel) { switch (logLevel) {
case LogLevel.crit: case LogLevel.crit:
case LogLevel.critical: case LogLevel.critical:
@ -32,6 +31,32 @@ export const getLogRowStyles = (theme: GrafanaTheme2, logLevel?: LogLevel) => {
} }
return { return {
logsRowLevelColor: css`
&::after {
background-color: ${logColor};
}
`,
};
};
export const getLogRowStyles = (theme: GrafanaTheme2) => {
const hoverBgColor = styleMixins.hoverColor(theme.colors.background.secondary, theme);
const contextOutlineColor = tinycolor(theme.components.dashboard.background).setAlpha(0.7).toRgbString();
return {
logsRowLevel: css`
label: logs-row__level;
max-width: ${theme.spacing(1.25)};
cursor: default;
&::after {
content: '';
display: block;
position: absolute;
top: 1px;
bottom: 1px;
width: 3px;
left: ${theme.spacing(0.5)};
}
`,
logsRowMatchHighLight: css` logsRowMatchHighLight: css`
label: logs-row__match-highlight; label: logs-row__match-highlight;
background: inherit; background: inherit;
@ -81,21 +106,6 @@ export const getLogRowStyles = (theme: GrafanaTheme2, logLevel?: LogLevel) => {
width: 4em; width: 4em;
cursor: default; cursor: default;
`, `,
logsRowLevel: css`
label: logs-row__level;
max-width: ${theme.spacing(1.25)};
cursor: default;
&::after {
content: '';
display: block;
position: absolute;
top: 1px;
bottom: 1px;
width: 3px;
left: ${theme.spacing(0.5)};
background-color: ${logColor};
}
`,
logIconError: css` logIconError: css`
color: ${theme.colors.warning.main}; color: ${theme.colors.warning.main};
`, `,
@ -174,5 +184,86 @@ export const getLogRowStyles = (theme: GrafanaTheme2, logLevel?: LogLevel) => {
background-color: ${hoverBgColor}; background-color: ${hoverBgColor};
} }
`, `,
// Log row
topVerticalAlign: css`
label: topVerticalAlign;
margin-top: -${theme.spacing(0.9)};
margin-left: -${theme.spacing(0.25)};
`,
detailsOpen: css`
&:hover {
background-color: ${styleMixins.hoverColor(theme.colors.background.primary, theme)};
}
`,
errorLogRow: css`
label: erroredLogRow;
color: ${theme.colors.text.secondary};
`,
// Log Row Message
positionRelative: css`
label: positionRelative;
position: relative;
`,
rowWithContext: css`
label: rowWithContext;
z-index: 1;
outline: 9999px solid ${contextOutlineColor};
display: inherit;
`,
horizontalScroll: css`
label: horizontalScroll;
white-space: pre;
`,
contextNewline: css`
display: block;
margin-left: 0px;
`,
rowMenu: css`
display: flex;
flex-wrap: nowrap;
flex-direction: row;
align-content: flex-end;
justify-content: space-evenly;
align-items: center;
position: absolute;
top: 0;
bottom: auto;
height: ${theme.spacing(4.5)};
background: ${theme.colors.background.primary};
box-shadow: ${theme.shadows.z3};
padding: ${theme.spacing(0, 0, 0, 0.5)};
z-index: 100;
visibility: hidden;
width: ${theme.spacing(5)};
`,
rowMenuWithContextButton: css`
width: ${theme.spacing(10)};
`,
logRowMenuCell: css`
position: absolute;
margin-top: -${theme.spacing(0.125)};
`,
logRowMenuCellDefaultPosition: css`
right: 40px;
`,
logRowMenuCellExplore: css`
right: calc(115px + ${theme.spacing(1)});
`,
logRowMenuCellExploreWithContextButton: css`
right: calc(155px + ${theme.spacing(1)});
`,
logLine: css`
background-color: transparent;
border: none;
diplay: inline;
font-family: ${theme.typography.fontFamilyMonospace};
font-size: ${theme.typography.bodySmall.fontSize};
letter-spacing: ${theme.typography.bodySmall.letterSpacing};
text-align: left;
padding: 0;
user-select: text;
`,
}; };
}; };
export type LogRowStyles = ReturnType<typeof getLogRowStyles>;

Loading…
Cancel
Save