grafana/public/app/features/logs/components/panel/LogListControls.test.tsx

287 lines
12 KiB
TypeScript
Raw Normal View History

New Logs Panel: Add LogListControl component (#102359) * LogListNavigation: create component * LogListNavigation: make it optional * Refactor Navigation into Controls * Explore Logs: hide old panel options * LogListControls: add more controls and apply new styles * LogListControls: update width * Remove console log * LogList: wrap component in context * LogListContext: make it stateful * LogListControls: connect with context * LogListContext: sync displayed fields * LogListContext: add syntax highlighting control * LogLine: improve color with highlighting off * LogListControls: improve button styles * LogListControls: add sort order option * LogListControls: add dedup strategy * LogListContext: sync prop changes with state * LogList: add option change callback * LogListContext: sync external changes only when showControls is disabled * LogListContext: unify sync effect * LogListControls: improve buttons active css * LogListContext: add optional storage support * LogList: make syntaxHighlighting and read from store or default to true * LogsPanel: add support for new options * Generated file * Update tests * New Logs Panel: add showControls option * LogList: make eventBus optional * LogsPanel: expose syntaxHighlighting * LogsPanel: expose grammar to plugins * Remove incorrect legacy file * LogListControls: allow options change with controls enabled in panel editor * LogLine: apply no-highlighting class to ansi wrapper * LogListControls: add frontend level filtering * LogList: filter by filterLevels * LogListControls: allow filterLevels in dashboards * LogLine: update unit tests * LogLineMenu: update unit test * LogListControls: add unit test * Revert * LogList: add unit test * LogList: add onLogRowHover support * LogList: test hover events * LogsPanel: add unit test * LogLine: use theme color for errors * LogLine: minor tweak to hover state * Chore: fix test case name * LogListControls: add border * LogListControls: prevent default on wrap toggle click * LogLine: switch info and debug colors * ContentOutline + LogControls: sync displayed levels and minor outline improvements * LogListContext: sync with external filterLevel changes * Logs: work with arrays of LogLevel and not plain strings * Fix type * LogListControl: increase controls size
2025-04-04 20:53:12 +08:00
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { CoreApp, EventBusSrv, LogLevel, LogsDedupStrategy, LogsSortOrder } from '@grafana/data';
import { downloadLogs } from '../../utils';
import { createLogRow } from '../__mocks__/logRow';
New Logs Panel: Add LogListControl component (#102359) * LogListNavigation: create component * LogListNavigation: make it optional * Refactor Navigation into Controls * Explore Logs: hide old panel options * LogListControls: add more controls and apply new styles * LogListControls: update width * Remove console log * LogList: wrap component in context * LogListContext: make it stateful * LogListControls: connect with context * LogListContext: sync displayed fields * LogListContext: add syntax highlighting control * LogLine: improve color with highlighting off * LogListControls: improve button styles * LogListControls: add sort order option * LogListControls: add dedup strategy * LogListContext: sync prop changes with state * LogList: add option change callback * LogListContext: sync external changes only when showControls is disabled * LogListContext: unify sync effect * LogListControls: improve buttons active css * LogListContext: add optional storage support * LogList: make syntaxHighlighting and read from store or default to true * LogsPanel: add support for new options * Generated file * Update tests * New Logs Panel: add showControls option * LogList: make eventBus optional * LogsPanel: expose syntaxHighlighting * LogsPanel: expose grammar to plugins * Remove incorrect legacy file * LogListControls: allow options change with controls enabled in panel editor * LogLine: apply no-highlighting class to ansi wrapper * LogListControls: add frontend level filtering * LogList: filter by filterLevels * LogListControls: allow filterLevels in dashboards * LogLine: update unit tests * LogLineMenu: update unit test * LogListControls: add unit test * Revert * LogList: add unit test * LogList: add onLogRowHover support * LogList: test hover events * LogsPanel: add unit test * LogLine: use theme color for errors * LogLine: minor tweak to hover state * Chore: fix test case name * LogListControls: add border * LogListControls: prevent default on wrap toggle click * LogLine: switch info and debug colors * ContentOutline + LogControls: sync displayed levels and minor outline improvements * LogListContext: sync with external filterLevel changes * Logs: work with arrays of LogLevel and not plain strings * Fix type * LogListControl: increase controls size
2025-04-04 20:53:12 +08:00
import { LogListContextProvider } from './LogListContext';
import { LogListControls } from './LogListControls';
import { ScrollToLogsEvent } from './virtualization';
jest.mock('../../utils');
New Logs Panel: Add LogListControl component (#102359) * LogListNavigation: create component * LogListNavigation: make it optional * Refactor Navigation into Controls * Explore Logs: hide old panel options * LogListControls: add more controls and apply new styles * LogListControls: update width * Remove console log * LogList: wrap component in context * LogListContext: make it stateful * LogListControls: connect with context * LogListContext: sync displayed fields * LogListContext: add syntax highlighting control * LogLine: improve color with highlighting off * LogListControls: improve button styles * LogListControls: add sort order option * LogListControls: add dedup strategy * LogListContext: sync prop changes with state * LogList: add option change callback * LogListContext: sync external changes only when showControls is disabled * LogListContext: unify sync effect * LogListControls: improve buttons active css * LogListContext: add optional storage support * LogList: make syntaxHighlighting and read from store or default to true * LogsPanel: add support for new options * Generated file * Update tests * New Logs Panel: add showControls option * LogList: make eventBus optional * LogsPanel: expose syntaxHighlighting * LogsPanel: expose grammar to plugins * Remove incorrect legacy file * LogListControls: allow options change with controls enabled in panel editor * LogLine: apply no-highlighting class to ansi wrapper * LogListControls: add frontend level filtering * LogList: filter by filterLevels * LogListControls: allow filterLevels in dashboards * LogLine: update unit tests * LogLineMenu: update unit test * LogListControls: add unit test * Revert * LogList: add unit test * LogList: add onLogRowHover support * LogList: test hover events * LogsPanel: add unit test * LogLine: use theme color for errors * LogLine: minor tweak to hover state * Chore: fix test case name * LogListControls: add border * LogListControls: prevent default on wrap toggle click * LogLine: switch info and debug colors * ContentOutline + LogControls: sync displayed levels and minor outline improvements * LogListContext: sync with external filterLevel changes * Logs: work with arrays of LogLevel and not plain strings * Fix type * LogListControl: increase controls size
2025-04-04 20:53:12 +08:00
const contextProps = {
app: CoreApp.Unknown,
dedupStrategy: LogsDedupStrategy.exact,
displayedFields: [],
logs: [],
New Logs Panel: Add LogListControl component (#102359) * LogListNavigation: create component * LogListNavigation: make it optional * Refactor Navigation into Controls * Explore Logs: hide old panel options * LogListControls: add more controls and apply new styles * LogListControls: update width * Remove console log * LogList: wrap component in context * LogListContext: make it stateful * LogListControls: connect with context * LogListContext: sync displayed fields * LogListContext: add syntax highlighting control * LogLine: improve color with highlighting off * LogListControls: improve button styles * LogListControls: add sort order option * LogListControls: add dedup strategy * LogListContext: sync prop changes with state * LogList: add option change callback * LogListContext: sync external changes only when showControls is disabled * LogListContext: unify sync effect * LogListControls: improve buttons active css * LogListContext: add optional storage support * LogList: make syntaxHighlighting and read from store or default to true * LogsPanel: add support for new options * Generated file * Update tests * New Logs Panel: add showControls option * LogList: make eventBus optional * LogsPanel: expose syntaxHighlighting * LogsPanel: expose grammar to plugins * Remove incorrect legacy file * LogListControls: allow options change with controls enabled in panel editor * LogLine: apply no-highlighting class to ansi wrapper * LogListControls: add frontend level filtering * LogList: filter by filterLevels * LogListControls: allow filterLevels in dashboards * LogLine: update unit tests * LogLineMenu: update unit test * LogListControls: add unit test * Revert * LogList: add unit test * LogList: add onLogRowHover support * LogList: test hover events * LogsPanel: add unit test * LogLine: use theme color for errors * LogLine: minor tweak to hover state * Chore: fix test case name * LogListControls: add border * LogListControls: prevent default on wrap toggle click * LogLine: switch info and debug colors * ContentOutline + LogControls: sync displayed levels and minor outline improvements * LogListContext: sync with external filterLevel changes * Logs: work with arrays of LogLevel and not plain strings * Fix type * LogListControl: increase controls size
2025-04-04 20:53:12 +08:00
showControls: true,
showTime: false,
sortOrder: LogsSortOrder.Ascending,
syntaxHighlighting: false,
wrapLogMessage: false,
};
describe('LogListControls', () => {
test('Renders without errors', () => {
render(
<LogListContextProvider {...contextProps}>
<LogListControls eventBus={new EventBusSrv()} />
</LogListContextProvider>
);
expect(screen.getByLabelText('Scroll to bottom')).toBeInTheDocument();
expect(screen.getByLabelText('Oldest logs first')).toBeInTheDocument();
expect(screen.getByLabelText('Deduplication')).toBeInTheDocument();
expect(screen.getByLabelText('Display levels')).toBeInTheDocument();
expect(screen.getByLabelText('Show timestamps')).toBeInTheDocument();
expect(screen.getByLabelText('Wrap lines')).toBeInTheDocument();
expect(screen.getByLabelText('Enable highlighting')).toBeInTheDocument();
expect(screen.getByLabelText('Scroll to top')).toBeInTheDocument();
expect(screen.queryByLabelText('Show unique labels')).not.toBeInTheDocument();
expect(screen.queryByLabelText('Expand JSON logs')).not.toBeInTheDocument();
expect(
screen.queryByLabelText('Fix incorrectly escaped newline and tab sequences in log lines')
).not.toBeInTheDocument();
expect(screen.queryByLabelText('Remove escaping')).not.toBeInTheDocument();
});
test('Renders legacy controls', () => {
render(
<LogListContextProvider {...contextProps} app={CoreApp.Explore} showUniqueLabels={false} prettifyJSON={false}>
<LogListControls eventBus={new EventBusSrv()} />
</LogListContextProvider>
);
expect(screen.getByLabelText('Show unique labels')).toBeInTheDocument();
expect(screen.getByLabelText('Expand JSON logs')).toBeInTheDocument();
New Logs Panel: Add LogListControl component (#102359) * LogListNavigation: create component * LogListNavigation: make it optional * Refactor Navigation into Controls * Explore Logs: hide old panel options * LogListControls: add more controls and apply new styles * LogListControls: update width * Remove console log * LogList: wrap component in context * LogListContext: make it stateful * LogListControls: connect with context * LogListContext: sync displayed fields * LogListContext: add syntax highlighting control * LogLine: improve color with highlighting off * LogListControls: improve button styles * LogListControls: add sort order option * LogListControls: add dedup strategy * LogListContext: sync prop changes with state * LogList: add option change callback * LogListContext: sync external changes only when showControls is disabled * LogListContext: unify sync effect * LogListControls: improve buttons active css * LogListContext: add optional storage support * LogList: make syntaxHighlighting and read from store or default to true * LogsPanel: add support for new options * Generated file * Update tests * New Logs Panel: add showControls option * LogList: make eventBus optional * LogsPanel: expose syntaxHighlighting * LogsPanel: expose grammar to plugins * Remove incorrect legacy file * LogListControls: allow options change with controls enabled in panel editor * LogLine: apply no-highlighting class to ansi wrapper * LogListControls: add frontend level filtering * LogList: filter by filterLevels * LogListControls: allow filterLevels in dashboards * LogLine: update unit tests * LogLineMenu: update unit test * LogListControls: add unit test * Revert * LogList: add unit test * LogList: add onLogRowHover support * LogList: test hover events * LogsPanel: add unit test * LogLine: use theme color for errors * LogLine: minor tweak to hover state * Chore: fix test case name * LogListControls: add border * LogListControls: prevent default on wrap toggle click * LogLine: switch info and debug colors * ContentOutline + LogControls: sync displayed levels and minor outline improvements * LogListContext: sync with external filterLevel changes * Logs: work with arrays of LogLevel and not plain strings * Fix type * LogListControl: increase controls size
2025-04-04 20:53:12 +08:00
});
test.each([CoreApp.Dashboard, CoreApp.PanelEditor, CoreApp.PanelViewer])(
'Renders a subset of options for dashboards',
(app: CoreApp) => {
render(
<LogListContextProvider {...contextProps} app={app}>
<LogListControls eventBus={new EventBusSrv()} />
</LogListContextProvider>
);
expect(screen.getByLabelText('Scroll to bottom')).toBeInTheDocument();
expect(screen.getByLabelText('Scroll to top')).toBeInTheDocument();
expect(screen.getByLabelText('Display levels')).toBeInTheDocument();
expect(screen.queryByLabelText('Oldest logs first')).not.toBeInTheDocument();
expect(screen.queryByLabelText('Deduplication')).not.toBeInTheDocument();
expect(screen.queryByLabelText('Show timestamps')).not.toBeInTheDocument();
expect(screen.queryByLabelText('Wrap lines')).not.toBeInTheDocument();
expect(screen.queryByLabelText('Enable highlighting')).not.toBeInTheDocument();
}
);
test('Renders a subset of options for plugins', () => {
render(
<LogListContextProvider {...contextProps} app={CoreApp.Unknown}>
<LogListControls eventBus={new EventBusSrv()} />
</LogListContextProvider>
);
expect(screen.getByLabelText('Scroll to bottom')).toBeInTheDocument();
expect(screen.getByLabelText('Oldest logs first')).toBeInTheDocument();
expect(screen.getByLabelText('Deduplication')).toBeInTheDocument();
expect(screen.getByLabelText('Display levels')).toBeInTheDocument();
expect(screen.getByLabelText('Show timestamps')).toBeInTheDocument();
expect(screen.getByLabelText('Wrap lines')).toBeInTheDocument();
expect(screen.getByLabelText('Enable highlighting')).toBeInTheDocument();
expect(screen.getByLabelText('Scroll to top')).toBeInTheDocument();
expect(screen.queryByLabelText('Show unique labels')).not.toBeInTheDocument();
expect(screen.queryByLabelText('Expand JSON logs')).not.toBeInTheDocument();
expect(
screen.queryByLabelText('Fix incorrectly escaped newline and tab sequences in log lines')
).not.toBeInTheDocument();
expect(screen.queryByLabelText('Remove escaping')).not.toBeInTheDocument();
});
New Logs Panel: Add LogListControl component (#102359) * LogListNavigation: create component * LogListNavigation: make it optional * Refactor Navigation into Controls * Explore Logs: hide old panel options * LogListControls: add more controls and apply new styles * LogListControls: update width * Remove console log * LogList: wrap component in context * LogListContext: make it stateful * LogListControls: connect with context * LogListContext: sync displayed fields * LogListContext: add syntax highlighting control * LogLine: improve color with highlighting off * LogListControls: improve button styles * LogListControls: add sort order option * LogListControls: add dedup strategy * LogListContext: sync prop changes with state * LogList: add option change callback * LogListContext: sync external changes only when showControls is disabled * LogListContext: unify sync effect * LogListControls: improve buttons active css * LogListContext: add optional storage support * LogList: make syntaxHighlighting and read from store or default to true * LogsPanel: add support for new options * Generated file * Update tests * New Logs Panel: add showControls option * LogList: make eventBus optional * LogsPanel: expose syntaxHighlighting * LogsPanel: expose grammar to plugins * Remove incorrect legacy file * LogListControls: allow options change with controls enabled in panel editor * LogLine: apply no-highlighting class to ansi wrapper * LogListControls: add frontend level filtering * LogList: filter by filterLevels * LogListControls: allow filterLevels in dashboards * LogLine: update unit tests * LogLineMenu: update unit test * LogListControls: add unit test * Revert * LogList: add unit test * LogList: add onLogRowHover support * LogList: test hover events * LogsPanel: add unit test * LogLine: use theme color for errors * LogLine: minor tweak to hover state * Chore: fix test case name * LogListControls: add border * LogListControls: prevent default on wrap toggle click * LogLine: switch info and debug colors * ContentOutline + LogControls: sync displayed levels and minor outline improvements * LogListContext: sync with external filterLevel changes * Logs: work with arrays of LogLevel and not plain strings * Fix type * LogListControl: increase controls size
2025-04-04 20:53:12 +08:00
test('Allows to scroll', async () => {
const eventBus = new EventBusSrv();
jest.spyOn(eventBus, 'publish');
render(
<LogListContextProvider {...contextProps}>
<LogListControls eventBus={eventBus} />
</LogListContextProvider>
);
await userEvent.click(screen.getByLabelText('Scroll to bottom'));
await userEvent.click(screen.getByLabelText('Scroll to top'));
expect(eventBus.publish).toHaveBeenCalledTimes(2);
expect(eventBus.publish).toHaveBeenCalledWith(
new ScrollToLogsEvent({
scrollTo: 'bottom',
})
);
expect(eventBus.publish).toHaveBeenCalledWith(
new ScrollToLogsEvent({
scrollTo: 'top',
})
);
});
test('Controls sort order', async () => {
const onLogOptionsChange = jest.fn();
render(
<LogListContextProvider
{...contextProps}
sortOrder={LogsSortOrder.Ascending}
onLogOptionsChange={onLogOptionsChange}
>
<LogListControls eventBus={new EventBusSrv()} />
</LogListContextProvider>
);
await userEvent.click(screen.getByLabelText('Oldest logs first'));
expect(onLogOptionsChange).toHaveBeenCalledTimes(1);
expect(onLogOptionsChange).toHaveBeenCalledWith('sortOrder', LogsSortOrder.Descending);
});
test('Controls deduplication', async () => {
const onLogOptionsChange = jest.fn();
render(
<LogListContextProvider {...contextProps} onLogOptionsChange={onLogOptionsChange}>
<LogListControls eventBus={new EventBusSrv()} />
</LogListContextProvider>
);
await userEvent.click(screen.getByLabelText('Deduplication'));
await userEvent.click(screen.getByText('Numbers'));
expect(onLogOptionsChange).toHaveBeenCalledTimes(1);
expect(onLogOptionsChange).toHaveBeenCalledWith('dedupStrategy', LogsDedupStrategy.numbers);
});
test('Sets level filters', async () => {
const onLogOptionsChange = jest.fn();
render(
<LogListContextProvider {...contextProps} onLogOptionsChange={onLogOptionsChange}>
<LogListControls eventBus={new EventBusSrv()} />
</LogListContextProvider>
);
await userEvent.click(screen.getByLabelText('Display levels'));
expect(await screen.findByText('All levels')).toBeVisible();
expect(screen.getByText('Info')).toBeVisible();
expect(screen.getByText('Debug')).toBeVisible();
expect(screen.getByText('Trace')).toBeVisible();
expect(screen.getByText('Warning')).toBeVisible();
expect(screen.getByText('Error')).toBeVisible();
expect(screen.getByText('Critical')).toBeVisible();
await userEvent.click(screen.getByText('Error'));
expect(onLogOptionsChange).toHaveBeenCalledWith('filterLevels', ['error']);
});
test('Controls timestamp visibility', async () => {
const onLogOptionsChange = jest.fn();
render(
<LogListContextProvider {...contextProps} showTime={false} onLogOptionsChange={onLogOptionsChange}>
<LogListControls eventBus={new EventBusSrv()} />
</LogListContextProvider>
);
await userEvent.click(screen.getByLabelText('Show timestamps'));
expect(onLogOptionsChange).toHaveBeenCalledTimes(1);
expect(onLogOptionsChange).toHaveBeenCalledWith('showTime', true);
});
test('Controls line wrapping', async () => {
const onLogOptionsChange = jest.fn();
render(
<LogListContextProvider {...contextProps} wrapLogMessage={false} onLogOptionsChange={onLogOptionsChange}>
<LogListControls eventBus={new EventBusSrv()} />
</LogListContextProvider>
);
await userEvent.click(screen.getByLabelText('Wrap lines'));
expect(onLogOptionsChange).toHaveBeenCalledTimes(1);
expect(onLogOptionsChange).toHaveBeenCalledWith('wrapLogMessage', true);
});
test('Controls syntax highlighting', async () => {
const onLogOptionsChange = jest.fn();
render(
<LogListContextProvider {...contextProps} syntaxHighlighting={false} onLogOptionsChange={onLogOptionsChange}>
<LogListControls eventBus={new EventBusSrv()} />
</LogListContextProvider>
);
await userEvent.click(screen.getByLabelText('Enable highlighting'));
expect(onLogOptionsChange).toHaveBeenCalledTimes(1);
expect(onLogOptionsChange).toHaveBeenCalledWith('syntaxHighlighting', true);
});
test('Controls unique labels', async () => {
const { rerender } = render(
<LogListContextProvider {...contextProps} app={CoreApp.Explore} showUniqueLabels={false}>
<LogListControls eventBus={new EventBusSrv()} />
</LogListContextProvider>
);
await userEvent.click(screen.getByLabelText('Show unique labels'));
rerender(
<LogListContextProvider {...contextProps} app={CoreApp.Explore} showUniqueLabels={false}>
<LogListControls eventBus={new EventBusSrv()} />
</LogListContextProvider>
);
expect(screen.getByLabelText('Hide unique labels'));
});
test('Controls Expand JSON logs', async () => {
const { rerender } = render(
<LogListContextProvider {...contextProps} prettifyJSON={false}>
<LogListControls eventBus={new EventBusSrv()} />
</LogListContextProvider>
);
await userEvent.click(screen.getByLabelText('Expand JSON logs'));
rerender(
<LogListContextProvider {...contextProps} showUniqueLabels={false}>
<LogListControls eventBus={new EventBusSrv()} />
</LogListContextProvider>
);
expect(screen.getByLabelText('Collapse JSON logs'));
});
test.each([
['txt', 'text'],
['json', 'json'],
['csv', 'csv'],
])('Allows to download logs', async (label: string, format: string) => {
jest.mocked(downloadLogs).mockClear();
render(
<LogListContextProvider {...contextProps}>
<LogListControls eventBus={new EventBusSrv()} />
</LogListContextProvider>
);
await userEvent.click(screen.getByLabelText('Download logs'));
await userEvent.click(await screen.findByText(label));
expect(downloadLogs).toHaveBeenCalledTimes(1);
expect(downloadLogs).toHaveBeenCalledWith(format, [], undefined);
});
test('Allows to download logs filtered logs', async () => {
jest.mocked(downloadLogs).mockClear();
const log1 = createLogRow({ logLevel: LogLevel.error });
const log2 = createLogRow({ logLevel: LogLevel.warning });
const logs = [log1, log2];
const filteredLogs = [log1];
render(
<LogListContextProvider {...contextProps} logs={logs} filterLevels={[LogLevel.error]}>
<LogListControls eventBus={new EventBusSrv()} />
</LogListContextProvider>
);
await userEvent.click(screen.getByLabelText('Download logs'));
await userEvent.click(await screen.findByText('txt'));
expect(downloadLogs).toHaveBeenCalledWith('text', filteredLogs, undefined);
});
test('Controls new lines', async () => {
const { rerender } = render(
<LogListContextProvider {...contextProps} hasUnescapedContent>
<LogListControls eventBus={new EventBusSrv()} />
</LogListContextProvider>
);
await userEvent.click(screen.getByLabelText('Fix incorrectly escaped newline and tab sequences in log lines'));
rerender(
<LogListContextProvider {...contextProps} hasUnescapedContent>
<LogListControls eventBus={new EventBusSrv()} />
</LogListContextProvider>
);
await userEvent.click(screen.getByLabelText('Remove escaping'));
});
New Logs Panel: Add LogListControl component (#102359) * LogListNavigation: create component * LogListNavigation: make it optional * Refactor Navigation into Controls * Explore Logs: hide old panel options * LogListControls: add more controls and apply new styles * LogListControls: update width * Remove console log * LogList: wrap component in context * LogListContext: make it stateful * LogListControls: connect with context * LogListContext: sync displayed fields * LogListContext: add syntax highlighting control * LogLine: improve color with highlighting off * LogListControls: improve button styles * LogListControls: add sort order option * LogListControls: add dedup strategy * LogListContext: sync prop changes with state * LogList: add option change callback * LogListContext: sync external changes only when showControls is disabled * LogListContext: unify sync effect * LogListControls: improve buttons active css * LogListContext: add optional storage support * LogList: make syntaxHighlighting and read from store or default to true * LogsPanel: add support for new options * Generated file * Update tests * New Logs Panel: add showControls option * LogList: make eventBus optional * LogsPanel: expose syntaxHighlighting * LogsPanel: expose grammar to plugins * Remove incorrect legacy file * LogListControls: allow options change with controls enabled in panel editor * LogLine: apply no-highlighting class to ansi wrapper * LogListControls: add frontend level filtering * LogList: filter by filterLevels * LogListControls: allow filterLevels in dashboards * LogLine: update unit tests * LogLineMenu: update unit test * LogListControls: add unit test * Revert * LogList: add unit test * LogList: add onLogRowHover support * LogList: test hover events * LogsPanel: add unit test * LogLine: use theme color for errors * LogLine: minor tweak to hover state * Chore: fix test case name * LogListControls: add border * LogListControls: prevent default on wrap toggle click * LogLine: switch info and debug colors * ContentOutline + LogControls: sync displayed levels and minor outline improvements * LogListContext: sync with external filterLevel changes * Logs: work with arrays of LogLevel and not plain strings * Fix type * LogListControl: increase controls size
2025-04-04 20:53:12 +08:00
});