import { css, cx } from '@emotion/css'; import React, { PureComponent } from 'react'; import { CoreApp, DataFrame, Field, GrafanaTheme2, LinkModel, LogRowModel } from '@grafana/data'; import { Themeable2, withTheme2 } from '@grafana/ui'; import { calculateLogsLabelStats, calculateStats } from '../utils'; import { LogDetailsRow } from './LogDetailsRow'; import { getLogLevelStyles, getLogRowStyles } from './getLogRowStyles'; import { getAllFields } from './logParser'; export interface Props extends Themeable2 { row: LogRowModel; showDuplicates: boolean; getRows: () => LogRowModel[]; wrapLogMessage: boolean; className?: string; hasError?: boolean; app?: CoreApp; onClickFilterLabel?: (key: string, value: string) => void; onClickFilterOutLabel?: (key: string, value: string) => void; getFieldLinks?: (field: Field, rowIndex: number, dataFrame: DataFrame) => Array>; displayedFields?: string[]; onClickShowField?: (key: string) => void; onClickHideField?: (key: string) => void; } const getStyles = (theme: GrafanaTheme2) => { return { logsRowLevelDetails: css` label: logs-row__level_details; &::after { top: -3px; } `, logDetails: css` label: logDetailsDefaultCursor; cursor: default; &:hover { background-color: ${theme.colors.background.primary}; } `, }; }; class UnThemedLogDetails extends PureComponent { render() { const { app, row, theme, hasError, onClickFilterOutLabel, onClickFilterLabel, getRows, showDuplicates, className, onClickShowField, onClickHideField, displayedFields, getFieldLinks, wrapLogMessage, } = this.props; const rowStyles = getLogRowStyles(theme); const levelStyles = getLogLevelStyles(theme, row.logLevel); const styles = getStyles(theme); const labels = row.labels ? row.labels : {}; const labelsAvailable = Object.keys(labels).length > 0; const fieldsAndLinks = getAllFields(row, getFieldLinks); const links = fieldsAndLinks.filter((f) => f.links?.length).sort(); const fields = fieldsAndLinks.filter((f) => f.links?.length === 0).sort(); const fieldsAvailable = fields && fields.length > 0; const linksAvailable = links && links.length > 0; // If logs with error, we are not showing the level color const levelClassName = hasError ? '' : `${levelStyles.logsRowLevelColor} ${rowStyles.logsRowLevel} ${styles.logsRowLevelDetails}`; return ( {showDuplicates && }
{(labelsAvailable || fieldsAvailable) && ( )} {Object.keys(labels) .sort() .map((key) => { const value = labels[key]; return ( calculateLogsLabelStats(getRows(), key)} onClickFilterOutLabel={onClickFilterOutLabel} onClickFilterLabel={onClickFilterLabel} onClickShowField={onClickShowField} onClickHideField={onClickHideField} row={row} app={app} wrapLogMessage={wrapLogMessage} displayedFields={displayedFields} /> ); })} {fields.map((field) => { const { key, value, fieldIndex } = field; return ( calculateStats(row.dataFrame.fields[fieldIndex].values.toArray())} displayedFields={displayedFields} wrapLogMessage={wrapLogMessage} row={row} app={app} /> ); })} {linksAvailable && ( )} {links.map((field) => { const { key, value, links, fieldIndex } = field; return ( calculateStats(row.dataFrame.fields[fieldIndex].values.toArray())} displayedFields={displayedFields} wrapLogMessage={wrapLogMessage} row={row} app={app} /> ); })} {!fieldsAvailable && !labelsAvailable && !linksAvailable && ( )}
Fields
Links
No details available
); } } export const LogDetails = withTheme2(UnThemedLogDetails); LogDetails.displayName = 'LogDetails';