mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Grok Debugger] Adding syntax highlighting for grok expressions (#18572)
* Adding basic syntax highlighting for grok expressions * Use EUI color palette * Handle regex tokens, escaped and unescaped * Return token for escaped content * Add functional test * Using higher-contrast colors * Removing comment I used for developing the highlight rules * Using object destructuring * Removing unnecessary method
This commit is contained in:
parent
617db3cbe8
commit
84ae548b77
7 changed files with 153 additions and 0 deletions
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import ace from 'ace';
|
||||
|
||||
const { TextHighlightRules } = ace.acequire("ace/mode/text_highlight_rules");
|
||||
|
||||
export class GrokHighlightRules extends TextHighlightRules {
|
||||
constructor() {
|
||||
super();
|
||||
this.$rules = {
|
||||
start: [
|
||||
{
|
||||
token: [
|
||||
"grokStart",
|
||||
"grokPatternName",
|
||||
"grokSeparator",
|
||||
"grokFieldName",
|
||||
"grokEnd"
|
||||
],
|
||||
regex: "(%{)([^:]+)(:)([^:]+)(})"
|
||||
},
|
||||
{
|
||||
token: [
|
||||
"grokStart",
|
||||
"grokPatternName",
|
||||
"grokSeparator",
|
||||
"grokFieldName",
|
||||
"grokSeparator",
|
||||
"grokFieldType",
|
||||
"grokEnd"
|
||||
],
|
||||
regex: "(%{)([^:]+)(:)([^:]+)(:)([^:]+)(})"
|
||||
},
|
||||
{
|
||||
token: (escapeToken, /* regexToken */) => {
|
||||
if (escapeToken) {
|
||||
return [ 'grokEscape', 'grokEscaped' ];
|
||||
}
|
||||
return 'grokRegex';
|
||||
},
|
||||
regex: "(\\\\)?([\\[\\]\\(\\)\\?\\:\\|])"
|
||||
},
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
17
x-pack/plugins/grokdebugger/public/lib/ace/grok_mode.js
Normal file
17
x-pack/plugins/grokdebugger/public/lib/ace/grok_mode.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import ace from 'ace';
|
||||
import { GrokHighlightRules } from './grok_highlight_rules';
|
||||
|
||||
const TextMode = ace.acequire("ace/mode/text").Mode;
|
||||
|
||||
export class GrokMode extends TextMode {
|
||||
constructor() {
|
||||
super();
|
||||
this.HighlightRules = GrokHighlightRules;
|
||||
}
|
||||
}
|
7
x-pack/plugins/grokdebugger/public/lib/ace/index.js
Normal file
7
x-pack/plugins/grokdebugger/public/lib/ace/index.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { GrokMode } from './grok_mode';
|
|
@ -18,4 +18,25 @@ grokdebugger {
|
|||
.grokdebugger-simulate-button {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.ace_grokStart,
|
||||
.ace_grokEnd,
|
||||
.ace_grokSeparator,
|
||||
.ace_grokEscape {
|
||||
color: #999999; // euiColorMediumShade
|
||||
}
|
||||
|
||||
.ace_grokPatternName {
|
||||
color: #017F75; // euiColorSecondary
|
||||
}
|
||||
|
||||
.ace_grokFieldName,
|
||||
.ace_grokRegex {
|
||||
color: #0079A5; // euiColorPrimary
|
||||
}
|
||||
|
||||
.ace_grokFieldType {
|
||||
color: #0079A5; // euiColorPrimary
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import { uiModules } from 'ui/modules';
|
||||
import template from './pattern_input.html';
|
||||
import './pattern_input.less';
|
||||
import { GrokMode } from '../../../../lib/ace';
|
||||
|
||||
const app = uiModules.get('xpack/grokdebugger');
|
||||
|
||||
|
@ -34,6 +35,7 @@ app.directive('patternInput', function () {
|
|||
maxLines: 10
|
||||
});
|
||||
editor.$blockScrolling = Infinity;
|
||||
editor.getSession().setMode(new GrokMode());
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,5 +42,43 @@ export default function ({ getService, getPageObjects }) {
|
|||
await grokDebugger.assertEventOutput({ f: 'Seger', m: 'Comma', l: 'Bob' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('syntax highlighting', () => {
|
||||
it('applies the correct CSS classes', async () => {
|
||||
const grokPattern = '\\[(?:-|%{NUMBER:bytes:int})\\]';
|
||||
|
||||
await grokDebugger.setPatternInput(grokPattern);
|
||||
|
||||
const GROK_START = 'grokStart';
|
||||
const GROK_PATTERN_NAME = 'grokPatternName';
|
||||
const GROK_SEPARATOR = 'grokSeparator';
|
||||
const GROK_FIELD_NAME = 'grokFieldName';
|
||||
const GROK_FIELD_TYPE = 'grokFieldType';
|
||||
const GROK_END = 'grokEnd';
|
||||
const GROK_ESCAPE = 'grokEscape';
|
||||
const GROK_ESCAPED = 'grokEscaped';
|
||||
const GROK_REGEX = 'grokRegex';
|
||||
|
||||
await grokDebugger.assertPatternInputSyntaxHighlighting([
|
||||
{ token: GROK_ESCAPE, content: '\\' },
|
||||
{ token: GROK_ESCAPED, content: '[' },
|
||||
{ token: GROK_REGEX, content: '(' },
|
||||
{ token: GROK_REGEX, content: '?' },
|
||||
{ token: GROK_REGEX, content: ':' },
|
||||
{ token: GROK_REGEX, content: '|' },
|
||||
{ token: GROK_START, content: '%{' },
|
||||
{ token: GROK_PATTERN_NAME, content: 'NUMBER' },
|
||||
{ token: GROK_SEPARATOR, content: ':' },
|
||||
{ token: GROK_FIELD_NAME, content: 'bytes' },
|
||||
{ token: GROK_SEPARATOR, content: ':' },
|
||||
{ token: GROK_FIELD_TYPE, content: 'int' },
|
||||
{ token: GROK_END, content: '}' },
|
||||
{ token: GROK_REGEX, content: ')' },
|
||||
{ token: GROK_ESCAPE, content: '\\' },
|
||||
{ token: GROK_ESCAPED, content: ']' },
|
||||
]);
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -61,5 +61,23 @@ export function GrokDebuggerProvider({ getService }) {
|
|||
expect(value).to.eql(expectedValue);
|
||||
});
|
||||
}
|
||||
|
||||
async assertPatternInputSyntaxHighlighting(expectedHighlights) {
|
||||
const patternInputElement = await testSubjects.find(SUBJ_UI_ACE_PATTERN_INPUT);
|
||||
const highlightedElements = await patternInputElement.findAllByXpath('.//div[@class="ace_line"]/*');
|
||||
|
||||
expect(highlightedElements.length).to.be(expectedHighlights.length);
|
||||
await Promise.all(highlightedElements.map(async (element, index) => {
|
||||
const highlightClass = await element.getAttribute('class');
|
||||
const highlightedContent = await element.getVisibleText();
|
||||
|
||||
const expectedHighlight = expectedHighlights[index];
|
||||
const expectedHighlightClass = `ace_${expectedHighlight.token}`;
|
||||
const expectedHighlightedContent = expectedHighlight.content;
|
||||
|
||||
expect(highlightClass).to.be(expectedHighlightClass);
|
||||
expect(highlightedContent).to.be(expectedHighlightedContent);
|
||||
}));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue