Skip to content

Commit e785329

Browse files
committed
[Console] Fix method suggestion order (#270787)
Closes #259251 ## Summary - Pins Console HTTP method completion ordering with explicit `sortText` values so Monaco does not fall back to alphabetical label sorting. - Keeps the existing method set unchanged while ordering `GET` first and `DELETE` last. ## Root Cause - Monaco uses `sortText` for completion ordering and falls back to the item label when `sortText` is missing, which can put `DELETE` before safer/default verbs. ## Fix - Assign stable `sortText` values to method completion items based on the intended canonical order. - Add a focused unit test that sorts method suggestions the same way and verifies `GET` is first and `DELETE` is last. ## Before <img width="723" height="466" alt="image" src="https://github.com/user-attachments/assets/faf244b2-4207-483b-acbc-32b148441b18" /> ## After <img width="725" height="437" alt="image" src="https://github.com/user-attachments/assets/782c0c60-6052-4c28-80bc-f45403fa1383" /> ## Test Plan - `node scripts/jest --config=src/platform/plugins/shared/console/jest.config.js src/platform/plugins/shared/console/public/application/containers/editor/monaco_editor_actions_provider.test.ts` — passed. - `node scripts/check_changes.ts` — passed. ## Release Note - Fixes Console autocomplete so `GET` is shown before `DELETE` when suggesting HTTP methods on an empty request line. Assisted with Cursor using GPT-5.5 Made with [Cursor](https://cursor.com) Co-authored-by: Cursor <cursoragent@cursor.com> (cherry picked from commit 8849fcf) # Conflicts: # src/platform/plugins/shared/console/public/application/containers/editor/monaco_editor_actions_provider.test.ts
1 parent a67f761 commit e785329

2 files changed

Lines changed: 27 additions & 3 deletions

File tree

src/platform/plugins/shared/console/public/application/containers/editor/monaco_editor_actions_provider.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,24 @@ describe('Editor actions provider', () => {
277277
);
278278
});
279279

280+
it('orders method suggestions with GET first and DELETE last using sortText', async () => {
281+
// Monaco sorts completion items by sortText, falling back to label. Without
282+
// an explicit sortText, alphabetical sorting puts DELETE first (#259251).
283+
mockGetParsedRequests.mockResolvedValue([]);
284+
const completionItems = await editorActionsProvider.provideCompletionItems(
285+
mockModel,
286+
mockPosition,
287+
mockContext
288+
);
289+
const sortedByMonaco = [...(completionItems?.suggestions ?? [])].sort((a, b) =>
290+
String(a.sortText ?? a.label).localeCompare(String(b.sortText ?? b.label))
291+
);
292+
const orderedLabels = sortedByMonaco.map((s) => s.label);
293+
expect(orderedLabels[0]).toBe('GET');
294+
expect(orderedLabels[orderedLabels.length - 1]).toBe('DELETE');
295+
expect(orderedLabels).toEqual(['GET', 'POST', 'PUT', 'PATCH', 'HEAD', 'DELETE']);
296+
});
297+
280298
it('returns completion items for url path if method already typed in', async () => {
281299
// mock a parsed request that only has a method
282300
mockGetParsedRequests.mockResolvedValue([

src/platform/plugins/shared/console/public/application/containers/editor/utils/autocomplete_utils.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,21 +62,27 @@ const filterTermsWithoutName = (terms: ResultTerm[]): ResultTerm[] =>
6262
terms.filter((term) => term.name !== undefined && term.name !== '');
6363

6464
/*
65-
* This function returns an array of completion items for the request method
65+
* This function returns an array of completion items for the request method.
66+
*
67+
* The order is deliberate: Monaco sorts completion items by `sortText` and
68+
* falls back to alphabetical label sorting, which would otherwise put DELETE
69+
* first (#259251). GET is the safest verb to accept by default and DELETE
70+
* the most destructive, so we pin GET first and DELETE last.
6671
*/
67-
const autocompleteMethods = ['GET', 'PUT', 'POST', 'DELETE', 'HEAD', 'PATCH'];
72+
const autocompleteMethods = ['GET', 'POST', 'PUT', 'PATCH', 'HEAD', 'DELETE'];
6873
export const getMethodCompletionItems = (
6974
model: monaco.editor.ITextModel,
7075
position: monaco.Position
7176
): monaco.languages.CompletionItem[] => {
7277
// get the word before suggestions to replace when selecting a suggestion from the list
7378
const wordUntilPosition = model.getWordUntilPosition(position);
74-
return autocompleteMethods.map((method) => ({
79+
return autocompleteMethods.map((method, index) => ({
7580
label: method,
7681
insertText: method,
7782
detail: i18nTexts.method,
7883
// only used to configure the icon
7984
kind: monaco.languages.CompletionItemKind.Constant,
85+
sortText: String(index),
8086
range: {
8187
// replace the whole word with the suggestion
8288
startColumn: wordUntilPosition.startColumn,

0 commit comments

Comments
 (0)