fix(editor): display configured execute shortcut

This commit is contained in:
Melody Ruch authored and GitHub committed 2026-08-14 14:47:08 +08:00
1 parent 30d13bc7f0
commit df95288aab
11 files changed
+80 -21

No files matched your search

@@ -275,6 +275,11 @@ const editCustomThemes = ref<CustomTheme[]>([...settingsStore.editorSettings.cus
const editActiveCustomThemeId = ref(settingsStore.editorSettings.activeCustomThemeId);
const showThemeCustomizer = ref(false);
const editExecuteMode = ref(settingsStore.editorSettings.executeMode);
const editShortcuts = ref(normalizeShortcutSettings(settingsStore.editorSettings.shortcuts));
function translateWithExecuteShortcut(key: string): string {
return t(key, { shortcut: formatShortcutDisplay(editShortcuts.value.executeSql) });
}
const executeModeLabel = computed(() => translateWithExecuteShortcut("settings.executeMode"));
const editExecuteAllOnBlankLine = ref(settingsStore.editorSettings.executeAllOnBlankLine);
const editShowExecutionTargetPicker = ref(settingsStore.editorSettings.showExecutionTargetPicker);
const editShowStatementRunButtons = ref(settingsStore.editorSettings.showStatementRunButtons);
@@ -379,7 +384,6 @@ function setSqlVariableSyntaxToggle(key: keyof SqlVariableSyntaxToggles, value:
const tableColumnTemplateSectionRef = ref<HTMLElement | null>(null);
const draggedTableColumnTemplateRowId = ref<string | null>(null);
let tableColumnTemplatePointerDragCleanup: (() => void) | null = null;
const editShortcuts = ref(normalizeShortcutSettings(settingsStore.editorSettings.shortcuts));
const editSqlFormatter = ref<SqlFormatterSettings>(normalizeSqlFormatterSettings(settingsStore.editorSettings.sqlFormatter));
const sqlFormatterConfigValid = ref(true);
const editingShortcutId = ref<ShortcutActionId | null>(null);
@@ -1474,7 +1478,7 @@ const settingsSearchEntries = computed(() =>
isWeb,
visibleCategories: new Set(settingsCategoryNav.value.map((category) => category.value)),
},
t,
translateWithExecuteShortcut,
settingsSearchCategoryLabels.value,
),
);
@@ -3681,10 +3685,10 @@ onUnmounted(() => {
<div class="grid gap-4 md:grid-cols-[minmax(0,1fr)_minmax(0,1fr)]">
<div class="space-y-2">
<Label>{{ t("settings.executeMode") }}</Label>
<Label>{{ executeModeLabel }}</Label>
<Select :model-value="editExecuteMode" @update:model-value="onExecuteModeChange">
<SelectTrigger>
<SelectValue :placeholder="t('settings.executeMode')" />
<SelectValue :placeholder="executeModeLabel" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">{{ t("settings.executeModeAll") }}</SelectItem>
@@ -9,6 +9,7 @@ import TruncatedTextTooltip from "@/components/ui/TruncatedTextTooltip.vue";
import DatabaseIcon from "@/components/icons/DatabaseIcon.vue";
import ProductionContextBadge from "@/components/common/ProductionContextBadge.vue";
import { useConnectionStore } from "@/stores/connectionStore";
import { useSettingsStore } from "@/stores/settingsStore";
import { catalogDatabaseOptionsKey, databaseAfterCatalogChange, normalizedQueryTabCatalog, queryCatalogSelectorVisible, selectedQueryCatalogName, useDatabaseOptions } from "@/composables/useDatabaseOptions";
import { useSchemaOptions } from "@/composables/useSchemaOptions";
import { connectionIconType } from "@/lib/connection/connectionPresentation";
@@ -20,6 +21,7 @@ import { supportsQueryExecution } from "@/lib/database/databaseFeatureSupport";
import { connectionIsDorisFamilyCatalogCapable } from "@/lib/database/databaseFeatureSupport";
import { hexToRgba } from "@/lib/common/color";
import { productionContextForDatabase } from "@/lib/database/productionSafety";
import { formatShortcutDisplay } from "@/lib/editor/shortcutDisplay";
import type { QueryTab, ConnectionConfig } from "@/types/database";
const props = defineProps<{
@@ -63,6 +65,7 @@ const emit = defineEmits<{
const { t } = useI18n();
const connectionStore = useConnectionStore();
const settingsStore = useSettingsStore();
const { databaseOptions, loadingDatabaseOptions, loadDatabaseOptions, catalogOptions, loadingCatalogOptions, loadCatalogOptions, catalogDatabaseOptions, loadingCatalogDatabaseOptions, loadCatalogDatabaseOptions } = useDatabaseOptions();
const { loadSchemaOptions, getSchemaOptionsForDb, isLoadingSchemas, isSchemaAware } = useSchemaOptions();
@@ -122,6 +125,8 @@ const supportsTransaction = computed(() => supportsTransactionFeature(props.acti
const hasDefaultDatabaseOption = computed(() => activeDatabaseOptions.value.includes(""));
const schemaDatabaseKey = computed(() => props.activeTab.database || (isSingleDb.value ? "_" : ""));
const saveTooltip = computed(() => (props.activeTab.objectSource ? t("objects.saveSource") : t("toolbar.saveSql")));
const executeShortcutDisplay = computed(() => formatShortcutDisplay(settingsStore.editorSettings.shortcuts.executeSql));
const executeShortcutTooltip = computed(() => t("toolbar.executeShortcut", { shortcut: executeShortcutDisplay.value }));
// DM calls it autotrace, Postgres EXPLAIN ANALYZE, SQL Server the actual execution
// plan (SET STATISTICS XML); all three execute the statement.
const supportsExplainAnalyze = computed(() => {
@@ -261,7 +266,7 @@ async function changeCatalog(selectedCatalog: string) {
<Play v-else class="h-3.5 w-3.5" />
</Button>
</TooltipTrigger>
<TooltipContent>{{ activeTab.isExecuting ? t("toolbar.stopQuery") : t("toolbar.executeShortcut") }}</TooltipContent>
<TooltipContent>{{ activeTab.isExecuting ? t("toolbar.stopQuery") : executeShortcutTooltip }}</TooltipContent>
</Tooltip>
<Tooltip v-if="supportsExplain">
<TooltipTrigger as-child>
@@ -0,0 +1,50 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
import i18n, { setLocale } from "@/i18n";
import { formatShortcutDisplay } from "@/lib/editor/shortcutDisplay";
// https://github.com/t8y2/dbx/issues/6199
// "设置为 Windows 但编辑器提示仍为 Mac" — the toolbar's Execute-button tooltip and the
// Editor Settings "Execute Mode" label hardcode "(Cmd+Enter)" in every locale, including
// English, so the hints can disagree with both the current platform and a customized binding.
const toolbarSource = readFileSync(new URL("../../components/layout/EditorToolbar.vue", import.meta.url), "utf8");
const settingsDialogSource = readFileSync(new URL("../../components/editor/EditorSettingsDialog.vue", import.meta.url), "utf8");
describe("execute-shortcut hints reflect the configured binding", () => {
it.each([
["MacIntel", "Mod+Enter", "⌘ ↵"],
["Win32", "Mod+Enter", "Ctrl + ↵"],
["Linux x86_64", "Mod+Enter", "Ctrl + ↵"],
["Win32", "Shift+Mod+Enter", "Ctrl + Shift + ↵"],
])("formats %s shortcuts for the active platform", (platform, shortcut, expected) => {
expect(formatShortcutDisplay(shortcut, platform)).toBe(expected);
});
it("interpolates the formatted shortcut into toolbar and settings labels", async () => {
const shortcut = formatShortcutDisplay("Shift+Mod+Enter", "Win32");
await setLocale("en");
expect(i18n.global.t("toolbar.executeShortcut", { shortcut })).toBe("Execute selection/query (Ctrl + Shift + ↵)");
expect(i18n.global.t("settings.executeMode", { shortcut })).toBe("Execute Mode (Ctrl + Shift + ↵)");
await setLocale("zh-CN");
expect(i18n.global.t("toolbar.executeShortcut", { shortcut })).toBe("执行选中/全部 (Ctrl + Shift + ↵)");
expect(i18n.global.t("settings.executeMode", { shortcut })).toBe("执行模式 (Ctrl + Shift + ↵)");
await setLocale("en");
});
it("EditorToolbar.vue uses the saved executeSql shortcut", () => {
expect(toolbarSource).toContain("formatShortcutDisplay(settingsStore.editorSettings.shortcuts.executeSql)");
expect(toolbarSource).toMatch(/t\(\s*"toolbar\.executeShortcut"\s*,\s*\{\s*shortcut:\s*executeShortcutDisplay\.value/);
});
it("EditorSettingsDialog.vue uses the currently edited executeSql shortcut", () => {
expect(settingsDialogSource).toMatch(/function translateWithExecuteShortcut\([^)]*\)[^}]*formatShortcutDisplay\(editShortcuts\.value\.executeSql\)/);
expect(settingsDialogSource).toContain('translateWithExecuteShortcut("settings.executeMode")');
});
it("EditorSettingsDialog.vue uses the same edited shortcut in settings search", () => {
expect(settingsDialogSource).toMatch(/resolveSettingsSearchEntries\(\s*\[[^\]]*\]\s*,\s*\{[^}]*\}\s*,\s*translateWithExecuteShortcut\s*,/s);
});
});
+2 -2
View File
@@ -144,7 +144,7 @@ export default {
newConnection: "New Connection",
newQuery: "New Query",
execute: "Execute",
executeShortcut: "Execute selection/query (Cmd+Enter)",
executeShortcut: "Execute selection/query ({shortcut})",
stopQuery: "Stop query",
explainPlan: "Explain plan",
stopExplain: "Stop explain",
@@ -5855,7 +5855,7 @@ export default {
resetAllDefaults: "Reset All Defaults",
save: "Save",
cancel: "Cancel",
executeMode: "Execute Mode (Cmd+Enter)",
executeMode: "Execute Mode ({shortcut})",
executeModeAll: "Execute all SQL",
executeModeCurrent: "Execute statement at cursor",
executeAllOnBlankLine: "Execute all SQL from blank lines",
+2 -2
View File
@@ -145,7 +145,7 @@ export default withEnglishFallback({
newConnection: "Nueva conexión",
newQuery: "Nueva consulta",
execute: "Ejecutar",
executeShortcut: "Ejecutar selección/consulta (Cmd+Enter)",
executeShortcut: "Ejecutar selección/consulta ({shortcut})",
stopQuery: "Detener consulta",
explainPlan: "Plan de ejecución",
stopExplain: "Detener análisis",
@@ -5574,7 +5574,7 @@ export default withEnglishFallback({
resetAllDefaults: "Restablecer todos los valores por defecto",
save: "Guardar",
cancel: "Cancelar",
executeMode: "Modo de ejecución (Cmd+Enter)",
executeMode: "Modo de ejecución ({shortcut})",
executeModeAll: "Ejecutar todo el SQL",
executeModeCurrent: "Ejecutar sentencia en el cursor",
executeAllOnBlankLine: "Ejecutar todo el SQL desde líneas en blanco",
+2 -2
View File
@@ -144,7 +144,7 @@ export default withEnglishFallback({
newConnection: "Nuova Connessione",
newQuery: "Nuova Query",
execute: "Esegui",
executeShortcut: "Esegui selezione/query (Cmd+Enter)",
executeShortcut: "Esegui selezione/query ({shortcut})",
stopQuery: "Interrompi query",
explainPlan: "Spiega piano",
stopExplain: "Interrompi spiegazione",
@@ -5574,7 +5574,7 @@ export default withEnglishFallback({
resetAllDefaults: "Ripristina Tutti i Predefiniti",
save: "Salva",
cancel: "Annulla",
executeMode: "Modalità Esecuzione (Cmd+Enter)",
executeMode: "Modalità Esecuzione ({shortcut})",
executeModeAll: "Esegui tutto l'SQL",
executeModeCurrent: "Esegui istruzione al cursore",
executeAllOnBlankLine: "Esegui tutto l'SQL dalle righe vuote",
+2 -2
View File
@@ -145,7 +145,7 @@ export default withEnglishFallback({
newConnection: "新しい接続",
newQuery: "新しいクエリ",
execute: "実行",
executeShortcut: "選択範囲/クエリを実行 (Cmd+Enter)",
executeShortcut: "選択範囲/クエリを実行 ({shortcut})",
stopQuery: "クエリを停止",
explainPlan: "実行計画を表示",
stopExplain: "実行計画の表示を停止",
@@ -5601,7 +5601,7 @@ export default withEnglishFallback({
resetAllDefaults: "すべての設定をリセット",
save: "保存",
cancel: "キャンセル",
executeMode: "実行モード (Cmd+Enter)",
executeMode: "実行モード ({shortcut})",
executeModeAll: "すべてのSQLを実行",
executeModeCurrent: "カーソル位置の文を実行",
executeAllOnBlankLine: "空行ではすべてのSQLを実行",
+2 -2
View File
@@ -145,7 +145,7 @@ export default withEnglishFallback({
newConnection: "새 연결",
newQuery: "새 쿼리",
execute: "실행",
executeShortcut: "선택 영역/쿼리 실행 (Cmd+Enter)",
executeShortcut: "선택 영역/쿼리 실행 ({shortcut})",
stopQuery: "쿼리 중지",
explainPlan: "실행 계획",
stopExplain: "실행 계획 중지",
@@ -5333,7 +5333,7 @@ export default withEnglishFallback({
resetAllDefaults: "모든 기본값 재설정",
save: "저장",
cancel: "취소",
executeMode: "실행 모드 (Cmd+Enter)",
executeMode: "실행 모드 ({shortcut})",
executeModeAll: "모든 SQL 실행",
executeModeCurrent: "커서 위치의 구문 실행",
executeAllOnBlankLine: "빈 줄에서 모든 SQL 실행",
+2 -2
View File
@@ -145,7 +145,7 @@ export default withEnglishFallback({
newConnection: "Nova Conexão",
newQuery: "Nova Consulta",
execute: "Executar",
executeShortcut: "Executar seleção/consulta (Cmd+Enter)",
executeShortcut: "Executar seleção/consulta ({shortcut})",
stopQuery: "Parar consulta",
explainPlan: "Explicar plano",
stopExplain: "Parar explicação",
@@ -5576,7 +5576,7 @@ export default withEnglishFallback({
resetAllDefaults: "Redefinir todos os padrões",
save: "Salvar",
cancel: "Cancelar",
executeMode: "Modo de execução (Cmd+Enter)",
executeMode: "Modo de execução ({shortcut})",
executeModeAll: "Executar todo o SQL",
executeModeCurrent: "Executar instrução no cursor",
executeAllOnBlankLine: "Executar todo o SQL em linhas em branco",
+2 -2
View File
@@ -69,7 +69,7 @@ export default withEnglishFallback({
newConnection: "新建连接",
newQuery: "新建查询",
execute: "执行",
executeShortcut: "执行选中/全部 (Cmd+Enter)",
executeShortcut: "执行选中/全部 ({shortcut})",
stopQuery: "停止执行",
explainPlan: "执行计划",
stopExplain: "停止执行计划",
@@ -5841,7 +5841,7 @@ export default withEnglishFallback({
resetAllDefaults: "恢复所有默认设置",
save: "保存",
cancel: "取消",
executeMode: "执行模式 (Cmd+Enter)",
executeMode: "执行模式 ({shortcut})",
executeModeAll: "执行全部 SQL",
executeModeCurrent: "执行光标所在语句",
executeAllOnBlankLine: "空白位置执行全部 SQL",
+2 -2
View File
@@ -145,7 +145,7 @@ export default withEnglishFallback({
newConnection: "建立連線",
newQuery: "建立查詢",
execute: "執行",
executeShortcut: "執行選取/全部 (Cmd+Enter)",
executeShortcut: "執行選取/全部 ({shortcut})",
stopQuery: "停止執行",
explainPlan: "執行計畫",
stopExplain: "停止執行計畫",
@@ -4910,7 +4910,7 @@ export default withEnglishFallback({
resetAllDefaults: "還原所有預設設定",
save: "儲存",
cancel: "取消",
executeMode: "執行模式 (Cmd+Enter)",
executeMode: "執行模式 ({shortcut})",
executeModeAll: "執行全部 SQL",
executeModeCurrent: "執行指標所在語句",
executeAllOnBlankLine: "空白位置執行全部 SQL",