diff --git a/packages/kbn-monaco/src/console/lexer_rules/console_output.ts b/packages/kbn-monaco/src/console/lexer_rules/console_output.ts index c9ebd0cb6e876..30b846d529fe5 100644 --- a/packages/kbn-monaco/src/console/lexer_rules/console_output.ts +++ b/packages/kbn-monaco/src/console/lexer_rules/console_output.ts @@ -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'), ], }, }; diff --git a/packages/kbn-monaco/src/console/theme.ts b/packages/kbn-monaco/src/console/theme.ts index bcb3d93368018..6f5a1e78618fb 100644 --- a/packages/kbn-monaco/src/console/theme.ts +++ b/packages/kbn-monaco/src/console/theme.ts @@ -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 { @@ -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, + }, }; }; diff --git a/src/plugins/console/public/application/containers/editor/utils/constants.ts b/src/plugins/console/public/application/containers/editor/utils/constants.ts index f97c9b4ef1d69..e6e5c1f622366 100644 --- a/src/plugins/console/public/application/containers/editor/utils/constants.ts +++ b/src/plugins/console/public/application/containers/editor/utils/constants.ts @@ -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/; diff --git a/src/plugins/console/public/application/containers/editor/utils/index.ts b/src/plugins/console/public/application/containers/editor/utils/index.ts index 1e58b3dc7fd71..d5c10cae6bdb3 100644 --- a/src/plugins/console/public/application/containers/editor/utils/index.ts +++ b/src/plugins/console/public/application/containers/editor/utils/index.ts @@ -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, diff --git a/src/plugins/console/public/application/containers/editor/utils/status_code_decoration_utils.test.ts b/src/plugins/console/public/application/containers/editor/utils/status_code_decoration_utils.test.ts index 8ea919257cb26..b93dd4d0a211b 100644 --- a/src/plugins/console/public/application/containers/editor/utils/status_code_decoration_utils.test.ts +++ b/src/plugins/console/public/application/containers/editor/utils/status_code_decoration_utils.test.ts @@ -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: @@ -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); - }); }); diff --git a/src/plugins/console/public/application/containers/editor/utils/status_code_decoration_utils.ts b/src/plugins/console/public/application/containers/editor/utils/status_code_decoration_utils.ts index 01b87abb2fdf5..daa7052223494 100644 --- a/src/plugins/console/public/application/containers/editor/utils/status_code_decoration_utils.ts +++ b/src/plugins/console/public/application/containers/editor/utils/status_code_decoration_utils.ts @@ -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[]) => { @@ -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; } }); diff --git a/src/plugins/console/public/application/hooks/use_send_current_request/send_request.ts b/src/plugins/console/public/application/hooks/use_send_current_request/send_request.ts index 101831300cb89..40f440eccd7ce 100644 --- a/src/plugins/console/public/application/hooks/use_send_current_request/send_request.ts +++ b/src/plugins/console/public/application/hooks/use_send_current_request/send_request.ts @@ -130,7 +130,7 @@ export function sendRequest(args: RequestArgs): Promise { 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({ @@ -164,7 +164,8 @@ export function sendRequest(args: RequestArgs): Promise { } 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 = { diff --git a/src/plugins/console/public/styles/_app.scss b/src/plugins/console/public/styles/_app.scss index 74367c32a468e..51fb701a57b46 100644 --- a/src/plugins/console/public/styles/_app.scss +++ b/src/plugins/console/public/styles/_app.scss @@ -203,29 +203,44 @@ max-width: 100%; } -.monaco__status_badge--primary { - @extend %monaco__status_badge; - background-color: $euiColorVis1; +.monaco__status_code_line--primary { + background-color: transparentize($euiColorVis1, .9); } -.monaco__status_badge--success { - @extend %monaco__status_badge; - background-color: $euiColorSuccess; +.monaco__status_code_line_number--primary { + background-color: transparentize($euiColorVis1, .5); } -.monaco__status_badge--default { - @extend %monaco__status_badge; - background-color: $euiColorLightShade; +.monaco__status_code_line--success { + background-color: transparentize($euiColorSuccess, .9); } -.monaco__status_badge--warning { - @extend %monaco__status_badge; - background-color: $euiColorWarning; +.monaco__status_code_line_number--success { + background-color: transparentize($euiColorSuccess, .5); } -.monaco__status_badge--danger { - @extend %monaco__status_badge; - background-color: $euiColorDanger; +.monaco__status_code_line--default { + background-color: transparentize($euiColorLightShade, .9); +} + +.monaco__status_code_line_number--default { + background-color: transparentize($euiColorLightShade, .5); +} + +.monaco__status_code_line--warning { + background-color: transparentize($euiColorWarning, .9); +} + +.monaco__status_code_line_number--warning { + background-color: transparentize($euiColorWarning, .5); +} + +.monaco__status_code_line--danger { + background-color: transparentize($euiColorDanger, .9); +} + +.monaco__status_code_line_number--danger { + background-color: transparentize($euiColorDanger, .5); } /* diff --git a/test/functional/apps/console/_console.ts b/test/functional/apps/console/_console.ts index ffba2a7ac41c4..0d0d31b12aaa9 100644 --- a/test/functional/apps/console/_console.ts +++ b/test/functional/apps/console/_console.ts @@ -203,8 +203,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await retry.try(async () => { const response = await PageObjects.console.getOutputText(); log.debug(response); - expect(response).to.contain('# 2: PUT test-index 200'); - expect(response).to.contain('# 3: DELETE test-index 200'); + expect(response).to.contain('# 2: PUT test-index [200 OK]'); + expect(response).to.contain('# 3: DELETE test-index [200 OK]'); }); }); diff --git a/test/functional/apps/console/_output_panel.ts b/test/functional/apps/console/_output_panel.ts index 8aa548ce4b139..49c41ae7a6ccc 100644 --- a/test/functional/apps/console/_output_panel.ts +++ b/test/functional/apps/console/_output_panel.ts @@ -65,7 +65,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await sendMultipleRequests(['\n GET /_search?pretty', '\n GET /_search?pretty']); const response = await PageObjects.console.getOutputText(); - expect(response).to.contain('# 2: GET /_search?pretty'); + expect(response).to.contain('# 2: GET /_search?pretty [200 OK]'); }); it('should clear the console output', async () => {