mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Logs: Added support to disable and re-enable the popover menu (#98254)
* PopoverMenu: add disable menu item * PopoverMenu: disable and reenable with shift * Style confirmation dialog * Update unit tests and add tracking * PopoverMenu: i18n * Translations * Update tracking property * Use alt+select to re-enable * Update betterer
This commit is contained in:
parent
df80bdeb14
commit
44e65c5bc9
@ -4335,11 +4335,6 @@ exports[`better eslint`] = {
|
|||||||
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "5"],
|
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "5"],
|
||||||
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "6"]
|
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "6"]
|
||||||
],
|
],
|
||||||
"public/app/features/explore/Logs/PopoverMenu.tsx:5381": [
|
|
||||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"],
|
|
||||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "1"],
|
|
||||||
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "2"]
|
|
||||||
],
|
|
||||||
"public/app/features/explore/MetaInfoText.tsx:5381": [
|
"public/app/features/explore/MetaInfoText.tsx:5381": [
|
||||||
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
|
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
|
||||||
],
|
],
|
||||||
|
@ -8,7 +8,7 @@ import { PopoverMenu } from './PopoverMenu';
|
|||||||
const row = createLogRow();
|
const row = createLogRow();
|
||||||
|
|
||||||
test('Does not render if the filter functions are not defined', () => {
|
test('Does not render if the filter functions are not defined', () => {
|
||||||
render(<PopoverMenu selection="test" x={0} y={0} row={row} close={() => {}} />);
|
render(<PopoverMenu selection="test" x={0} y={0} row={row} close={() => {}} onDisable={() => {}} />);
|
||||||
|
|
||||||
expect(screen.queryByText('Copy selection')).not.toBeInTheDocument();
|
expect(screen.queryByText('Copy selection')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
@ -16,7 +16,15 @@ test('Does not render if the filter functions are not defined', () => {
|
|||||||
test('Renders copy and line contains filter', async () => {
|
test('Renders copy and line contains filter', async () => {
|
||||||
const onClickFilterString = jest.fn();
|
const onClickFilterString = jest.fn();
|
||||||
render(
|
render(
|
||||||
<PopoverMenu selection="test" x={0} y={0} row={row} close={() => {}} onClickFilterString={onClickFilterString} />
|
<PopoverMenu
|
||||||
|
selection="test"
|
||||||
|
x={0}
|
||||||
|
y={0}
|
||||||
|
row={row}
|
||||||
|
close={() => {}}
|
||||||
|
onDisable={() => {}}
|
||||||
|
onClickFilterString={onClickFilterString}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(screen.getByText('Copy selection')).toBeInTheDocument();
|
expect(screen.getByText('Copy selection')).toBeInTheDocument();
|
||||||
@ -37,6 +45,7 @@ test('Renders copy and line does not contain filter', async () => {
|
|||||||
y={0}
|
y={0}
|
||||||
row={row}
|
row={row}
|
||||||
close={() => {}}
|
close={() => {}}
|
||||||
|
onDisable={() => {}}
|
||||||
onClickFilterOutString={onClickFilterOutString}
|
onClickFilterOutString={onClickFilterOutString}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -58,6 +67,7 @@ test('Renders copy, line contains filter, and line does not contain filter', ()
|
|||||||
y={0}
|
y={0}
|
||||||
row={row}
|
row={row}
|
||||||
close={() => {}}
|
close={() => {}}
|
||||||
|
onDisable={() => {}}
|
||||||
onClickFilterString={() => {}}
|
onClickFilterString={() => {}}
|
||||||
onClickFilterOutString={() => {}}
|
onClickFilterOutString={() => {}}
|
||||||
/>
|
/>
|
||||||
@ -77,6 +87,7 @@ test('Can be dismissed with escape', async () => {
|
|||||||
y={0}
|
y={0}
|
||||||
row={row}
|
row={row}
|
||||||
close={close}
|
close={close}
|
||||||
|
onDisable={() => {}}
|
||||||
onClickFilterString={() => {}}
|
onClickFilterString={() => {}}
|
||||||
onClickFilterOutString={() => {}}
|
onClickFilterOutString={() => {}}
|
||||||
/>
|
/>
|
||||||
@ -87,3 +98,24 @@ test('Can be dismissed with escape', async () => {
|
|||||||
await userEvent.keyboard('{Escape}');
|
await userEvent.keyboard('{Escape}');
|
||||||
expect(close).toHaveBeenCalledTimes(1);
|
expect(close).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Can be disabled', async () => {
|
||||||
|
const onDisable = jest.fn();
|
||||||
|
render(
|
||||||
|
<PopoverMenu
|
||||||
|
selection="test"
|
||||||
|
x={0}
|
||||||
|
y={0}
|
||||||
|
row={row}
|
||||||
|
close={() => {}}
|
||||||
|
onDisable={onDisable}
|
||||||
|
onClickFilterString={() => {}}
|
||||||
|
onClickFilterOutString={() => {}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(onDisable).not.toHaveBeenCalled();
|
||||||
|
expect(screen.getByText('Disable menu')).toBeInTheDocument();
|
||||||
|
await userEvent.click(screen.getByText('Disable menu'));
|
||||||
|
expect(onDisable).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import { useEffect, useRef } from 'react';
|
import { useCallback, useEffect, useRef } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2, LogRowModel } from '@grafana/data';
|
import { GrafanaTheme2, LogRowModel } from '@grafana/data';
|
||||||
import { reportInteraction } from '@grafana/runtime';
|
import { reportInteraction } from '@grafana/runtime';
|
||||||
import { Menu, useStyles2 } from '@grafana/ui';
|
import { Menu, useStyles2 } from '@grafana/ui';
|
||||||
|
import { t } from 'app/core/internationalization';
|
||||||
|
|
||||||
import { copyText } from '../../logs/utils';
|
import { copyText } from '../../logs/utils';
|
||||||
|
|
||||||
@ -13,6 +14,7 @@ interface PopoverMenuProps {
|
|||||||
y: number;
|
y: number;
|
||||||
onClickFilterString?: (value: string, refId?: string) => void;
|
onClickFilterString?: (value: string, refId?: string) => void;
|
||||||
onClickFilterOutString?: (value: string, refId?: string) => void;
|
onClickFilterOutString?: (value: string, refId?: string) => void;
|
||||||
|
onDisable: () => void;
|
||||||
row: LogRowModel;
|
row: LogRowModel;
|
||||||
close: () => void;
|
close: () => void;
|
||||||
}
|
}
|
||||||
@ -25,6 +27,7 @@ export const PopoverMenu = ({
|
|||||||
selection,
|
selection,
|
||||||
row,
|
row,
|
||||||
close,
|
close,
|
||||||
|
...props
|
||||||
}: PopoverMenuProps) => {
|
}: PopoverMenuProps) => {
|
||||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||||
const styles = useStyles2(getStyles);
|
const styles = useStyles2(getStyles);
|
||||||
@ -42,6 +45,11 @@ export const PopoverMenu = ({
|
|||||||
};
|
};
|
||||||
}, [close]);
|
}, [close]);
|
||||||
|
|
||||||
|
const onDisable = useCallback(() => {
|
||||||
|
track('popover_menu_disabled', selection.length, row.datasourceType);
|
||||||
|
props.onDisable();
|
||||||
|
}, [props, row.datasourceType, selection.length]);
|
||||||
|
|
||||||
const supported = onClickFilterString || onClickFilterOutString;
|
const supported = onClickFilterString || onClickFilterOutString;
|
||||||
|
|
||||||
if (!supported) {
|
if (!supported) {
|
||||||
@ -49,38 +57,42 @@ export const PopoverMenu = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.menu} style={{ top: y, left: x }}>
|
<>
|
||||||
<Menu ref={containerRef}>
|
<div className={styles.menu} style={{ top: y, left: x }}>
|
||||||
<Menu.Item
|
<Menu ref={containerRef}>
|
||||||
label="Copy selection"
|
|
||||||
onClick={() => {
|
|
||||||
copyText(selection, containerRef);
|
|
||||||
close();
|
|
||||||
track('copy', selection.length, row.datasourceType);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{onClickFilterString && (
|
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
label="Add as line contains filter"
|
label={t('logs.popover-menu.copy', 'Copy selection')}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onClickFilterString(selection, row.dataFrame.refId);
|
copyText(selection, containerRef);
|
||||||
close();
|
close();
|
||||||
track('line_contains', selection.length, row.datasourceType);
|
track('copy', selection.length, row.datasourceType);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
{onClickFilterString && (
|
||||||
{onClickFilterOutString && (
|
<Menu.Item
|
||||||
<Menu.Item
|
label={t('logs.popover-menu.line-contains', 'Add as line contains filter')}
|
||||||
label="Add as line does not contain filter"
|
onClick={() => {
|
||||||
onClick={() => {
|
onClickFilterString(selection, row.dataFrame.refId);
|
||||||
onClickFilterOutString(selection, row.dataFrame.refId);
|
close();
|
||||||
close();
|
track('line_contains', selection.length, row.datasourceType);
|
||||||
track('line_does_not_contain', selection.length, row.datasourceType);
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
)}
|
||||||
)}
|
{onClickFilterOutString && (
|
||||||
</Menu>
|
<Menu.Item
|
||||||
</div>
|
label={t('logs.popover-menu.line-contains-not', 'Add as line does not contain filter')}
|
||||||
|
onClick={() => {
|
||||||
|
onClickFilterOutString(selection, row.dataFrame.refId);
|
||||||
|
close();
|
||||||
|
track('line_does_not_contain', selection.length, row.datasourceType);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Menu.Divider />
|
||||||
|
<Menu.Item label={t('logs.popover-menu.disable-menu', 'Disable menu')} onClick={onDisable} />
|
||||||
|
</Menu>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,9 +3,18 @@ import userEvent from '@testing-library/user-event';
|
|||||||
|
|
||||||
import { LogRowModel, LogsDedupStrategy, LogsSortOrder } from '@grafana/data';
|
import { LogRowModel, LogsDedupStrategy, LogsSortOrder } from '@grafana/data';
|
||||||
|
|
||||||
|
import { disablePopoverMenu, enablePopoverMenu, isPopoverMenuDisabled } from '../utils';
|
||||||
|
|
||||||
import { LogRows, Props } from './LogRows';
|
import { LogRows, Props } from './LogRows';
|
||||||
import { createLogRow } from './__mocks__/logRow';
|
import { createLogRow } from './__mocks__/logRow';
|
||||||
|
|
||||||
|
jest.mock('../utils', () => ({
|
||||||
|
...jest.requireActual('../utils'),
|
||||||
|
isPopoverMenuDisabled: jest.fn(),
|
||||||
|
disablePopoverMenu: jest.fn(),
|
||||||
|
enablePopoverMenu: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
jest.mock('@grafana/runtime', () => ({
|
jest.mock('@grafana/runtime', () => ({
|
||||||
...jest.requireActual('@grafana/runtime'),
|
...jest.requireActual('@grafana/runtime'),
|
||||||
config: {
|
config: {
|
||||||
@ -155,6 +164,9 @@ describe('Popover menu', () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
let orgGetSelection: () => Selection | null;
|
let orgGetSelection: () => Selection | null;
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.mocked(isPopoverMenuDisabled).mockReturnValue(false);
|
||||||
|
});
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
orgGetSelection = document.getSelection;
|
orgGetSelection = document.getSelection;
|
||||||
jest.spyOn(document, 'getSelection').mockReturnValue({
|
jest.spyOn(document, 'getSelection').mockReturnValue({
|
||||||
@ -177,6 +189,27 @@ describe('Popover menu', () => {
|
|||||||
expect(screen.getByText('Add as line contains filter')).toBeInTheDocument();
|
expect(screen.getByText('Add as line contains filter')).toBeInTheDocument();
|
||||||
expect(screen.getByText('Add as line does not contain filter')).toBeInTheDocument();
|
expect(screen.getByText('Add as line does not contain filter')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
it('Can be disabled', async () => {
|
||||||
|
setup();
|
||||||
|
await userEvent.click(screen.getByText('log message 1'));
|
||||||
|
await userEvent.click(screen.getByText('Disable menu'));
|
||||||
|
await userEvent.click(screen.getByText('Confirm'));
|
||||||
|
expect(disablePopoverMenu).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
it('Does not appear when disabled', async () => {
|
||||||
|
jest.mocked(isPopoverMenuDisabled).mockReturnValue(true);
|
||||||
|
setup();
|
||||||
|
await userEvent.click(screen.getByText('log message 1'));
|
||||||
|
expect(screen.queryByText('Copy selection')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
it('Can be re-enabled', async () => {
|
||||||
|
jest.mocked(isPopoverMenuDisabled).mockReturnValue(true);
|
||||||
|
const user = userEvent.setup();
|
||||||
|
setup();
|
||||||
|
await user.keyboard('[AltLeft>]'); // Press Alt (without releasing it)
|
||||||
|
await user.click(screen.getByText('log message 1'));
|
||||||
|
expect(enablePopoverMenu).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
it('Does not appear when the props are not defined', async () => {
|
it('Does not appear when the props are not defined', async () => {
|
||||||
setup({
|
setup({
|
||||||
onClickFilterOutString: undefined,
|
onClickFilterOutString: undefined,
|
||||||
|
@ -14,11 +14,12 @@ import {
|
|||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { config } from '@grafana/runtime';
|
import { config } from '@grafana/runtime';
|
||||||
import { DataQuery } from '@grafana/schema';
|
import { DataQuery } from '@grafana/schema';
|
||||||
import { PopoverContent, useTheme2 } from '@grafana/ui';
|
import { ConfirmModal, Icon, PopoverContent, useTheme2 } from '@grafana/ui';
|
||||||
|
import { t, Trans } from 'app/core/internationalization';
|
||||||
|
|
||||||
import { PopoverMenu } from '../../explore/Logs/PopoverMenu';
|
import { PopoverMenu } from '../../explore/Logs/PopoverMenu';
|
||||||
import { UniqueKeyMaker } from '../UniqueKeyMaker';
|
import { UniqueKeyMaker } from '../UniqueKeyMaker';
|
||||||
import { sortLogRows, targetIsElement } from '../utils';
|
import { disablePopoverMenu, enablePopoverMenu, isPopoverMenuDisabled, sortLogRows, targetIsElement } from '../utils';
|
||||||
|
|
||||||
//Components
|
//Components
|
||||||
import { LogRow } from './LogRow';
|
import { LogRow } from './LogRow';
|
||||||
@ -112,6 +113,7 @@ export const LogRows = memo(
|
|||||||
selectedRow: null,
|
selectedRow: null,
|
||||||
popoverMenuCoordinates: { x: 0, y: 0 },
|
popoverMenuCoordinates: { x: 0, y: 0 },
|
||||||
});
|
});
|
||||||
|
const [showDisablePopoverOptions, setShowDisablePopoverOptions] = useState(false);
|
||||||
const logRowsRef = useRef<HTMLDivElement>(null);
|
const logRowsRef = useRef<HTMLDivElement>(null);
|
||||||
const theme = useTheme2();
|
const theme = useTheme2();
|
||||||
const styles = getLogRowStyles(theme);
|
const styles = getLogRowStyles(theme);
|
||||||
@ -121,7 +123,6 @@ export const LogRows = memo(
|
|||||||
[dedupedRows]
|
[dedupedRows]
|
||||||
);
|
);
|
||||||
const showDuplicates = dedupStrategy !== LogsDedupStrategy.none && dedupCount > 0;
|
const showDuplicates = dedupStrategy !== LogsDedupStrategy.none && dedupCount > 0;
|
||||||
// Staged rendering
|
|
||||||
const orderedRows = useMemo(
|
const orderedRows = useMemo(
|
||||||
() => (logsSortOrder ? sortLogRows(dedupedRows, logsSortOrder) : dedupedRows),
|
() => (logsSortOrder ? sortLogRows(dedupedRows, logsSortOrder) : dedupedRows),
|
||||||
[dedupedRows, logsSortOrder]
|
[dedupedRows, logsSortOrder]
|
||||||
@ -130,7 +131,6 @@ export const LogRows = memo(
|
|||||||
const getRows = useMemo(() => () => orderedRows, [orderedRows]);
|
const getRows = useMemo(() => () => orderedRows, [orderedRows]);
|
||||||
const handleDeselectionRef = useRef<((e: Event) => void) | null>(null);
|
const handleDeselectionRef = useRef<((e: Event) => void) | null>(null);
|
||||||
const keyMaker = new UniqueKeyMaker();
|
const keyMaker = new UniqueKeyMaker();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
@ -169,7 +169,7 @@ export const LogRows = memo(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const popoverMenuSupported = useCallback(() => {
|
const popoverMenuSupported = useCallback(() => {
|
||||||
if (!config.featureToggles.logRowsPopoverMenu) {
|
if (!config.featureToggles.logRowsPopoverMenu || isPopoverMenuDisabled()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return Boolean(onClickFilterOutString || onClickFilterString);
|
return Boolean(onClickFilterOutString || onClickFilterString);
|
||||||
@ -209,6 +209,9 @@ export const LogRows = memo(
|
|||||||
if (!selection) {
|
if (!selection) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (e.altKey) {
|
||||||
|
enablePopoverMenu();
|
||||||
|
}
|
||||||
if (popoverMenuSupported() === false) {
|
if (popoverMenuSupported() === false) {
|
||||||
// This signals onRowClick inside LogRow to skip the event because the user is selecting text
|
// This signals onRowClick inside LogRow to skip the event because the user is selecting text
|
||||||
return selection ? true : false;
|
return selection ? true : false;
|
||||||
@ -236,6 +239,19 @@ export const LogRows = memo(
|
|||||||
[handleDeselection, popoverMenuSupported]
|
[handleDeselection, popoverMenuSupported]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const onDisablePopoverMenu = useCallback(() => {
|
||||||
|
setShowDisablePopoverOptions(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onDisableCancel = useCallback(() => {
|
||||||
|
setShowDisablePopoverOptions(false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onDisableConfirm = useCallback(() => {
|
||||||
|
disablePopoverMenu();
|
||||||
|
setShowDisablePopoverOptions(false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.logRows} ref={logRowsRef}>
|
<div className={styles.logRows} ref={logRowsRef}>
|
||||||
{popoverState.selection && popoverState.selectedRow && (
|
{popoverState.selection && popoverState.selectedRow && (
|
||||||
@ -246,6 +262,29 @@ export const LogRows = memo(
|
|||||||
{...popoverState.popoverMenuCoordinates}
|
{...popoverState.popoverMenuCoordinates}
|
||||||
onClickFilterString={onClickFilterString}
|
onClickFilterString={onClickFilterString}
|
||||||
onClickFilterOutString={onClickFilterOutString}
|
onClickFilterOutString={onClickFilterOutString}
|
||||||
|
onDisable={onDisablePopoverMenu}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{showDisablePopoverOptions && (
|
||||||
|
<ConfirmModal
|
||||||
|
isOpen
|
||||||
|
title={t('logs.log-rows.disable-popover.title', 'Disable menu')}
|
||||||
|
body={
|
||||||
|
<>
|
||||||
|
<Trans i18nKey="logs.log-rows.disable-popover.message">
|
||||||
|
You are about to disable the logs filter menu. To re-enable it, select text in a log line while
|
||||||
|
holding the alt key.
|
||||||
|
</Trans>
|
||||||
|
<div className={styles.shortcut}>
|
||||||
|
<Icon name="keyboard" />
|
||||||
|
<Trans i18nKey="logs.log-rows.disable-popover-message.shortcut">alt+select to enable again</Trans>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
confirmText={t('logs.log-rows.disable-popover.confirm', 'Confirm')}
|
||||||
|
icon="exclamation-triangle"
|
||||||
|
onConfirm={onDisableConfirm}
|
||||||
|
onDismiss={onDisableCancel}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<table className={cx(styles.logsRowsTable, props.overflowingContent ? '' : styles.logsRowsTableContain)}>
|
<table className={cx(styles.logsRowsTable, props.overflowingContent ? '' : styles.logsRowsTableContain)}>
|
||||||
|
@ -72,6 +72,15 @@ export const getLogRowStyles = memoizeOne((theme: GrafanaTheme2) => {
|
|||||||
logRows: css({
|
logRows: css({
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
}),
|
}),
|
||||||
|
shortcut: css({
|
||||||
|
display: 'inline-flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: theme.spacing(1),
|
||||||
|
color: theme.colors.text.secondary,
|
||||||
|
opacity: 0.7,
|
||||||
|
fontSize: theme.typography.bodySmall.fontSize,
|
||||||
|
marginTop: theme.spacing(1),
|
||||||
|
}),
|
||||||
logsRowsTable: css({
|
logsRowsTable: css({
|
||||||
label: 'logs-rows',
|
label: 'logs-rows',
|
||||||
fontFamily: theme.typography.fontFamilyMonospace,
|
fontFamily: theme.typography.fontFamilyMonospace,
|
||||||
|
@ -373,3 +373,16 @@ function getDataSourceLabelType(labelType: string, datasourceType: string) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const POPOVER_STORAGE_KEY = 'logs.popover.disabled';
|
||||||
|
export function disablePopoverMenu() {
|
||||||
|
localStorage.setItem(POPOVER_STORAGE_KEY, 'true');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function enablePopoverMenu() {
|
||||||
|
localStorage.removeItem(POPOVER_STORAGE_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isPopoverMenuDisabled() {
|
||||||
|
return Boolean(localStorage.getItem(POPOVER_STORAGE_KEY));
|
||||||
|
}
|
||||||
|
@ -1781,6 +1781,22 @@
|
|||||||
"log-row-message": {
|
"log-row-message": {
|
||||||
"ellipsis": "… ",
|
"ellipsis": "… ",
|
||||||
"more": "more"
|
"more": "more"
|
||||||
|
},
|
||||||
|
"log-rows": {
|
||||||
|
"disable-popover": {
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"message": "You are about to disable the logs filter menu. To re-enable it, select text in a log line while holding the alt key.",
|
||||||
|
"title": "Disable menu"
|
||||||
|
},
|
||||||
|
"disable-popover-message": {
|
||||||
|
"shortcut": "alt+select to enable again"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"popover-menu": {
|
||||||
|
"copy": "Copy selection",
|
||||||
|
"disable-menu": "Disable menu",
|
||||||
|
"line-contains": "Add as line contains filter",
|
||||||
|
"line-contains-not": "Add as line does not contain filter"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"migrate-to-cloud": {
|
"migrate-to-cloud": {
|
||||||
|
@ -1781,6 +1781,22 @@
|
|||||||
"log-row-message": {
|
"log-row-message": {
|
||||||
"ellipsis": "… ",
|
"ellipsis": "… ",
|
||||||
"more": "mőřę"
|
"more": "mőřę"
|
||||||
|
},
|
||||||
|
"log-rows": {
|
||||||
|
"disable-popover": {
|
||||||
|
"confirm": "Cőʼnƒįřm",
|
||||||
|
"message": "Ÿőū äřę äþőūŧ ŧő đįşäþľę ŧĥę ľőģş ƒįľŧęř męʼnū. Ŧő řę-ęʼnäþľę įŧ, şęľęčŧ ŧęχŧ įʼn ä ľőģ ľįʼnę ŵĥįľę ĥőľđįʼnģ ŧĥę äľŧ ĸęy.",
|
||||||
|
"title": "Đįşäþľę męʼnū"
|
||||||
|
},
|
||||||
|
"disable-popover-message": {
|
||||||
|
"shortcut": "äľŧ+şęľęčŧ ŧő ęʼnäþľę äģäįʼn"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"popover-menu": {
|
||||||
|
"copy": "Cőpy şęľęčŧįőʼn",
|
||||||
|
"disable-menu": "Đįşäþľę męʼnū",
|
||||||
|
"line-contains": "Åđđ äş ľįʼnę čőʼnŧäįʼnş ƒįľŧęř",
|
||||||
|
"line-contains-not": "Åđđ äş ľįʼnę đőęş ʼnőŧ čőʼnŧäįʼn ƒįľŧęř"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"migrate-to-cloud": {
|
"migrate-to-cloud": {
|
||||||
|
Loading…
Reference in New Issue
Block a user