mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-08-21 08:22:44 +08:00
Merge pull request #765 from virgosgod-maker/fix/issue-753
This commit is contained in:
@@ -225,6 +225,8 @@ const editorState = vi.hoisted(() => {
|
||||
decorationIds: [] as string[],
|
||||
contentHoverCalls: [] as any[],
|
||||
latestOnChange: null as null | ((value?: string) => void),
|
||||
transformToUppercaseRun: vi.fn(),
|
||||
transformToLowercaseRun: vi.fn(),
|
||||
};
|
||||
const offsetAt = (position: { lineNumber: number; column: number }) => {
|
||||
const text = state.value;
|
||||
@@ -304,6 +306,15 @@ const editorState = vi.hoisted(() => {
|
||||
state.value = state.value.slice(0, start) + edit.text + state.value.slice(end);
|
||||
});
|
||||
}),
|
||||
getAction: vi.fn((id: string) => {
|
||||
if (id === 'editor.action.transformToUppercase') {
|
||||
return { run: state.transformToUppercaseRun };
|
||||
}
|
||||
if (id === 'editor.action.transformToLowercase') {
|
||||
return { run: state.transformToLowercaseRun };
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
addAction: vi.fn(),
|
||||
addCommand: vi.fn(),
|
||||
onDidChangeModelContent: vi.fn((listener: (event?: any) => void) => {
|
||||
@@ -925,6 +936,9 @@ describe('QueryEditor external SQL save', () => {
|
||||
editorState.editor.getModel().getValueLength.mockClear();
|
||||
editorState.editor.setValue.mockClear();
|
||||
editorState.editor.executeEdits.mockClear();
|
||||
editorState.editor.getAction.mockClear();
|
||||
editorState.transformToUppercaseRun.mockReset();
|
||||
editorState.transformToLowercaseRun.mockReset();
|
||||
editorState.editor.getScrollLeft.mockClear();
|
||||
editorState.editor.setScrollLeft.mockClear();
|
||||
editorState.editor.deltaDecorations.mockClear();
|
||||
@@ -4824,6 +4838,36 @@ describe('QueryEditor external SQL save', () => {
|
||||
}));
|
||||
});
|
||||
|
||||
it('registers SQL case conversion context-menu actions and delegates to Monaco', async () => {
|
||||
await act(async () => {
|
||||
create(<QueryEditor tab={createTab()} />);
|
||||
});
|
||||
|
||||
const uppercaseAction = findEditorAction('gonavi.queryEditor.transformToUppercase');
|
||||
const lowercaseAction = findEditorAction('gonavi.queryEditor.transformToLowercase');
|
||||
|
||||
expect(uppercaseAction).toMatchObject({
|
||||
label: '转大写',
|
||||
precondition: '!editorReadonly',
|
||||
contextMenuGroupId: '1_modification',
|
||||
contextMenuOrder: 1,
|
||||
});
|
||||
expect(lowercaseAction).toMatchObject({
|
||||
label: '转小写',
|
||||
precondition: '!editorReadonly',
|
||||
contextMenuGroupId: '1_modification',
|
||||
contextMenuOrder: 2,
|
||||
});
|
||||
|
||||
await uppercaseAction.run(editorState.editor);
|
||||
await lowercaseAction.run(editorState.editor);
|
||||
|
||||
expect(editorState.editor.getAction).toHaveBeenNthCalledWith(1, 'editor.action.transformToUppercase');
|
||||
expect(editorState.editor.getAction).toHaveBeenNthCalledWith(2, 'editor.action.transformToLowercase');
|
||||
expect(editorState.transformToUppercaseRun).toHaveBeenCalledOnce();
|
||||
expect(editorState.transformToLowercaseRun).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it('localizes Monaco action labels for the active language', async () => {
|
||||
setCurrentLanguage('en-US');
|
||||
storeState.shortcutOptions.runQuery.mac = { enabled: true, combo: 'Meta+Q' };
|
||||
@@ -4846,6 +4890,12 @@ describe('QueryEditor external SQL save', () => {
|
||||
expect(findEditorAction('gonavi.insertSqlSnippet')).toMatchObject({
|
||||
label: 'Insert SQL Snippet',
|
||||
});
|
||||
expect(findEditorAction('gonavi.queryEditor.transformToUppercase')).toMatchObject({
|
||||
label: 'convert to uppercase',
|
||||
});
|
||||
expect(findEditorAction('gonavi.queryEditor.transformToLowercase')).toMatchObject({
|
||||
label: 'convert to lowercase',
|
||||
});
|
||||
expect(findEditorAction('gonavi.selectCurrentStatement')).toMatchObject({
|
||||
label: 'GoNavi: Select Current Line and Copy',
|
||||
});
|
||||
@@ -4878,6 +4928,12 @@ describe('QueryEditor external SQL save', () => {
|
||||
expect(findEditorAction('gonavi.insertSqlSnippet')).toMatchObject({
|
||||
label: '插入 SQL 片段',
|
||||
});
|
||||
expect(findEditorAction('gonavi.queryEditor.transformToUppercase')).toMatchObject({
|
||||
label: '转大写',
|
||||
});
|
||||
expect(findEditorAction('gonavi.queryEditor.transformToLowercase')).toMatchObject({
|
||||
label: '转小写',
|
||||
});
|
||||
expect(findEditorAction('gonavi.selectCurrentStatement')).toMatchObject({
|
||||
label: 'GoNavi: 选择当前行并复制',
|
||||
});
|
||||
@@ -4897,6 +4953,8 @@ describe('QueryEditor external SQL save', () => {
|
||||
expect(findEditorActionLabels('gonavi.queryEditor.showObjectInfo')).toContain('GoNavi: Show Object Info');
|
||||
expect(findEditorActionLabels('gonavi.runQuery')).toContain('GoNavi: Run SQL');
|
||||
expect(findEditorActionLabels('gonavi.insertSqlSnippet')).toContain('Insert SQL Snippet');
|
||||
expect(findEditorActionLabels('gonavi.queryEditor.transformToUppercase')).toContain('convert to uppercase');
|
||||
expect(findEditorActionLabels('gonavi.queryEditor.transformToLowercase')).toContain('convert to lowercase');
|
||||
expect(findEditorActionLabels('gonavi.selectCurrentStatement')).toContain('GoNavi: Select Current Line and Copy');
|
||||
expect(findEditorActionLabels('gonavi.duplicateCurrentLine')).toContain('GoNavi: Duplicate Current Line Below');
|
||||
expect(findEditorActionLabels('gonavi.saveQuery')).toContain('GoNavi: Save Query');
|
||||
@@ -4909,6 +4967,12 @@ describe('QueryEditor external SQL save', () => {
|
||||
expect(findEditorAction('gonavi.insertSqlSnippet')).toMatchObject({
|
||||
label: 'Insert SQL Snippet',
|
||||
});
|
||||
expect(findEditorAction('gonavi.queryEditor.transformToUppercase')).toMatchObject({
|
||||
label: 'convert to uppercase',
|
||||
});
|
||||
expect(findEditorAction('gonavi.queryEditor.transformToLowercase')).toMatchObject({
|
||||
label: 'convert to lowercase',
|
||||
});
|
||||
expect(findEditorAction('gonavi.selectCurrentStatement')).toMatchObject({
|
||||
label: 'GoNavi: Select Current Line and Copy',
|
||||
});
|
||||
|
||||
@@ -1365,6 +1365,7 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
|
||||
const triggerSqlAiCompletionActionRef = useRef<any>(null);
|
||||
const triggerSqlAiCompletionKeydownDisposableRef = useRef<any>(null);
|
||||
const insertSqlSnippetActionRef = useRef<any>(null);
|
||||
const transformCaseActionDisposablesRef = useRef<any[]>([]);
|
||||
const aiContextMenuActionDisposablesRef = useRef<any[]>([]);
|
||||
const toggleQueryResultsPanelActionRef = useRef<any>(null);
|
||||
const lastExternalQueryRef = useRef<string>(getTabQueryValue(tab));
|
||||
@@ -1629,6 +1630,36 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
|
||||
});
|
||||
}, [handleOpenSqlSnippetPicker]);
|
||||
|
||||
const disposeTransformCaseContextMenuActions = useCallback(() => {
|
||||
transformCaseActionDisposablesRef.current.forEach((disposable) => disposable?.dispose?.());
|
||||
transformCaseActionDisposablesRef.current = [];
|
||||
}, []);
|
||||
|
||||
const registerTransformCaseContextMenuActions = useCallback((editor: any) => {
|
||||
disposeTransformCaseContextMenuActions();
|
||||
transformCaseActionDisposablesRef.current = [
|
||||
{
|
||||
id: 'gonavi.queryEditor.transformToUppercase',
|
||||
label: translate('query_editor.completion.action.uppercase'),
|
||||
actionId: 'editor.action.transformToUppercase',
|
||||
contextMenuOrder: 1,
|
||||
},
|
||||
{
|
||||
id: 'gonavi.queryEditor.transformToLowercase',
|
||||
label: translate('query_editor.completion.action.lowercase'),
|
||||
actionId: 'editor.action.transformToLowercase',
|
||||
contextMenuOrder: 2,
|
||||
},
|
||||
].map((action) => editor.addAction({
|
||||
id: action.id,
|
||||
label: action.label,
|
||||
precondition: '!editorReadonly',
|
||||
contextMenuGroupId: '1_modification',
|
||||
contextMenuOrder: action.contextMenuOrder,
|
||||
run: (ed: any) => ed.getAction?.(action.actionId)?.run?.(),
|
||||
}));
|
||||
}, [disposeTransformCaseContextMenuActions]);
|
||||
|
||||
// SQL 诊断 / 慢 SQL 历史的快捷键监听(必须在 binding 声明之后)
|
||||
useEffect(() => {
|
||||
if (!isActive) return;
|
||||
@@ -4795,6 +4826,7 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
|
||||
sharedActiveEditorModelUri = '';
|
||||
}
|
||||
disposeQueryEditorAiContextMenuActions();
|
||||
disposeTransformCaseContextMenuActions();
|
||||
window.removeEventListener('keydown', syncModifierState);
|
||||
window.removeEventListener('keyup', syncModifierState);
|
||||
window.removeEventListener('blur', handleWindowBlur);
|
||||
@@ -4811,6 +4843,7 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
|
||||
// 注册 AI 右键菜单操作
|
||||
registerQueryEditorAiContextMenuActions(editor);
|
||||
registerInsertSqlSnippetContextMenuAction(editor);
|
||||
registerTransformCaseContextMenuActions(editor);
|
||||
registerTriggerSqlAiCompletionAction(editor, monaco);
|
||||
|
||||
// Register runQuery shortcut inside Monaco so it overrides Monaco's default keybinding
|
||||
@@ -7739,6 +7772,17 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
|
||||
};
|
||||
}, [languagePreference, registerInsertSqlSnippetContextMenuAction]);
|
||||
|
||||
useEffect(() => {
|
||||
const editor = editorRef.current;
|
||||
if (!editor) return;
|
||||
|
||||
registerTransformCaseContextMenuActions(editor);
|
||||
|
||||
return () => {
|
||||
disposeTransformCaseContextMenuActions();
|
||||
};
|
||||
}, [languagePreference, disposeTransformCaseContextMenuActions, registerTransformCaseContextMenuActions]);
|
||||
|
||||
useEffect(() => {
|
||||
const editor = editorRef.current;
|
||||
const monaco = monacoRef.current;
|
||||
|
||||
Reference in New Issue
Block a user