forked from elastic/kibana
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Console Monaco] Improve highlighting for status codes in multiple re…
…sponses (elastic#189210) Closes elastic#184010 ## Summary This PR adds color badges for the status codes in the output panel when there are multiple responses. https://github.com/user-attachments/assets/be07b34d-7d04-4448-bf5d-b0d6fa36f2d7 **How to test:** Send the following requests at once (try arranging them in different orders): Success badge 🟢 : `GET _search` Client error (warning) badge 🟡 : `GET _test` Server error (danger) badge 🔴 : ``` PUT /library/_bulk?refresh {"index":{"_id":"Leviathan Wakes"}} {"name":"Leviathan Wakes","author":"James S.A. Corey","release_date":"2011-06-02","page_count":561} ``` ^ This request should usually succeed and it was fixed in elastic#188552, but these changes aren't in this branch yet so the request still fails. I couldn't find another example that returns a 5** status code. Note: AFAIK Es currently only uses 2**, 4**, and 5** status codes (200 OK, 201 Created, 202 Accepted, 204 No Content, 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 409 Conflict, 429 Too Many Requests, 500 Internal Server Error, 503 Service Unavailable). Practically only the success, warning, and danger badges will be used, but added badges for the rest status codes in case they are added in Es.
- Loading branch information
1 parent
183a2ea
commit 495bb30
Showing
8 changed files
with
346 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
197 changes: 197 additions & 0 deletions
197
...le/public/application/containers/editor/monaco/utils/status_code_decoration_utils.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
import { getStatusCodeDecorations } from './status_code_decoration_utils'; | ||
import { | ||
SUCCESS_STATUS_BADGE_CLASSNAME, | ||
WARNING_STATUS_BADGE_CLASSNAME, | ||
DANGER_STATUS_BADGE_CLASSNAME, | ||
} from './constants'; | ||
import { RequestResult } from '../../../../hooks/use_send_current_request/send_request'; | ||
|
||
describe('getStatusCodeDecorations', () => { | ||
it('correctly returns all decorations on full data', () => { | ||
// Sample multiple-response data returned from ES: | ||
// 1 # GET _search 200 OK | ||
// 2 { | ||
// 3 "took": 1, | ||
// 4 "timed_out": false, | ||
// 5 "hits": { | ||
// 6 "total": { | ||
// 7 "value": 0, | ||
// 8 "relation": "eq" | ||
// 9 } | ||
// 10 } | ||
// 11 } | ||
// 12 # GET _test 400 Bad Request | ||
// 13 { | ||
// 14 "error": { | ||
// 15 "root_cause": [], | ||
// 16 "status": 400 | ||
// 17 } | ||
// 18 # PUT /library/_bulk 500 Internal Server Error | ||
// 19 { | ||
// 20 "error": { | ||
// 21 "root_cause": [], | ||
// 22 "status": 500 | ||
// 23 } | ||
const SAMPLE_COMPLETE_DATA: RequestResult[] = [ | ||
{ | ||
response: { | ||
timeMs: 50, | ||
statusCode: 200, | ||
statusText: 'OK', | ||
contentType: 'application/json', | ||
value: | ||
'# GET _search 200 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, | ||
statusCode: 500, | ||
statusText: 'Internal Server Error', | ||
contentType: 'application/json', | ||
value: | ||
'# PUT /library/_bulk 500 Internal Server Error\n{\n"error": {\n"root_cause": [],\n"status": 500\n}', | ||
}, | ||
request: { | ||
data: '', | ||
method: 'PUT', | ||
path: '/library/_bulk?refresh', | ||
}, | ||
}, | ||
]; | ||
|
||
const EXPECTED_DECORATIONS = [ | ||
{ | ||
range: { | ||
endColumn: 21, | ||
endLineNumber: 1, | ||
startColumn: 15, | ||
startLineNumber: 1, | ||
}, | ||
options: { | ||
inlineClassName: SUCCESS_STATUS_BADGE_CLASSNAME, | ||
}, | ||
}, | ||
{ | ||
range: { | ||
endColumn: 28, | ||
endLineNumber: 12, | ||
startColumn: 13, | ||
startLineNumber: 12, | ||
}, | ||
options: { | ||
inlineClassName: WARNING_STATUS_BADGE_CLASSNAME, | ||
}, | ||
}, | ||
{ | ||
range: { | ||
endColumn: 47, | ||
endLineNumber: 18, | ||
startColumn: 22, | ||
startLineNumber: 18, | ||
}, | ||
options: { | ||
inlineClassName: DANGER_STATUS_BADGE_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); | ||
}); | ||
}); |
65 changes: 65 additions & 0 deletions
65
...console/public/application/containers/editor/monaco/utils/status_code_decoration_utils.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
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'; | ||
|
||
const getStatusCodeClassName = (statusCode: number) => { | ||
if (statusCode <= 199) { | ||
return DEFAULT_STATUS_BADGE_CLASSNAME; | ||
} | ||
if (statusCode <= 299) { | ||
return SUCCESS_STATUS_BADGE_CLASSNAME; | ||
} | ||
if (statusCode <= 399) { | ||
return PRIMARY_STATUS_BADGE_CLASSNAME; | ||
} | ||
if (statusCode <= 499) { | ||
return WARNING_STATUS_BADGE_CLASSNAME; | ||
} | ||
return DANGER_STATUS_BADGE_CLASSNAME; | ||
}; | ||
|
||
export const getStatusCodeDecorations = (data: RequestResult[]) => { | ||
const decorations: monaco.editor.IModelDeltaDecoration[] = []; | ||
let lastResponseEndLine = 0; | ||
|
||
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), | ||
}, | ||
}); | ||
} | ||
lastResponseEndLine += (response.value as string).split(/\\n|\n/).length; | ||
} | ||
}); | ||
|
||
return decorations; | ||
}; |
Oops, something went wrong.