🐛 fix(query-editor): 修复SQL AI补全误触普通补全

This commit is contained in:
Syngnat
2026-07-06 17:26:41 +08:00
parent 2fc587fd31
commit 22697baa37
4 changed files with 45 additions and 14 deletions

View File

@@ -1498,7 +1498,7 @@ describe('QueryEditor external SQL save', () => {
expect(editorState.value).toBe('SELECT * FROM ');
});
it('uses structured SQL suggestions instead of freeform AI when manual completion is triggered in table-name context', async () => {
it('does not fall back to structured SQL suggestions when manual AI completion is triggered in table-name context', async () => {
backendApp.DBGetTables.mockResolvedValueOnce({
success: true,
data: [
@@ -1566,7 +1566,7 @@ describe('QueryEditor external SQL save', () => {
}
});
expect(editorState.editor.trigger).toHaveBeenCalledWith(
expect(editorState.editor.trigger).not.toHaveBeenCalledWith(
'gonavi-ai-inline-manual',
'editor.action.triggerSuggest',
undefined,
@@ -1962,7 +1962,7 @@ describe('QueryEditor external SQL save', () => {
}
});
it('strips a stray backslash before opening manual table suggestions from the toolbar AI button', async () => {
it('strips a stray backslash before keeping manual toolbar AI completion on the AI path', async () => {
backendApp.DBGetTables.mockResolvedValueOnce({
success: true,
data: [
@@ -2013,7 +2013,39 @@ describe('QueryEditor external SQL save', () => {
})],
);
expect(editorState.value).toBe('SELECT * FROM ');
expect(editorState.editor.trigger).toHaveBeenCalledWith(
expect(editorState.editor.trigger).not.toHaveBeenCalledWith(
'gonavi-ai-inline-manual',
'editor.action.triggerSuggest',
undefined,
);
});
it('keeps the AI dropdown completion action on the AI path instead of opening plain suggestions', async () => {
backendApp.DBGetTables.mockResolvedValueOnce({
success: true,
data: [
{ TABLE_NAME: 'videos' },
{ TABLE_NAME: 'visits' },
],
});
let renderer: ReactTestRenderer;
await act(async () => {
renderer = create(<QueryEditor tab={createTab({ query: 'SELECT * FROM ', dbName: 'main' })} />);
});
editorState.value = 'SELECT * FROM ';
editorState.position = { lineNumber: 1, column: 'SELECT * FROM '.length + 1 };
editorState.editor.trigger.mockClear();
await act(async () => {
findButton(renderer!, '触发 SQL AI 自动补全').props.onClick();
for (let i = 0; i < 8; i += 1) {
await Promise.resolve();
}
});
expect(editorState.editor.trigger).not.toHaveBeenCalledWith(
'gonavi-ai-inline-manual',
'editor.action.triggerSuggest',
undefined,

View File

@@ -3599,17 +3599,14 @@ const QueryEditor: React.FC<{ tab: TabData; isActive?: boolean }> = ({ tab, isAc
return;
}
if (!insertText.trim()) {
if (intent.intent === 'table_name' || intent.intent === 'column_name') {
const shouldTriggerStructuredSuggest = manualTrigger
|| shouldTriggerQueryEditorInlineObjectSuggestFallback({
aiContext: buildQueryEditorAiContext(),
editorSnapshot,
});
// Keep the manual AI action on the AI path; silently downgrading to plain suggest is misleading.
if (!manualTrigger && (intent.intent === 'table_name' || intent.intent === 'column_name')) {
const shouldTriggerStructuredSuggest = shouldTriggerQueryEditorInlineObjectSuggestFallback({
aiContext: buildQueryEditorAiContext(),
editorSnapshot,
});
if (shouldTriggerStructuredSuggest) {
triggerStructuredSqlSuggest(
manualTrigger ? 'gonavi-ai-inline-manual' : 'gonavi-ai-inline-auto',
!manualTrigger,
);
triggerStructuredSqlSuggest('gonavi-ai-inline-auto', true);
}
}
return;

View File

@@ -8,6 +8,7 @@ describe('QueryEditorToolbar AI trigger affordance', () => {
expect(source).toContain('onMouseDown={onCaptureEditorCursorPosition}');
expect(source).toContain('onClick={onTriggerSqlAiCompletion}');
expect(source).toContain('triggerSqlAiCompletionLabel');
expect(source).toMatch(/aria-label="AI more actions"\s+onMouseDown=\{onCaptureEditorCursorPosition\}/);
});
it('keeps the secondary AI dropdown for other actions', () => {

View File

@@ -400,6 +400,7 @@ const QueryEditorToolbar: React.FC<QueryEditorToolbarProps> = ({
className={isV2Ui ? "gn-v2-query-toolbar-icon-action" : undefined}
icon={<DownOutlined />}
aria-label="AI more actions"
onMouseDown={onCaptureEditorCursorPosition}
/>
</Dropdown>
</div>