Log Line Details: Header options and inline icons improvements (#114479)
* LogLineDetailsHeader: introduce divider * LogLineDetails: improve icons spacing * useKeyBindings: close sidebar details with escape
This commit is contained in:
@@ -267,54 +267,56 @@ export const LogLineDetailsField = ({
|
||||
<div className={styles.row}>
|
||||
{!disableActions && (
|
||||
<div className={styles.actions}>
|
||||
{onClickFilterLabel && fieldSupportsFilters && (
|
||||
<AsyncIconButton
|
||||
name="search-plus"
|
||||
onClick={filterLabel}
|
||||
// We purposely want to pass a new function on every render to allow the active state to be updated when log details remains open between updates.
|
||||
isActive={labelFilterActive}
|
||||
tooltipSuffix={refIdTooltip}
|
||||
/>
|
||||
)}
|
||||
{onClickFilterOutLabel && fieldSupportsFilters && (
|
||||
<div className={styles.actionIcons}>
|
||||
{onClickFilterLabel && fieldSupportsFilters && (
|
||||
<AsyncIconButton
|
||||
name="search-plus"
|
||||
onClick={filterLabel}
|
||||
// We purposely want to pass a new function on every render to allow the active state to be updated when log details remains open between updates.
|
||||
isActive={labelFilterActive}
|
||||
tooltipSuffix={refIdTooltip}
|
||||
/>
|
||||
)}
|
||||
{onClickFilterOutLabel && fieldSupportsFilters && (
|
||||
<IconButton
|
||||
name="search-minus"
|
||||
tooltip={
|
||||
app === CoreApp.Explore && log.dataFrame?.refId
|
||||
? t('logs.log-line-details.fields.filter-out-query', 'Filter out value in query {{query}}', {
|
||||
query: log.dataFrame?.refId,
|
||||
})
|
||||
: t('logs.log-line-details.fields.filter-out', 'Filter out value')
|
||||
}
|
||||
onClick={filterOutLabel}
|
||||
/>
|
||||
)}
|
||||
{singleKey && displayedFields.includes(keys[0]) && (
|
||||
<IconButton
|
||||
variant="primary"
|
||||
tooltip={t('logs.log-line-details.fields.toggle-field-button.hide-this-field', 'Hide this field')}
|
||||
name="eye"
|
||||
onClick={hideField}
|
||||
/>
|
||||
)}
|
||||
{singleKey && !displayedFields.includes(keys[0]) && (
|
||||
<IconButton
|
||||
tooltip={t(
|
||||
'logs.log-line-details.fields.toggle-field-button.field-instead-message',
|
||||
'Show this field instead of the message'
|
||||
)}
|
||||
name="eye"
|
||||
onClick={showField}
|
||||
/>
|
||||
)}
|
||||
<IconButton
|
||||
name="search-minus"
|
||||
tooltip={
|
||||
app === CoreApp.Explore && log.dataFrame?.refId
|
||||
? t('logs.log-line-details.fields.filter-out-query', 'Filter out value in query {{query}}', {
|
||||
query: log.dataFrame?.refId,
|
||||
})
|
||||
: t('logs.log-line-details.fields.filter-out', 'Filter out value')
|
||||
}
|
||||
onClick={filterOutLabel}
|
||||
variant={showFieldsStats ? 'primary' : 'secondary'}
|
||||
name="signal"
|
||||
tooltip={t('logs.log-line-details.fields.adhoc-statistics', 'Ad-hoc statistics')}
|
||||
className={styles.statsIcon}
|
||||
disabled={!singleKey}
|
||||
onClick={showStats}
|
||||
/>
|
||||
)}
|
||||
{singleKey && displayedFields.includes(keys[0]) && (
|
||||
<IconButton
|
||||
variant="primary"
|
||||
tooltip={t('logs.log-line-details.fields.toggle-field-button.hide-this-field', 'Hide this field')}
|
||||
name="eye"
|
||||
onClick={hideField}
|
||||
/>
|
||||
)}
|
||||
{singleKey && !displayedFields.includes(keys[0]) && (
|
||||
<IconButton
|
||||
tooltip={t(
|
||||
'logs.log-line-details.fields.toggle-field-button.field-instead-message',
|
||||
'Show this field instead of the message'
|
||||
)}
|
||||
name="eye"
|
||||
onClick={showField}
|
||||
/>
|
||||
)}
|
||||
<IconButton
|
||||
variant={showFieldsStats ? 'primary' : 'secondary'}
|
||||
name="signal"
|
||||
tooltip={t('logs.log-line-details.fields.adhoc-statistics', 'Ad-hoc statistics')}
|
||||
className="stats-button"
|
||||
disabled={!singleKey}
|
||||
onClick={showStats}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className={styles.label}>
|
||||
@@ -388,6 +390,15 @@ const getFieldStyles = (theme: GrafanaTheme2) => ({
|
||||
actions: css({
|
||||
whiteSpace: 'nowrap',
|
||||
}),
|
||||
actionIcons: css({
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
paddingRight: 2,
|
||||
}),
|
||||
statsIcon: css({
|
||||
margin: 0,
|
||||
paddingRight: 4,
|
||||
}),
|
||||
label: css({
|
||||
paddingRight: theme.spacing(1),
|
||||
overflowWrap: 'break-word',
|
||||
|
||||
@@ -235,6 +235,7 @@ export const LogLineDetailsHeader = ({ focusLogLine, log, search, onSearch }: Pr
|
||||
tabIndex={0}
|
||||
/>
|
||||
)}
|
||||
<div className={`${styles.divider} ${styles.dividerMargin}`} />
|
||||
<IconButton
|
||||
name={detailsMode === 'inline' ? 'web-section' : 'gf-layout-simple'}
|
||||
tooltip={
|
||||
@@ -244,9 +245,11 @@ export const LogLineDetailsHeader = ({ focusLogLine, log, search, onSearch }: Pr
|
||||
}
|
||||
onClick={toggleDetailsMode}
|
||||
/>
|
||||
<div className={styles.divider} />
|
||||
<IconButton
|
||||
name="times"
|
||||
tooltip={t('logs.log-line-details.close', 'Close log details')}
|
||||
variant="primary"
|
||||
onClick={closeDetails}
|
||||
/>
|
||||
</div>
|
||||
@@ -280,6 +283,7 @@ const getStyles = (theme: GrafanaTheme2, mode: LogLineDetailsMode, wrapLogMessag
|
||||
display: 'flex',
|
||||
gap: theme.spacing(1),
|
||||
paddingLeft: theme.spacing(1),
|
||||
alignContent: 'center',
|
||||
}),
|
||||
copyLogButton: css({
|
||||
padding: 0,
|
||||
@@ -293,4 +297,12 @@ const getStyles = (theme: GrafanaTheme2, mode: LogLineDetailsMode, wrapLogMessag
|
||||
componentWrapper: css({
|
||||
padding: theme.spacing(0, 1, 1, 1),
|
||||
}),
|
||||
divider: css({
|
||||
width: 1,
|
||||
borderRight: `solid 1px ${theme.colors.border.medium}`,
|
||||
height: theme.spacing(2.25),
|
||||
}),
|
||||
dividerMargin: css({
|
||||
marginRight: theme.spacing(0.5),
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { useLogDetailsContext } from './LogDetailsContext';
|
||||
import { useLogListSearchContext } from './LogListSearchContext';
|
||||
|
||||
/**
|
||||
@@ -11,6 +12,7 @@ import { useLogListSearchContext } from './LogListSearchContext';
|
||||
|
||||
export const useKeyBindings = () => {
|
||||
const { hideSearch, searchVisible, showSearch } = useLogListSearchContext();
|
||||
const { showDetails, detailsMode, closeDetails } = useLogDetailsContext();
|
||||
|
||||
useEffect(() => {
|
||||
function handleToggleSearch(event: KeyboardEvent) {
|
||||
@@ -24,10 +26,13 @@ export const useKeyBindings = () => {
|
||||
if (event.key === 'Escape' && searchVisible) {
|
||||
hideSearch();
|
||||
}
|
||||
if (event.key === 'Escape' && showDetails.length > 0 && detailsMode === 'sidebar') {
|
||||
closeDetails();
|
||||
}
|
||||
}
|
||||
document.addEventListener('keydown', handleToggleSearch);
|
||||
return () => {
|
||||
document.removeEventListener('keydown', handleToggleSearch);
|
||||
};
|
||||
});
|
||||
}, [closeDetails, detailsMode, hideSearch, searchVisible, showDetails.length, showSearch]);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user