diff --git a/frontend/src/components/QueryEditor.external-sql-save.test.tsx b/frontend/src/components/QueryEditor.external-sql-save.test.tsx
index 69a1e6a2..04215b42 100644
--- a/frontend/src/components/QueryEditor.external-sql-save.test.tsx
+++ b/frontend/src/components/QueryEditor.external-sql-save.test.tsx
@@ -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();
+ });
+
+ 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,
diff --git a/frontend/src/components/QueryEditor.tsx b/frontend/src/components/QueryEditor.tsx
index 617fae9f..2cead968 100644
--- a/frontend/src/components/QueryEditor.tsx
+++ b/frontend/src/components/QueryEditor.tsx
@@ -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;
diff --git a/frontend/src/components/QueryEditorToolbar.ai-trigger.test.tsx b/frontend/src/components/QueryEditorToolbar.ai-trigger.test.tsx
index af4bc60f..0c2dfc53 100644
--- a/frontend/src/components/QueryEditorToolbar.ai-trigger.test.tsx
+++ b/frontend/src/components/QueryEditorToolbar.ai-trigger.test.tsx
@@ -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', () => {
diff --git a/frontend/src/components/QueryEditorToolbar.tsx b/frontend/src/components/QueryEditorToolbar.tsx
index 382fccf0..6ea431ff 100644
--- a/frontend/src/components/QueryEditorToolbar.tsx
+++ b/frontend/src/components/QueryEditorToolbar.tsx
@@ -400,6 +400,7 @@ const QueryEditorToolbar: React.FC = ({
className={isV2Ui ? "gn-v2-query-toolbar-icon-action" : undefined}
icon={}
aria-label="AI more actions"
+ onMouseDown={onCaptureEditorCursorPosition}
/>