mirror of
https://github.com/grafana/grafana.git
synced 2026-01-06 17:33:49 +08:00
New Logs Panel: Read default font size from storage + add missing unescaped content check + fix mutation (#106755)
* Logs Panel: remove default value to it's taken from local storage code * processing: do not remove newlines, let truncation handle * LogList: check and pass unescaped content to context * LogLine: prevent mutation of searchWords * grammar: use parseFlags * grammar: escape regex
This commit is contained in:
@@ -236,7 +236,7 @@ const DisplayedFields = ({
|
||||
const { matchingUids, search } = useLogListSearchContext();
|
||||
|
||||
const searchWords = useMemo(() => {
|
||||
const searchWords = log.searchWords && log.searchWords[0] ? log.searchWords : [];
|
||||
const searchWords = log.searchWords && log.searchWords[0] ? log.searchWords.slice() : [];
|
||||
if (search && matchingUids?.includes(log.uid)) {
|
||||
searchWords.push(search);
|
||||
}
|
||||
@@ -271,7 +271,7 @@ const LogLineBody = ({ log, styles }: { log: LogListModel; styles: LogLineStyles
|
||||
const { matchingUids, search } = useLogListSearchContext();
|
||||
|
||||
const highlight = useMemo(() => {
|
||||
const searchWords = log.searchWords && log.searchWords[0] ? log.searchWords : [];
|
||||
const searchWords = log.searchWords && log.searchWords[0] ? log.searchWords.slice() : [];
|
||||
if (search && matchingUids?.includes(log.uid)) {
|
||||
searchWords.push(search);
|
||||
}
|
||||
|
||||
@@ -259,5 +259,33 @@ describe('LogList', () => {
|
||||
|
||||
expect(screen.queryByPlaceholderText('Search in logs')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('Does not conflict with search words', async () => {
|
||||
logs = [
|
||||
createLogRow({ uid: '1' }),
|
||||
createLogRow({ uid: '2', entry: '(?i)some text', searchWords: ['some text'] }),
|
||||
];
|
||||
|
||||
render(<LogList {...defaultProps} logs={logs} />);
|
||||
|
||||
expect(screen.queryByPlaceholderText('Search in logs')).not.toBeInTheDocument();
|
||||
expect(screen.getByText('log message 1')).toBeInTheDocument();
|
||||
expect(screen.getByText('some text')).toBeInTheDocument();
|
||||
|
||||
await userEvent.keyboard('{Control>}{f}{/Control}');
|
||||
|
||||
expect(screen.getByPlaceholderText('Search in logs')).toBeInTheDocument();
|
||||
|
||||
await userEvent.type(screen.getByPlaceholderText('Search in logs'), '(?i)');
|
||||
|
||||
expect(screen.getByText('log message 1')).toBeInTheDocument();
|
||||
expect(screen.getByText('(?i)')).toBeInTheDocument();
|
||||
expect(screen.getByText('some text')).toBeInTheDocument();
|
||||
|
||||
await userEvent.clear(screen.getByPlaceholderText('Search in logs'));
|
||||
|
||||
expect(screen.getByText('log message 1')).toBeInTheDocument();
|
||||
expect(screen.getByText('some text')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -151,6 +151,7 @@ export const LogList = ({
|
||||
timeZone,
|
||||
wrapLogMessage,
|
||||
}: Props) => {
|
||||
const hasUnescapedContent = useMemo(() => logs.some((log) => log.hasUnescapedContent), [logs]);
|
||||
return (
|
||||
<LogListContextProvider
|
||||
app={app}
|
||||
@@ -161,6 +162,7 @@ export const LogList = ({
|
||||
filterLevels={filterLevels}
|
||||
fontSize={fontSize}
|
||||
getRowContextQuery={getRowContextQuery}
|
||||
hasUnescapedContent={hasUnescapedContent}
|
||||
isLabelFilterActive={isLabelFilterActive}
|
||||
logs={logs}
|
||||
logsMeta={logsMeta}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Grammar } from 'prismjs';
|
||||
|
||||
import { escapeRegex } from '@grafana/data';
|
||||
import { escapeRegex, parseFlags } from '@grafana/data';
|
||||
|
||||
import { LogListModel } from './processing';
|
||||
|
||||
@@ -30,14 +30,26 @@ export const generateTextMatchGrammar = (
|
||||
highlightWords: string[] | undefined = [],
|
||||
search: string | undefined
|
||||
): Grammar => {
|
||||
const textMatches = [...highlightWords];
|
||||
/**
|
||||
* See:
|
||||
* - https://github.com/grafana/grafana/blob/96f1582c36f94cf4ac7621b7af86bc9e2ad626fb/public/app/features/logs/components/LogRowMessage.tsx#L67
|
||||
* - https://github.com/grafana/grafana/blob/96f1582c36f94cf4ac7621b7af86bc9e2ad626fb/packages/grafana-data/src/text/text.ts#L12
|
||||
*/
|
||||
const expressions = highlightWords.map((word) => {
|
||||
const { cleaned, flags } = parseFlags(cleanNeedle(word));
|
||||
return new RegExp(`(?:${cleaned})`, flags);
|
||||
});
|
||||
if (search) {
|
||||
textMatches.push(escapeRegex(search));
|
||||
expressions.push(new RegExp(escapeRegex(search), 'gi'));
|
||||
}
|
||||
if (!textMatches.length) {
|
||||
if (!expressions.length) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
'log-search-match': new RegExp(textMatches.join('|'), 'g'),
|
||||
'log-search-match': expressions,
|
||||
};
|
||||
};
|
||||
|
||||
const cleanNeedle = (needle: string): string => {
|
||||
return needle.replace(/[[{(][\w,.\/:;<=>?:*+]+$/, '');
|
||||
};
|
||||
|
||||
@@ -88,9 +88,7 @@ export class LogListModel implements LogRowModel {
|
||||
|
||||
get body(): string {
|
||||
if (this._body === undefined) {
|
||||
let body = this.collapsed ? this.raw.substring(0, getTruncationLength(null)) : this.raw;
|
||||
// Turn it into a single-line log entry for the list
|
||||
this._body = body.replace(/(\r\n|\n|\r)/g, '');
|
||||
this._body = this.collapsed ? this.raw.substring(0, getTruncationLength(null)) : this.raw;
|
||||
}
|
||||
return this._body;
|
||||
}
|
||||
|
||||
@@ -87,7 +87,6 @@ export const plugin = new PanelPlugin<Options>(LogsPanel)
|
||||
},
|
||||
],
|
||||
},
|
||||
defaultValue: 'default',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user