diff --git a/apps/desktop/src/components/editor/EditorSettingsDialog.vue b/apps/desktop/src/components/editor/EditorSettingsDialog.vue index 45653e8d9..9f5f98783 100644 --- a/apps/desktop/src/components/editor/EditorSettingsDialog.vue +++ b/apps/desktop/src/components/editor/EditorSettingsDialog.vue @@ -14,7 +14,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@ import { Separator } from "@/components/ui/separator"; import { Switch } from "@/components/ui/switch"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; +import { Tooltip, TooltipContent, TooltipTrigger, TooltipProvider } from "@/components/ui/tooltip"; import { useSettingsStore, AI_PROVIDER_PRESETS, @@ -104,6 +104,7 @@ const editSidebarHiddenTablePrefixes = ref(settingsStore.editorSettings.sidebarH const editSidebarHideTableComments = ref(settingsStore.editorSettings.sidebarHideTableComments); const editSidebarAllowHorizontalScroll = ref(settingsStore.editorSettings.sidebarAllowHorizontalScroll); const editExportBatchSize = ref(settingsStore.editorSettings.exportBatchSize); +const editToolbarItems = ref({ ...settingsStore.editorSettings.toolbarItems }); const redisScanPageSizeOptions = [200, 1000, 5000, 10000]; const systemFonts = ref([]); const systemFontsLoading = ref(false); @@ -263,6 +264,7 @@ watch( editSidebarHideTableComments.value = settingsStore.editorSettings.sidebarHideTableComments; editSidebarAllowHorizontalScroll.value = settingsStore.editorSettings.sidebarAllowHorizontalScroll; editExportBatchSize.value = settingsStore.editorSettings.exportBatchSize; + editToolbarItems.value = { ...settingsStore.editorSettings.toolbarItems }; editSnippets.value = settingsStore.editorSettings.snippets.map((s) => ({ ...s })); void loadSystemFontOptions(); } @@ -314,6 +316,7 @@ function hasChanges(): boolean { editSidebarHideTableComments.value !== settingsStore.editorSettings.sidebarHideTableComments || editSidebarAllowHorizontalScroll.value !== settingsStore.editorSettings.sidebarAllowHorizontalScroll || editExportBatchSize.value !== settingsStore.editorSettings.exportBatchSize || + JSON.stringify(editToolbarItems.value) !== JSON.stringify(settingsStore.editorSettings.toolbarItems) || JSON.stringify(normalizeSidebarHiddenTablePrefixes(editSidebarHiddenTablePrefixes.value)) !== JSON.stringify(settingsStore.editorSettings.sidebarHiddenTablePrefixes) || JSON.stringify(editSnippets.value) !== JSON.stringify(settingsStore.editorSettings.snippets) ); @@ -349,6 +352,7 @@ async function persistSettings() { sidebarAllowHorizontalScroll: editSidebarAllowHorizontalScroll.value, sidebarHiddenTablePrefixes: normalizeSidebarHiddenTablePrefixes(editSidebarHiddenTablePrefixes.value), exportBatchSize: editExportBatchSize.value, + toolbarItems: { ...editToolbarItems.value }, snippets: editSnippets.value, }); await settingsStore.updateDesktopSettings({ @@ -401,6 +405,7 @@ function resetDefaults() { editSidebarAllowHorizontalScroll.value = DEFAULT_EDITOR_SETTINGS.sidebarAllowHorizontalScroll; editSidebarHiddenTablePrefixes.value = DEFAULT_EDITOR_SETTINGS.sidebarHiddenTablePrefixes.join("\n"); editExportBatchSize.value = DEFAULT_EDITOR_SETTINGS.exportBatchSize; + editToolbarItems.value = { ...DEFAULT_EDITOR_SETTINGS.toolbarItems }; editSnippets.value = DEFAULT_SQL_SNIPPETS.map((s) => ({ ...s })); } @@ -1602,6 +1607,46 @@ watch( + + + +
+
+ + + + + + + +

{{ t("settings.toolbarHiddenHint") }}

+
+
+
+
+
+
+ + +
+
+
diff --git a/apps/desktop/src/components/layout/AppToolbar.vue b/apps/desktop/src/components/layout/AppToolbar.vue index 6fbe77da1..adcc04f57 100644 --- a/apps/desktop/src/components/layout/AppToolbar.vue +++ b/apps/desktop/src/components/layout/AppToolbar.vue @@ -8,6 +8,7 @@ import LightDropdown from "@/components/ui/LightDropdown.vue"; import WindowControls from "@/components/layout/WindowControls.vue"; import ExportProgressPopover from "@/components/export/ExportProgressPopover.vue"; import { shouldReserveMacTrafficLightInset, useWindowControls } from "@/composables/useWindowControls"; +import { useSettingsStore } from "@/stores/settingsStore"; import type { AppThemeMode } from "@/lib/appTheme"; const props = defineProps<{ @@ -42,6 +43,8 @@ const emit = defineEmits<{ }>(); const { t } = useI18n(); +const settingsStore = useSettingsStore(); +const toolbarItems = computed(() => settingsStore.editorSettings.toolbarItems); const { isMac, isDesktop, showControls, isMaximized, isFullscreen, minimize, toggleMaximize, close } = useWindowControls(); const themeItems = computed(() => [ @@ -82,47 +85,89 @@ onBeforeUnmount(() => { resizeObserver?.disconnect(); }); -const moreItems = computed(() => [ - { - value: "sql-file", - label: t("sqlFile.title"), - icon: FileCode, - action: () => emit("open-sql-file"), - disabled: !props.hasSqlFileConnections, - }, - { - value: "schema-diff", - label: t("diff.title"), - icon: GitCompareArrows, - action: () => emit("open-schema-diff"), - disabled: !props.hasConnections, - }, - { - value: "data-compare", - label: t("dataCompare.title"), - icon: TableProperties, - action: () => emit("open-data-compare"), - disabled: !props.hasConnections, - }, -]); +const moreItems = computed(() => { + const items: Array<{ value: string; label: string; icon: any; action: () => void; disabled: boolean }> = []; -const collapsedItems = computed(() => [ - { - value: "transfer", - label: t("transfer.dataTransfer"), - icon: ArrowLeftRight, - action: () => emit("open-transfer"), - disabled: !props.hasConnections, - }, - ...moreItems.value, - { - value: "driver-store", - label: props.agentDriverUpdateCount > 0 ? `${t("toolbar.driverManager")} (${props.agentDriverUpdateCount})` : t("toolbar.driverManager"), - icon: Package, - action: () => emit("open-driver-store"), - disabled: false, - }, -]); + // Hidden left-side items go into "更多" + if (!toolbarItems.value.dataTransfer) { + items.push({ + value: "transfer", + label: t("transfer.dataTransfer"), + icon: ArrowLeftRight, + action: () => emit("open-transfer"), + disabled: !props.hasConnections, + }); + } + if (!toolbarItems.value.driverManager) { + items.push({ + value: "driver-store", + label: t("toolbar.driverManager"), + icon: Package, + action: () => emit("open-driver-store"), + disabled: false, + }); + } + + // "更多" menu items (individually toggleable) + if (toolbarItems.value.sqlFile) { + items.push({ + value: "sql-file", + label: t("sqlFile.title"), + icon: FileCode, + action: () => emit("open-sql-file"), + disabled: !props.hasSqlFileConnections, + }); + } + if (toolbarItems.value.schemaDiff) { + items.push({ + value: "schema-diff", + label: t("diff.title"), + icon: GitCompareArrows, + action: () => emit("open-schema-diff"), + disabled: !props.hasConnections, + }); + } + if (toolbarItems.value.dataCompare) { + items.push({ + value: "data-compare", + label: t("dataCompare.title"), + icon: TableProperties, + action: () => emit("open-data-compare"), + disabled: !props.hasConnections, + }); + } + + return items; +}); + +const showMoreDropdown = computed(() => moreItems.value.length > 0); + +const collapsedItems = computed(() => { + const items: Array<{ value: string; label: string; icon: any; action: () => void; disabled: boolean }> = []; + if (toolbarItems.value.dataTransfer) { + items.push({ + value: "transfer", + label: t("transfer.dataTransfer"), + icon: ArrowLeftRight, + action: () => emit("open-transfer"), + disabled: !props.hasConnections, + }); + } + if (toolbarItems.value.driverManager) { + items.push({ + value: "driver-store", + label: props.agentDriverUpdateCount > 0 ? `${t("toolbar.driverManager")} (${props.agentDriverUpdateCount})` : t("toolbar.driverManager"), + icon: Package, + action: () => emit("open-driver-store"), + disabled: false, + }); + } + // Always include moreItems (may contain hidden left-side items) + if (moreItems.value.length > 0) { + items.push(...moreItems.value); + } + return items; +});