Skip to content

Commit

Permalink
[Console] Improve status code highlighting (elastic#192888)
Browse files Browse the repository at this point in the history
Closes elastic#190731

## Summary

This PR improves the status code highlighting when multiple requests are
sent.


https://github.com/user-attachments/assets/a0e8ba07-534d-4a48-aa7a-3964adc0e540


Dark mode:
<img width="1495" alt="Screenshot 2024-09-17 at 12 02 36"
src="https://github.com/user-attachments/assets/140e211d-57c2-48b7-abb8-09cfb4e24366">

All code statuses:
<img width="860" alt="Screenshot 2024-09-17 at 11 42 22"
src="https://github.com/user-attachments/assets/9509f9cd-ec60-44e2-b700-afaea595ad13">
  • Loading branch information
ElenaStoeva authored Sep 18, 2024
1 parent e546302 commit 61d0b7f
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 165 deletions.
27 changes: 15 additions & 12 deletions packages/kbn-monaco/src/console/lexer_rules/console_output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,24 @@ export const consoleOutputLexerRules: monaco.languages.IMonarchLanguage = {
comments: [
// Line comment indicated by #
// Everything after the # character is matched, stopping right before the status code and status text at the end if they are present
matchTokensWithEOL('comment', /# .+?(?=\s+\d{3}(?: \w+)*$)/, 'root', 'status'),
matchTokensWithEOL('comment.default', /# .+?(?=\s+\[\b1\d{2}(?: \w+)*\]$)/, 'root', 'status'),
matchTokensWithEOL('comment.success', /# .+?(?=\s+\[\b2\d{2}(?: \w+)*\]$)/, 'root', 'status'),
matchTokensWithEOL('comment.primary', /# .+?(?=\s+\[\b3\d{2}(?: \w+)*\]$)/, 'root', 'status'),
matchTokensWithEOL('comment.warning', /# .+?(?=\s+\[\b4\d{2}(?: \w+)*\]$)/, 'root', 'status'),
matchTokensWithEOL('comment.danger', /# .+?(?=\s+\[\b5\d{2}(?: \w+)*\]$)/, 'root', 'status'),
...consoleSharedLexerRules.tokenizer.comments,
],
status: [
// Following HTTP response status codes conventions
// Informational responses (status codes 100 – 199)
matchTokensWithEOL('status.info', /\b1\d{2}(?: \w+)*$/, 'root'),
// Successful responses (status codes 200 – 299)
matchTokensWithEOL('status.success', /\b2\d{2}(?: \w+)*$/, 'root'),
// Redirection messages (status codes 300 – 399)
matchTokensWithEOL('status.redirect', /\b3\d{2}(?: \w+)*$/, 'root'),
// Client error responses (status codes 400 – 499)
matchTokensWithEOL('status.warning', /\b4\d{2}(?: \w+)*$/, 'root'),
// Server error responses (status codes 500 – 599)
matchTokensWithEOL('status.error', /\b5\d{2}(?: \w+)*$/, 'root'),
// Status codes 100 – 199
matchTokensWithEOL('status.default', /\[\b1\d{2}(?: \w+)*\]$/, 'root'),
// Status codes 200 – 299
matchTokensWithEOL('status.success', /\[\b2\d{2}(?: \w+)*\]$/, 'root'),
// Status codes 300 – 399
matchTokensWithEOL('status.primary', /\[\b3\d{2}(?: \w+)*\]$/, 'root'),
// Status codes 400 – 499
matchTokensWithEOL('status.warning', /\[\b4\d{2}(?: \w+)*\]$/, 'root'),
// Status codes 500 – 599
matchTokensWithEOL('status.danger', /\[\b5\d{2}(?: \w+)*\]$/, 'root'),
],
},
};
50 changes: 42 additions & 8 deletions packages/kbn-monaco/src/console/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ const background = euiThemeVars.euiFormBackgroundColor;
const booleanTextColor = '#585CF6';
const methodTextColor = '#DD0A73';
const urlTextColor = '#00A69B';
const defaultStatusBackgroundColor = darkMode ? '#191B20' : '#F7F8FA';
const successStatusBackgroundColor = darkMode ? '#212B30' : '#E7F5F5';
const primaryStatusBackgroundColor = darkMode ? '#1E232D' : '#EBF1F7';
const warningStatusBackgroundColor = darkMode ? '#2C2B25' : '#FBF6E9';
const dangerStatusBackgroundColor = darkMode ? '#2E2024' : '#F6E6E7';
export const buildConsoleTheme = (): monaco.editor.IStandaloneThemeData => {
const euiTheme = darkMode ? buildDarkTheme() : buildLightTheme();
return {
Expand All @@ -39,27 +44,56 @@ export const buildConsoleTheme = (): monaco.editor.IStandaloneThemeData => {
makeHighContrastColor(euiThemeVars.euiColorAccentText)(background)
),
...buildRuleGroup(
['status.info'],
makeHighContrastColor(euiThemeVars.euiTextColor)(background)
['comment.default'],
makeHighContrastColor(euiThemeVars.euiTextColor)(defaultStatusBackgroundColor)
),
...buildRuleGroup(
['comment.success'],
makeHighContrastColor(euiThemeVars.euiColorSuccessText)(successStatusBackgroundColor)
),
...buildRuleGroup(
['comment.primary'],
makeHighContrastColor(euiThemeVars.euiTextColor)(primaryStatusBackgroundColor)
),
...buildRuleGroup(
['comment.warning'],
makeHighContrastColor(euiThemeVars.euiColorWarningText)(warningStatusBackgroundColor)
),
...buildRuleGroup(
['comment.danger'],
makeHighContrastColor(euiThemeVars.euiColorDangerText)(dangerStatusBackgroundColor)
),
...buildRuleGroup(
['status.default'],
makeHighContrastColor(euiThemeVars.euiTextColor)(defaultStatusBackgroundColor),
true
),
...buildRuleGroup(
['status.success'],
makeHighContrastColor(euiThemeVars.euiTextColor)(euiThemeVars.euiColorSuccess)
makeHighContrastColor(euiThemeVars.euiColorSuccessText)(successStatusBackgroundColor),
true
),
...buildRuleGroup(
['status.redirect'],
makeHighContrastColor(euiThemeVars.euiTextColor)(background)
['status.primary'],
makeHighContrastColor(euiThemeVars.euiTextColor)(primaryStatusBackgroundColor),
true
),
...buildRuleGroup(
['status.warning'],
makeHighContrastColor(euiThemeVars.euiTextColor)(euiThemeVars.euiColorWarning)
makeHighContrastColor(euiThemeVars.euiColorWarningText)(warningStatusBackgroundColor),
true
),
...buildRuleGroup(
['status.error'],
makeHighContrastColor('#FFFFFF')(euiThemeVars.euiColorDanger)
['status.danger'],
makeHighContrastColor(euiThemeVars.euiColorDangerText)(dangerStatusBackgroundColor),
true
),
...buildRuleGroup(['method'], makeHighContrastColor(methodTextColor)(background)),
...buildRuleGroup(['url'], makeHighContrastColor(urlTextColor)(background)),
],
colors: {
...euiTheme.colors,
'editorLineNumber.foreground': euiThemeVars.euiTextColor,
},
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@ export const SELECTED_REQUESTS_CLASSNAME = 'console__monaco_editor__selectedRequ
/*
* CSS class names used for the styling of multiple-response status codes
*/
export const PRIMARY_STATUS_BADGE_CLASSNAME = 'monaco__status_badge--primary';
export const SUCCESS_STATUS_BADGE_CLASSNAME = 'monaco__status_badge--success';
export const DEFAULT_STATUS_BADGE_CLASSNAME = 'monaco__status_badge--default';
export const WARNING_STATUS_BADGE_CLASSNAME = 'monaco__status_badge--warning';
export const DANGER_STATUS_BADGE_CLASSNAME = 'monaco__status_badge--danger';
export const STATUS_CODE_LINE_CLASSNAME = 'monaco__status_code_line';

export const whitespacesRegex = /\s+/;
export const newLineRegex = /\n/;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,7 @@
export {
AutocompleteType,
SELECTED_REQUESTS_CLASSNAME,
SUCCESS_STATUS_BADGE_CLASSNAME,
WARNING_STATUS_BADGE_CLASSNAME,
PRIMARY_STATUS_BADGE_CLASSNAME,
DEFAULT_STATUS_BADGE_CLASSNAME,
DANGER_STATUS_BADGE_CLASSNAME,
STATUS_CODE_LINE_CLASSNAME,
} from './constants';
export {
getRequestStartLineNumber,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@
*/

import { getStatusCodeDecorations } from './status_code_decoration_utils';
import {
SUCCESS_STATUS_BADGE_CLASSNAME,
WARNING_STATUS_BADGE_CLASSNAME,
DANGER_STATUS_BADGE_CLASSNAME,
} from './constants';
import { STATUS_CODE_LINE_CLASSNAME } from './constants';
import { RequestResult } from '../../../hooks/use_send_current_request/send_request';

const SUCCESS_STATUS_CODE_CLASSNAME = `${STATUS_CODE_LINE_CLASSNAME}--success`;
const WARNING_STATUS_CODE_CLASSNAME = `${STATUS_CODE_LINE_CLASSNAME}--warning`;
const DANGER_STATUS_CODE_CLASSNAME = `${STATUS_CODE_LINE_CLASSNAME}--danger`;

const SUCCESS_STATUS_CODE_LINE_CLASSNAME = `${STATUS_CODE_LINE_CLASSNAME}_number--success`;
const WARNING_STATUS_CODE_LINE_CLASSNAME = `${STATUS_CODE_LINE_CLASSNAME}_number--warning`;
const DANGER_STATUS_CODE_LINE_CLASSNAME = `${STATUS_CODE_LINE_CLASSNAME}_number--danger`;

describe('getStatusCodeDecorations', () => {
it('correctly returns all decorations on full data', () => {
// Sample multiple-response data returned from ES:
Expand Down Expand Up @@ -91,108 +95,45 @@ describe('getStatusCodeDecorations', () => {
const EXPECTED_DECORATIONS = [
{
range: {
endColumn: 21,
endColumn: 1,
endLineNumber: 1,
startColumn: 15,
startColumn: 1,
startLineNumber: 1,
},
options: {
inlineClassName: SUCCESS_STATUS_BADGE_CLASSNAME,
isWholeLine: true,
blockClassName: SUCCESS_STATUS_CODE_CLASSNAME,
marginClassName: SUCCESS_STATUS_CODE_LINE_CLASSNAME,
},
},
{
range: {
endColumn: 28,
endColumn: 1,
endLineNumber: 12,
startColumn: 13,
startColumn: 1,
startLineNumber: 12,
},
options: {
inlineClassName: WARNING_STATUS_BADGE_CLASSNAME,
isWholeLine: true,
blockClassName: WARNING_STATUS_CODE_CLASSNAME,
marginClassName: WARNING_STATUS_CODE_LINE_CLASSNAME,
},
},
{
range: {
endColumn: 47,
endColumn: 1,
endLineNumber: 18,
startColumn: 22,
startColumn: 1,
startLineNumber: 18,
},
options: {
inlineClassName: DANGER_STATUS_BADGE_CLASSNAME,
isWholeLine: true,
blockClassName: DANGER_STATUS_CODE_CLASSNAME,
marginClassName: DANGER_STATUS_CODE_LINE_CLASSNAME,
},
},
];

expect(getStatusCodeDecorations(SAMPLE_COMPLETE_DATA)).toEqual(EXPECTED_DECORATIONS);
});

it('only returns decorations for data with complete status code and text', () => {
// This sample data is same as in previous test but some of it has incomplete status code or status text
const SAMPLE_INCOMPLETE_DATA: RequestResult[] = [
{
response: {
timeMs: 50,
// @ts-ignore
statusCode: undefined,
statusText: 'OK',
contentType: 'application/json',
value:
'# GET _search OK\n{\n"took": 1,\n"timed_out": false,\n"hits": {\n"total": {\n"value": 0,\n"relation": "eq"\n}\n}\n}',
},
request: {
data: '',
method: 'GET',
path: '_search',
},
},
{
response: {
timeMs: 22,
statusCode: 400,
statusText: 'Bad Request',
contentType: 'application/json',
value: '# GET _test 400 Bad Request\n{\n"error": {\n"root_cause": [],\n"status": 400\n}',
},
request: {
data: '',
method: 'GET',
path: '_test',
},
},
{
response: {
timeMs: 23,
// @ts-ignore
statusCode: undefined,
// @ts-ignore
statusText: undefined,
contentType: 'application/json',
value: '# PUT /library/_bulk\n{\n"error": {\n"root_cause": [],\n"status": 500\n}',
},
request: {
data: '',
method: 'PUT',
path: '/library/_bulk?refresh',
},
},
];

// Only the second response has complete status code and text
const EXPECTED_DECORATIONS = [
{
range: {
endColumn: 28,
endLineNumber: 12,
startColumn: 13,
startLineNumber: 12,
},
options: {
inlineClassName: WARNING_STATUS_BADGE_CLASSNAME,
},
},
];

expect(getStatusCodeDecorations(SAMPLE_INCOMPLETE_DATA)).toEqual(EXPECTED_DECORATIONS);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,22 @@

import { monaco } from '@kbn/monaco';
import { RequestResult } from '../../../hooks/use_send_current_request/send_request';
import {
DEFAULT_STATUS_BADGE_CLASSNAME,
SUCCESS_STATUS_BADGE_CLASSNAME,
PRIMARY_STATUS_BADGE_CLASSNAME,
WARNING_STATUS_BADGE_CLASSNAME,
DANGER_STATUS_BADGE_CLASSNAME,
} from './constants';
import { STATUS_CODE_LINE_CLASSNAME } from './constants';

const getStatusCodeClassName = (statusCode: number) => {
const getStatusCodeClassNameSuffix = (statusCode: number) => {
if (statusCode <= 199) {
return DEFAULT_STATUS_BADGE_CLASSNAME;
return '--default';
}
if (statusCode <= 299) {
return SUCCESS_STATUS_BADGE_CLASSNAME;
return '--success';
}
if (statusCode <= 399) {
return PRIMARY_STATUS_BADGE_CLASSNAME;
return '--primary';
}
if (statusCode <= 499) {
return WARNING_STATUS_BADGE_CLASSNAME;
return '--warning';
}
return DANGER_STATUS_BADGE_CLASSNAME;
return '--danger';
};

export const getStatusCodeDecorations = (data: RequestResult[]) => {
Expand All @@ -39,25 +33,21 @@ export const getStatusCodeDecorations = (data: RequestResult[]) => {

data.forEach(({ response }) => {
if (response?.value) {
const totalStatus =
response.statusCode && response.statusText
? response.statusCode + ' ' + response.statusText
: '';
const startColumn = (response.value as string).indexOf(totalStatus) + 1;
if (totalStatus && startColumn !== 0) {
const range = {
startLineNumber: lastResponseEndLine + 1,
startColumn,
endLineNumber: lastResponseEndLine + 1,
endColumn: startColumn + totalStatus.length,
};
decorations.push({
range,
options: {
inlineClassName: getStatusCodeClassName(response.statusCode),
},
});
}
const range = {
startLineNumber: lastResponseEndLine + 1,
startColumn: 1,
endLineNumber: lastResponseEndLine + 1,
endColumn: 1, // It doesn't matter what endColumn we set as the decoration will be applied to the whole line
};
const classNameSuffix = getStatusCodeClassNameSuffix(response.statusCode);
decorations.push({
range,
options: {
isWholeLine: true,
blockClassName: `${STATUS_CODE_LINE_CLASSNAME}${classNameSuffix}`,
marginClassName: `${STATUS_CODE_LINE_CLASSNAME}_number${classNameSuffix}`,
},
});
lastResponseEndLine += (response.value as string).split(/\\n|\n/).length;
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export function sendRequest(args: RequestArgs): Promise<RequestResult[]> {

if (isMultiRequest) {
const lineNumber = req.lineNumber ? `${req.lineNumber}: ` : '';
value = `# ${lineNumber}${req.method} ${req.url} ${statusCode} ${statusText}\n${value}`;
value = `# ${lineNumber}${req.method} ${req.url} [${statusCode} ${statusText}]\n${value}`;
}

results.push({
Expand Down Expand Up @@ -164,7 +164,8 @@ export function sendRequest(args: RequestArgs): Promise<RequestResult[]> {
}

if (isMultiRequest) {
value = `# ${req.method} ${req.url} ${statusCode} ${statusText}\n${value}`;
const lineNumber = req.lineNumber ? `${req.lineNumber}: ` : '';
value = `# ${lineNumber}${req.method} ${req.url} [${statusCode} ${statusText}]\n${value}`;
}

const result = {
Expand Down
Loading

0 comments on commit 61d0b7f

Please sign in to comment.