mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Explore: Save log results sort order (#45423)
* Explore: Save log results sort order * Change to radio group, add test and make language consistent with logs plugin
This commit is contained in:
parent
434697e0fd
commit
31090a75eb
87
public/app/features/explore/Logs.test.tsx
Normal file
87
public/app/features/explore/Logs.test.tsx
Normal file
@ -0,0 +1,87 @@
|
||||
import React from 'react';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import { LoadingState, LogLevel, LogRowModel, MutableDataFrame, toUtc } from '@grafana/data';
|
||||
|
||||
import { Logs } from './Logs';
|
||||
|
||||
describe('Logs', () => {
|
||||
const setup = (propOverrides?: object) => {
|
||||
const rows = [
|
||||
makeLog({ uid: '1', timeEpochMs: 1 }),
|
||||
makeLog({ uid: '2', timeEpochMs: 2 }),
|
||||
makeLog({ uid: '3', timeEpochMs: 3 }),
|
||||
];
|
||||
|
||||
return render(
|
||||
<Logs
|
||||
logRows={rows}
|
||||
timeZone={'utc'}
|
||||
width={50}
|
||||
loading={false}
|
||||
loadingState={LoadingState.Done}
|
||||
absoluteRange={{
|
||||
from: toUtc('2019-01-01 10:00:00').valueOf(),
|
||||
to: toUtc('2019-01-01 16:00:00').valueOf(),
|
||||
}}
|
||||
addResultsToCache={() => {}}
|
||||
onChangeTime={() => {}}
|
||||
clearCache={() => {}}
|
||||
getFieldLinks={() => {
|
||||
return [];
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers('modern');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should render logs', () => {
|
||||
setup();
|
||||
const logsSection = screen.getByTestId('logRows');
|
||||
let logRows = logsSection.querySelectorAll('tr');
|
||||
expect(logRows.length).toBe(3);
|
||||
expect(logRows[0].textContent).toContain('log message 3');
|
||||
expect(logRows[2].textContent).toContain('log message 1');
|
||||
});
|
||||
|
||||
it('should flip the order', () => {
|
||||
setup();
|
||||
const oldestFirstSelection = screen.getByLabelText('Oldest first');
|
||||
fireEvent.click(oldestFirstSelection);
|
||||
jest.advanceTimersByTime(1000);
|
||||
const logsSection = screen.getByTestId('logRows');
|
||||
let logRows = logsSection.querySelectorAll('tr');
|
||||
expect(logRows.length).toBe(3);
|
||||
expect(logRows[0].textContent).toContain('log message 1');
|
||||
expect(logRows[2].textContent).toContain('log message 3');
|
||||
});
|
||||
});
|
||||
|
||||
const makeLog = (overrides: Partial<LogRowModel>): LogRowModel => {
|
||||
const uid = overrides.uid || '1';
|
||||
const entry = `log message ${uid}`;
|
||||
return {
|
||||
uid,
|
||||
entryFieldIndex: 0,
|
||||
rowIndex: 0,
|
||||
dataFrame: new MutableDataFrame(),
|
||||
logLevel: LogLevel.debug,
|
||||
entry,
|
||||
hasAnsi: false,
|
||||
hasUnescapedContent: false,
|
||||
labels: {},
|
||||
raw: entry,
|
||||
timeFromNow: '',
|
||||
timeEpochMs: 1,
|
||||
timeEpochNs: '1000000',
|
||||
timeLocal: '',
|
||||
timeUtc: '',
|
||||
...overrides,
|
||||
};
|
||||
};
|
@ -43,6 +43,7 @@ const SETTINGS_KEYS = {
|
||||
showTime: 'grafana.explore.logs.showTime',
|
||||
wrapLogMessage: 'grafana.explore.logs.wrapLogMessage',
|
||||
prettifyLogMessage: 'grafana.explore.logs.prettifyLogMessage',
|
||||
logsSortOrder: 'grafana.explore.logs.sortOrder',
|
||||
};
|
||||
|
||||
interface Props extends Themeable2 {
|
||||
@ -96,7 +97,7 @@ class UnthemedLogs extends PureComponent<Props, State> {
|
||||
prettifyLogMessage: store.getBool(SETTINGS_KEYS.prettifyLogMessage, false),
|
||||
dedupStrategy: LogsDedupStrategy.none,
|
||||
hiddenLogLevels: [],
|
||||
logsSortOrder: null,
|
||||
logsSortOrder: store.get(SETTINGS_KEYS.logsSortOrder) || LogsSortOrder.Descending,
|
||||
isFlipping: false,
|
||||
showDetectedFields: [],
|
||||
forceEscape: false,
|
||||
@ -117,10 +118,10 @@ class UnthemedLogs extends PureComponent<Props, State> {
|
||||
// we are using setTimeout here to make sure that disabled button is rendered before the rendering of reordered logs
|
||||
this.flipOrderTimer = window.setTimeout(() => {
|
||||
this.setState((prevState) => {
|
||||
if (prevState.logsSortOrder === null || prevState.logsSortOrder === LogsSortOrder.Descending) {
|
||||
return { logsSortOrder: LogsSortOrder.Ascending };
|
||||
}
|
||||
return { logsSortOrder: LogsSortOrder.Descending };
|
||||
const newSortOrder =
|
||||
prevState.logsSortOrder === LogsSortOrder.Descending ? LogsSortOrder.Ascending : LogsSortOrder.Descending;
|
||||
store.set(SETTINGS_KEYS.logsSortOrder, newSortOrder);
|
||||
return { logsSortOrder: newSortOrder };
|
||||
});
|
||||
}, 0);
|
||||
this.cancelFlippingTimer = window.setTimeout(() => this.setState({ isFlipping: false }), 1000);
|
||||
@ -291,7 +292,6 @@ class UnthemedLogs extends PureComponent<Props, State> {
|
||||
const { dedupedRows, dedupCount } = this.dedupRows(filteredLogs, dedupStrategy);
|
||||
|
||||
const scanText = scanRange ? `Scanning ${rangeUtil.describeTimeRange(scanRange)}` : 'Scanning...';
|
||||
|
||||
return (
|
||||
<>
|
||||
{logsSeries && logsSeries.length ? (
|
||||
@ -366,16 +366,26 @@ class UnthemedLogs extends PureComponent<Props, State> {
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
<div>
|
||||
<Button
|
||||
variant="secondary"
|
||||
disabled={isFlipping}
|
||||
title={logsSortOrder === LogsSortOrder.Ascending ? 'Change to newest first' : 'Change to oldest first'}
|
||||
aria-label="Flip results order"
|
||||
className={styles.headerButton}
|
||||
onClick={this.onChangeLogsSortOrder}
|
||||
>
|
||||
{isFlipping ? 'Flipping...' : 'Flip results order'}
|
||||
</Button>
|
||||
<InlineField label="Display results" className={styles.horizontalInlineLabel} transparent>
|
||||
<RadioButtonGroup
|
||||
disabled={isFlipping}
|
||||
options={[
|
||||
{
|
||||
label: 'Newest first',
|
||||
value: LogsSortOrder.Descending,
|
||||
description: 'Show results newest to oldest',
|
||||
},
|
||||
{
|
||||
label: 'Oldest first',
|
||||
value: LogsSortOrder.Ascending,
|
||||
description: 'Show results oldest to newest',
|
||||
},
|
||||
]}
|
||||
value={logsSortOrder}
|
||||
onChange={this.onChangeLogsSortOrder}
|
||||
className={styles.radioButtons}
|
||||
/>
|
||||
</InlineField>
|
||||
</div>
|
||||
</div>
|
||||
<LogsMetaRow
|
||||
@ -390,7 +400,7 @@ class UnthemedLogs extends PureComponent<Props, State> {
|
||||
clearDetectedFields={this.clearDetectedFields}
|
||||
/>
|
||||
<div className={styles.logsSection}>
|
||||
<div className={styles.logRows}>
|
||||
<div className={styles.logRows} data-testid="logRows">
|
||||
<LogRows
|
||||
logRows={logRows}
|
||||
deduplicatedRows={dedupedRows}
|
||||
|
@ -74,8 +74,8 @@ export const plugin = new PanelPlugin<Options>(LogsPanel)
|
||||
description: '',
|
||||
settings: {
|
||||
options: [
|
||||
{ value: LogsSortOrder.Descending, label: 'Descending' },
|
||||
{ value: LogsSortOrder.Ascending, label: 'Ascending' },
|
||||
{ value: LogsSortOrder.Descending, label: 'Newest first' },
|
||||
{ value: LogsSortOrder.Ascending, label: 'Oldest first' },
|
||||
],
|
||||
},
|
||||
defaultValue: LogsSortOrder.Descending,
|
||||
|
Loading…
Reference in New Issue
Block a user