From bde8a1b2e1d2e526f676210b4c4542bf9abe0c9c Mon Sep 17 00:00:00 2001 From: Sven Grossmann Date: Thu, 29 Sep 2022 11:50:22 +0200 Subject: [PATCH] Logs: Show copy button independently from context (#55934) (#55993) (cherry picked from commit 998a368c69843c23ea51b2ab747a4556e8f9d32a) --- public/app/features/explore/Logs.tsx | 2 + .../app/features/logs/components/LogRow.tsx | 9 +++++ .../logs/components/LogRowMessage.tsx | 37 ++++++++++--------- .../app/features/logs/components/LogRows.tsx | 34 ++++++++++++++++- .../logs/components/getLogRowStyles.ts | 13 +------ public/app/plugins/panel/logs/LogsPanel.tsx | 2 + 6 files changed, 66 insertions(+), 31 deletions(-) diff --git a/public/app/features/explore/Logs.tsx b/public/app/features/explore/Logs.tsx index 55f6c387cb5..8b7215d33e7 100644 --- a/public/app/features/explore/Logs.tsx +++ b/public/app/features/explore/Logs.tsx @@ -22,6 +22,7 @@ import { LoadingState, SplitOpen, DataQueryResponse, + CoreApp, } from '@grafana/data'; import { reportInteraction } from '@grafana/runtime'; import { @@ -455,6 +456,7 @@ class UnthemedLogs extends PureComponent { showDetectedFields={showDetectedFields} onClickShowDetectedField={this.showDetectedField} onClickHideDetectedField={this.hideDetectedField} + app={CoreApp.Explore} /> LogRowModel[]; onClickFilterLabel?: (key: string, value: string) => void; onClickFilterOutLabel?: (key: string, value: string) => void; @@ -52,6 +55,7 @@ interface Props extends Themeable2 { onClickShowDetectedField?: (key: string) => void; onClickHideDetectedField?: (key: string) => void; onLogRowHover?: (row?: LogRowModel) => void; + toggleContextIsOpen?: () => void; } interface State { @@ -91,6 +95,7 @@ class UnThemedLogRow extends PureComponent { }; toggleContext = () => { + this.props.toggleContextIsOpen?.(); this.setState((state) => { return { showContext: !state.showContext, @@ -131,6 +136,7 @@ class UnThemedLogRow extends PureComponent { row, showDuplicates, showContextToggle, + showRowMenu, showLabels, showTime, showDetectedFields, @@ -140,6 +146,7 @@ class UnThemedLogRow extends PureComponent { getFieldLinks, forceEscape, onLogRowHover, + app, } = this.props; const { showDetails, showContext } = this.state; const style = getLogRowStyles(theme, row.logLevel); @@ -206,9 +213,11 @@ class UnThemedLogRow extends PureComponent { context={context} contextIsOpen={showContext} showContextToggle={showContextToggle} + showRowMenu={showRowMenu} wrapLogMessage={wrapLogMessage} prettifyLogMessage={prettifyLogMessage} onToggleContext={this.toggleContext} + app={app} /> )} diff --git a/public/app/features/logs/components/LogRowMessage.tsx b/public/app/features/logs/components/LogRowMessage.tsx index 9f6f1275c12..fe8d76ee6ed 100644 --- a/public/app/features/logs/components/LogRowMessage.tsx +++ b/public/app/features/logs/components/LogRowMessage.tsx @@ -4,7 +4,7 @@ import React, { PureComponent } from 'react'; import Highlighter from 'react-highlight-words'; import tinycolor from 'tinycolor2'; -import { LogRowModel, findHighlightChunksInText, GrafanaTheme2 } from '@grafana/data'; +import { LogRowModel, findHighlightChunksInText, GrafanaTheme2, CoreApp } from '@grafana/data'; import { withTheme2, Themeable2, IconButton, Tooltip } from '@grafana/ui'; import { LogMessageAnsi } from './LogMessageAnsi'; @@ -12,8 +12,6 @@ import { LogRowContext } from './LogRowContext'; import { LogRowContextQueryErrors, HasMoreContextRows, LogRowContextRows } from './LogRowContextProvider'; import { getLogRowStyles } from './getLogRowStyles'; -//Components - export const MAX_CHARACTERS = 100000; interface Props extends Themeable2 { @@ -24,13 +22,15 @@ interface Props extends Themeable2 { prettifyLogMessage: boolean; errors?: LogRowContextQueryErrors; context?: LogRowContextRows; + showRowMenu?: boolean; + app?: CoreApp; showContextToggle?: (row?: LogRowModel) => boolean; getRows: () => LogRowModel[]; onToggleContext: () => void; updateLimit?: () => void; } -const getStyles = (theme: GrafanaTheme2) => { +const getStyles = (theme: GrafanaTheme2, showContextButton: boolean, isInDashboard: boolean | undefined) => { const outlineColor = tinycolor(theme.components.dashboard.background).setAlpha(0.7).toRgbString(); return { @@ -51,7 +51,7 @@ const getStyles = (theme: GrafanaTheme2) => { display: block; margin-left: 0px; `, - contextButton: css` + rowMenu: css` display: flex; flex-wrap: nowrap; flex-direction: row; @@ -59,15 +59,16 @@ const getStyles = (theme: GrafanaTheme2) => { justify-content: space-evenly; align-items: center; position: absolute; - right: -8px; + right: ${isInDashboard ? '0px' : '-8px'}; top: 0; bottom: auto; - width: 80px; height: 36px; 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 ? '80px' : '40px'}; `, }; }; @@ -124,16 +125,19 @@ class UnThemedLogRowMessage extends PureComponent { updateLimit, context, contextIsOpen, - showContextToggle, + showRowMenu, wrapLogMessage, prettifyLogMessage, onToggleContext, + app, + showContextToggle, } = this.props; const style = getLogRowStyles(theme, row.logLevel); const { hasAnsi, raw } = row; const restructuredEntry = restructureLog(raw, prettifyLogMessage); - const styles = getStyles(theme); + const shouldShowContextToggle = showContextToggle ? showContextToggle(row) : false; + const styles = getStyles(theme, shouldShowContextToggle, app === CoreApp.Dashboard); return ( // When context is open, the position has to be NOT relative. @@ -160,14 +164,13 @@ class UnThemedLogRowMessage extends PureComponent { {renderLogMessage(hasAnsi, restructuredEntry, row.searchWords, style.logsRowMatchHighLight)} - {!contextIsOpen && showContextToggle?.(row) && ( - e.stopPropagation()} - > - - - + {showRowMenu && ( + e.stopPropagation()}> + {shouldShowContextToggle && ( + + + + )} boolean; onClickFilterLabel?: (key: string, value: string) => void; onClickFilterOutLabel?: (key: string, value: string) => void; @@ -37,6 +47,7 @@ export interface Props extends Themeable2 { interface State { renderAll: boolean; + contextIsOpen: boolean; } class UnThemedLogRows extends PureComponent { @@ -48,6 +59,18 @@ class UnThemedLogRows extends PureComponent { state: State = { renderAll: false, + contextIsOpen: false, + }; + + /** + * Toggle the `contextIsOpen` state when a context of one LogRow is opened in order to not show the menu of the other log rows. + */ + toggleContextIsOpen = (): void => { + this.setState((state) => { + return { + contextIsOpen: !state.contextIsOpen, + }; + }); }; componentDidMount() { @@ -100,8 +123,9 @@ class UnThemedLogRows extends PureComponent { onClickHideDetectedField, forceEscape, onLogRowHover, + app, } = this.props; - const { renderAll } = this.state; + const { renderAll, contextIsOpen } = this.state; const { logsRowsTable } = getLogRowStyles(theme); const dedupedRows = deduplicatedRows ? deduplicatedRows : logRows; const hasData = logRows && logRows.length > 0; @@ -130,6 +154,7 @@ class UnThemedLogRows extends PureComponent { getRowContext={getRowContext} row={row} showContextToggle={showContextToggle} + showRowMenu={!contextIsOpen} showDuplicates={showDuplicates} showLabels={showLabels} showTime={showTime} @@ -145,7 +170,9 @@ class UnThemedLogRows extends PureComponent { getFieldLinks={getFieldLinks} logsSortOrder={logsSortOrder} forceEscape={forceEscape} + toggleContextIsOpen={this.toggleContextIsOpen} onLogRowHover={onLogRowHover} + app={app} /> ))} {hasData && @@ -157,6 +184,7 @@ class UnThemedLogRows extends PureComponent { getRowContext={getRowContext} row={row} showContextToggle={showContextToggle} + showRowMenu={!contextIsOpen} showDuplicates={showDuplicates} showLabels={showLabels} showTime={showTime} @@ -172,7 +200,9 @@ class UnThemedLogRows extends PureComponent { getFieldLinks={getFieldLinks} logsSortOrder={logsSortOrder} forceEscape={forceEscape} + toggleContextIsOpen={this.toggleContextIsOpen} onLogRowHover={onLogRowHover} + app={app} /> ))} {hasData && !renderAll && ( diff --git a/public/app/features/logs/components/getLogRowStyles.ts b/public/app/features/logs/components/getLogRowStyles.ts index eccdc8bb892..b6a2b734bd0 100644 --- a/public/app/features/logs/components/getLogRowStyles.ts +++ b/public/app/features/logs/components/getLogRowStyles.ts @@ -45,13 +45,6 @@ export const getLogRowStyles = (theme: GrafanaTheme2, logLevel?: LogLevel) => { font-size: ${theme.typography.bodySmall.fontSize}; width: 100%; `, - context: css` - label: context; - visibility: hidden; - white-space: nowrap; - position: relative; - margin-left: 10px; - `, logsRow: css` label: logs-row; width: 100%; @@ -59,13 +52,9 @@ export const getLogRowStyles = (theme: GrafanaTheme2, logLevel?: LogLevel) => { vertical-align: top; &:hover { - .log-row-context { + .log-row-menu { visibility: visible; z-index: 1; - text-decoration: underline; - &:hover { - color: ${theme.colors.warning.main}; - } } } diff --git a/public/app/plugins/panel/logs/LogsPanel.tsx b/public/app/plugins/panel/logs/LogsPanel.tsx index 8ec083829ea..0a970f00f26 100644 --- a/public/app/plugins/panel/logs/LogsPanel.tsx +++ b/public/app/plugins/panel/logs/LogsPanel.tsx @@ -10,6 +10,7 @@ import { LogRowModel, DataHoverClearEvent, DataHoverEvent, + CoreApp, } from '@grafana/data'; import { CustomScrollbar, useStyles2, usePanelContext } from '@grafana/ui'; import { dataFrameToLogsModel, dedupLogRows, COMMON_LABELS } from 'app/core/logsModel'; @@ -116,6 +117,7 @@ export const LogsPanel: React.FunctionComponent = ({ enableLogDetails={enableLogDetails} previewLimit={isAscending ? logRows.length : undefined} onLogRowHover={onLogRowHover} + app={CoreApp.Dashboard} /> {showCommonLabels && isAscending && renderCommonLabels()}