diff --git a/frontend/src/components/QueryEditor.external-sql-save.test.tsx b/frontend/src/components/QueryEditor.external-sql-save.test.tsx
index 199271b..2570da8 100644
--- a/frontend/src/components/QueryEditor.external-sql-save.test.tsx
+++ b/frontend/src/components/QueryEditor.external-sql-save.test.tsx
@@ -7227,8 +7227,9 @@ describe('QueryEditor external SQL save', () => {
expect(transactionSettingsSource).toContain('query_editor.transaction.mode.auto');
expect(transactionSettingsSource).not.toContain("label: '手动提交'");
expect(transactionSettingsSource).not.toContain("label: '自动提交'");
- expect(transactionSettingsSource).toContain('query_editor.transaction.delay.immediate');
- expect(transactionSettingsSource).toContain("label: '3s'");
+ expect(transactionSettingsSource).toContain('query_editor.transaction.delay.immediate_commit');
+ expect(transactionSettingsSource).toContain('query_editor.transaction.delay.seconds_commit');
+ expect(transactionSettingsSource).not.toContain("label: '3s'");
expect(source).toContain('QueryEditorTransactionToolbar');
expect(transactionToolbarSource).toContain("className={isV2Ui ? 'gn-v2-query-transaction-toolbar' : undefined}");
expect(transactionToolbarSource).toContain(": null;");
@@ -7255,8 +7256,8 @@ describe('QueryEditor external SQL save', () => {
expect(css).toContain('body[data-ui-version="v2"] .gn-v2-query-toolbar-selects');
expect(css).toContain('body[data-ui-version="v2"] .gn-v2-query-toolbar-actions');
- expect(css).toContain('width: 74px !important;');
- expect(css).toContain('width: 62px !important;');
+ expect(css).toContain('width: 78px !important;');
+ expect(css).toContain('width: 104px !important;');
expect(css).toContain('flex: 0 0 auto !important;');
expect(css).toContain('justify-content: flex-start;');
expect(css).toContain('height: 32px !important;');
diff --git a/frontend/src/components/QueryEditor.results-and-drop.test.tsx b/frontend/src/components/QueryEditor.results-and-drop.test.tsx
index f83cb4e..6da266a 100644
--- a/frontend/src/components/QueryEditor.results-and-drop.test.tsx
+++ b/frontend/src/components/QueryEditor.results-and-drop.test.tsx
@@ -2553,8 +2553,9 @@ describe('QueryEditor external SQL save', () => {
expect(transactionSettingsSource).toContain('query_editor.transaction.mode.auto');
expect(transactionSettingsSource).not.toContain("label: '手动提交'");
expect(transactionSettingsSource).not.toContain("label: '自动提交'");
- expect(transactionSettingsSource).toContain('query_editor.transaction.delay.immediate');
- expect(transactionSettingsSource).toContain("label: '3s'");
+ expect(transactionSettingsSource).toContain('query_editor.transaction.delay.immediate_commit');
+ expect(transactionSettingsSource).toContain('query_editor.transaction.delay.seconds_commit');
+ expect(transactionSettingsSource).not.toContain("label: '3s'");
expect(source).toContain('QueryEditorTransactionToolbar');
expect(transactionToolbarSource).toContain("className={isV2Ui ? 'gn-v2-query-transaction-toolbar' : undefined}");
expect(transactionToolbarSource).toContain(": null;");
@@ -2581,8 +2582,8 @@ describe('QueryEditor external SQL save', () => {
expect(css).toContain('body[data-ui-version="v2"] .gn-v2-query-toolbar-selects');
expect(css).toContain('body[data-ui-version="v2"] .gn-v2-query-toolbar-actions');
- expect(css).toContain('width: 74px !important;');
- expect(css).toContain('width: 62px !important;');
+ expect(css).toContain('width: 78px !important;');
+ expect(css).toContain('width: 104px !important;');
expect(css).toContain('flex: 0 0 auto !important;');
expect(css).toContain('justify-content: flex-start;');
expect(css).toContain('height: 32px !important;');
diff --git a/frontend/src/components/QueryEditorToolbar.layout.test.tsx b/frontend/src/components/QueryEditorToolbar.layout.test.tsx
index 38dcc78..0f33e0d 100644
--- a/frontend/src/components/QueryEditorToolbar.layout.test.tsx
+++ b/frontend/src/components/QueryEditorToolbar.layout.test.tsx
@@ -62,4 +62,21 @@ describe('QueryEditorToolbar layout', () => {
expect(commitHoverCss).toContain('box-shadow:');
expect(commitKbdHoverCss).toContain('background:');
});
+
+ it('keeps transaction selects wide enough for localized auto-commit labels', () => {
+ const css = readV2ThemeCss();
+ const transactionModeCss = css.slice(
+ css.indexOf('body[data-ui-version="v2"] .gn-v2-query-toolbar-transaction-mode-select {'),
+ css.indexOf('body[data-ui-version="v2"] .gn-v2-query-toolbar-transaction-delay-select {'),
+ );
+ const transactionDelayCss = css.slice(
+ css.indexOf('body[data-ui-version="v2"] .gn-v2-query-toolbar-transaction-delay-select {'),
+ css.indexOf('body[data-ui-version="v2"] .gn-v2-query-toolbar .ant-select-selector {'),
+ );
+
+ expect(transactionModeCss).toContain('width: 78px !important;');
+ expect(transactionModeCss).toContain('flex: 0 0 78px !important;');
+ expect(transactionDelayCss).toContain('width: 104px !important;');
+ expect(transactionDelayCss).toContain('flex: 0 0 104px !important;');
+ });
});
diff --git a/frontend/src/components/QueryEditorTransaction.i18n.test.ts b/frontend/src/components/QueryEditorTransaction.i18n.test.ts
index e289205..ba600b6 100644
--- a/frontend/src/components/QueryEditorTransaction.i18n.test.ts
+++ b/frontend/src/components/QueryEditorTransaction.i18n.test.ts
@@ -20,6 +20,8 @@ const toolbarLegacyLiterals = [
const requiredKeys = [
'query_editor.transaction.delay.immediate',
+ 'query_editor.transaction.delay.immediate_commit',
+ 'query_editor.transaction.delay.seconds_commit',
'query_editor.transaction.mode.tooltip',
'query_editor.transaction.mode.manual',
'query_editor.transaction.mode.auto',
diff --git a/frontend/src/components/QueryEditorTransactionSettings.test.tsx b/frontend/src/components/QueryEditorTransactionSettings.test.tsx
new file mode 100644
index 0000000..d850990
--- /dev/null
+++ b/frontend/src/components/QueryEditorTransactionSettings.test.tsx
@@ -0,0 +1,74 @@
+import React from 'react';
+import { act, create, type ReactTestRenderer } from 'react-test-renderer';
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
+
+import QueryEditorTransactionSettings from './QueryEditorTransactionSettings';
+
+const antdState = vi.hoisted(() => ({
+ selectProps: [] as any[],
+ tooltipProps: [] as any[],
+}));
+
+vi.mock('antd', () => ({
+ Select: (props: any) => {
+ antdState.selectProps.push(props);
+ return ;
+ },
+ Tooltip: (props: any) => {
+ antdState.tooltipProps.push(props);
+ return
{props.children}
;
+ },
+}));
+
+vi.mock('../i18n/provider', () => ({
+ useOptionalI18n: () => ({
+ t: (key: string, params?: Record) => params?.seconds ? `${params.seconds}s后提交` : key,
+ }),
+}));
+
+const latestSelectProps = () => antdState.selectProps[antdState.selectProps.length - 1];
+const latestTooltipProps = () => antdState.tooltipProps[antdState.tooltipProps.length - 1];
+
+describe('QueryEditorTransactionSettings', () => {
+ let renderer: ReactTestRenderer | null = null;
+
+ beforeEach(() => {
+ antdState.selectProps = [];
+ antdState.tooltipProps = [];
+ });
+
+ afterEach(() => {
+ renderer?.unmount();
+ renderer = null;
+ });
+
+ it('hides the DBeaver reference tooltip while the transaction mode select is open', () => {
+ act(() => {
+ renderer = create(
+ ,
+ );
+ });
+
+ act(() => {
+ latestTooltipProps().onOpenChange(true);
+ });
+ expect(latestTooltipProps().open).toBe(true);
+
+ act(() => {
+ latestSelectProps().onOpenChange(true);
+ });
+ expect(latestTooltipProps().open).toBe(false);
+
+ act(() => {
+ latestSelectProps().onOpenChange(false);
+ latestTooltipProps().onOpenChange(true);
+ });
+ expect(latestTooltipProps().open).toBe(true);
+ });
+});
diff --git a/frontend/src/components/QueryEditorTransactionSettings.tsx b/frontend/src/components/QueryEditorTransactionSettings.tsx
index a52c083..9af9fef 100644
--- a/frontend/src/components/QueryEditorTransactionSettings.tsx
+++ b/frontend/src/components/QueryEditorTransactionSettings.tsx
@@ -8,18 +8,14 @@ export type SqlEditorCommitMode = 'manual' | 'auto';
type SqlEditorAutoCommitDelayOption = {
value: number;
- label: string;
-} | {
- value: number;
- labelKey: string;
};
export const SQL_EDITOR_AUTO_COMMIT_DELAY_OPTIONS: SqlEditorAutoCommitDelayOption[] = [
- { value: 0, labelKey: 'query_editor.transaction.delay.immediate' },
- { value: 3000, label: '3s' },
- { value: 5000, label: '5s' },
- { value: 10000, label: '10s' },
- { value: 30000, label: '30s' },
+ { value: 0 },
+ { value: 3000 },
+ { value: 5000 },
+ { value: 10000 },
+ { value: 30000 },
];
type QueryEditorTransactionSettingsProps = {
@@ -39,18 +35,36 @@ const QueryEditorTransactionSettings: React.FC {
const i18n = useOptionalI18n();
const t = i18n?.t ?? defaultTranslate;
+ const [isModeSelectOpen, setIsModeSelectOpen] = React.useState(false);
+ const [isModeTooltipOpen, setIsModeTooltipOpen] = React.useState(false);
const autoCommitDelayOptions = SQL_EDITOR_AUTO_COMMIT_DELAY_OPTIONS.map((option) => ({
value: option.value,
- label: 'labelKey' in option ? t(option.labelKey) : option.label,
+ label: option.value === 0
+ ? t('query_editor.transaction.delay.immediate_commit')
+ : t('query_editor.transaction.delay.seconds_commit', { seconds: Math.round(option.value / 1000) }),
}));
+ const handleModeSelectOpenChange = (open: boolean) => {
+ setIsModeSelectOpen(open);
+ if (open) {
+ setIsModeTooltipOpen(false);
+ }
+ };
+ const handleModeTooltipOpenChange = (open: boolean) => {
+ setIsModeTooltipOpen(open);
+ };
return (
<>
-
+