feat(sidebar): add routine source open mode

This commit is contained in:
polemp authored and GitHub committed 2026-07-29 20:48:40 +08:00
1 parent 2152f8cde8
commit d928412bf6
16 files changed
+161 -6

No files matched your search

@@ -375,6 +375,7 @@ const editingShortcutId = ref<ShortcutActionId | null>(null);
const editSidebarActivation = ref(settingsStore.editorSettings.sidebarActivation);
const editSidebarObjectDisplay = ref(settingsStore.editorSettings.sidebarObjectDisplay);
const sidebarObjectDisplayHelp = ref<"grouped" | "simple" | null>(null);
const editRoutineSourceOpenMode = ref(settingsStore.editorSettings.routineSourceOpenMode);
const editSidebarTableSearchEnabled = ref(settingsStore.editorSettings.sidebarTableSearchEnabled);
const editAutoSelectActiveSidebarNode = ref(settingsStore.editorSettings.autoSelectActiveSidebarNode);
const editOpenTabsRestoreMode = ref<OpenTabsRestoreMode>(settingsStore.editorSettings.openTabsRestoreMode);
@@ -478,6 +479,7 @@ function currentEditorSettingsDraft(): EditorSettingsDraft {
sqlFormatter: normalizeSqlFormatterSettings(editSqlFormatter.value),
sidebarActivation: editSidebarActivation.value,
sidebarObjectDisplay: editSidebarObjectDisplay.value,
routineSourceOpenMode: editRoutineSourceOpenMode.value,
sidebarTableSearchEnabled: editSidebarTableSearchEnabled.value,
autoSelectActiveSidebarNode: editAutoSelectActiveSidebarNode.value,
openTabsRestoreMode: editOpenTabsRestoreMode.value,
@@ -742,6 +744,7 @@ function syncEditorSettingsDraftFromStore() {
sqlFormatterConfigValid.value = true;
editSidebarActivation.value = settingsStore.editorSettings.sidebarActivation;
editSidebarObjectDisplay.value = settingsStore.editorSettings.sidebarObjectDisplay;
editRoutineSourceOpenMode.value = settingsStore.editorSettings.routineSourceOpenMode;
editSidebarTableSearchEnabled.value = settingsStore.editorSettings.sidebarTableSearchEnabled;
editAutoSelectActiveSidebarNode.value = settingsStore.editorSettings.autoSelectActiveSidebarNode;
editOpenTabsRestoreMode.value = settingsStore.editorSettings.openTabsRestoreMode;
@@ -944,6 +947,7 @@ function resetDefaultsForTab(tab: SettingsCategory) {
editSidebarTablePageSize.value = DEFAULT_SIDEBAR_TABLE_PAGE_SIZE;
editSidebarActivation.value = DEFAULT_EDITOR_SETTINGS.sidebarActivation;
editSidebarObjectDisplay.value = DEFAULT_EDITOR_SETTINGS.sidebarObjectDisplay;
editRoutineSourceOpenMode.value = DEFAULT_EDITOR_SETTINGS.routineSourceOpenMode;
editSidebarTableSearchEnabled.value = DEFAULT_EDITOR_SETTINGS.sidebarTableSearchEnabled;
editAutoSelectActiveSidebarNode.value = DEFAULT_EDITOR_SETTINGS.autoSelectActiveSidebarNode;
editOpenTabsRestoreMode.value = DEFAULT_EDITOR_SETTINGS.openTabsRestoreMode;
@@ -1032,6 +1036,7 @@ function resetAllDefaults() {
sqlFormatterConfigValid.value = true;
editSidebarActivation.value = DEFAULT_EDITOR_SETTINGS.sidebarActivation;
editSidebarObjectDisplay.value = DEFAULT_EDITOR_SETTINGS.sidebarObjectDisplay;
editRoutineSourceOpenMode.value = DEFAULT_EDITOR_SETTINGS.routineSourceOpenMode;
editSidebarTableSearchEnabled.value = DEFAULT_EDITOR_SETTINGS.sidebarTableSearchEnabled;
editAutoSelectActiveSidebarNode.value = DEFAULT_EDITOR_SETTINGS.autoSelectActiveSidebarNode;
editOpenTabsRestoreMode.value = DEFAULT_EDITOR_SETTINGS.openTabsRestoreMode;
@@ -1256,6 +1261,10 @@ function setSidebarObjectDisplay(value: "grouped" | "simple") {
editSidebarObjectDisplay.value = value;
}
function setRoutineSourceOpenMode(value: "query-tab" | "dialog") {
editRoutineSourceOpenMode.value = value;
}
function setIconTheme(value: DesktopIconTheme) {
editIconTheme.value = value;
}
@@ -4098,6 +4107,32 @@ onUnmounted(cleanupPreviewEditor);
</Button>
</div>
</div>
<div class="space-y-2">
<div class="flex items-center gap-2">
<Label>{{ t("settings.routineSourceOpenMode") }}</Label>
<HelpTooltip :label="t('settings.routineSourceOpenMode')">
{{ t("settings.routineSourceOpenModeQueryTabDescription") }}
</HelpTooltip>
</div>
<div class="grid grid-cols-2 gap-2">
<Button type="button" variant="outline" class="h-auto justify-start border p-3" :class="editRoutineSourceOpenMode === 'query-tab' ? 'dbx-choice-selected' : ''" @click="setRoutineSourceOpenMode('query-tab')">
<div class="text-left">
<div class="text-sm font-medium">{{ t("settings.routineSourceOpenModeQueryTab") }}</div>
<div class="text-xs text-muted-foreground">
{{ t("settings.routineSourceOpenModeQueryTabDescription") }}
</div>
</div>
</Button>
<Button type="button" variant="outline" class="h-auto justify-start border p-3" :class="editRoutineSourceOpenMode === 'dialog' ? 'dbx-choice-selected' : ''" @click="setRoutineSourceOpenMode('dialog')">
<div class="text-left">
<div class="text-sm font-medium">{{ t("settings.routineSourceOpenModeDialog") }}</div>
<div class="text-xs text-muted-foreground">
{{ t("settings.routineSourceOpenModeDialogDescription") }}
</div>
</div>
</Button>
</div>
</div>
<div class="flex items-center justify-between gap-4 rounded-md border bg-muted/20 px-3 py-2">
<div class="flex items-center gap-2">
<Label for="sidebar-table-search-enabled">{{ t("settings.sidebarTableSearchEnabled") }}</Label>
@@ -22,6 +22,7 @@ const emit = defineEmits<{
export: [];
startResize: [event: MouseEvent];
collapse: [];
"open-settings": [initialTab: string];
}>();
type ImportSource = "dbx" | "navicat" | "dbeaver" | "datagrip";
@@ -243,7 +244,7 @@ defineExpose({ focusSearch });
</template>
</div>
<div class="flex-1 min-h-0">
<ConnectionTree ref="connectionTreeRef" />
<ConnectionTree ref="connectionTreeRef" @open-settings="(initialTab) => emit('open-settings', initialTab)" />
</div>
</div>
<div class="panel-resize-handle panel-resize-handle--right" @mousedown="emit('startResize', $event)" />
@@ -62,6 +62,10 @@ const sidebarScrollbarTrackRef = ref<HTMLElement | null>(null);
const sidebarHorizontalScrollbarTrackRef = ref<HTMLElement | null>(null);
const sidebarContextMenuRef = ref<{ close: () => void } | null>(null);
const sidebarContextMenuItems = ref<ContextMenuItem[]>([]);
const emit = defineEmits<{
"open-settings": [initialTab: string];
}>();
const sidebarContextMenuTarget = ref<SidebarActionTarget | null>(null);
const sidebarDangerDialogRequest = ref<SidebarDangerDialogRequest | null>(null);
const sidebarDangerDialogOpen = ref(false);
@@ -1219,6 +1223,10 @@ function openSidebarObjectSource(node: TreeNode, initialEditing: boolean) {
});
}
function openSidebarSettings(initialTab: string) {
emit("open-settings", initialTab);
}
function openSidebarProcedure(node: TreeNode) {
if (node.type !== "procedure" || !node.connectionId || !node.database) return;
beginSidebarAction();
@@ -1605,6 +1613,7 @@ defineExpose({ focusSearch, createNewGroup, collapseAllTreeNodes });
@open-ddl="openSidebarDdl"
@open-object-source="openSidebarObjectSource"
@open-procedure="openSidebarProcedure"
@open-settings="openSidebarSettings"
@open-data="openSidebarData"
@open-visible-databases="openSidebarVisibleDatabases"
@open-visible-schemas="openSidebarVisibleSchemas"
@@ -52,6 +52,7 @@ import {
ListX,
Info,
X,
Settings2,
} from "@lucide/vue";
import type { ContextMenuItem } from "@/components/ui/CustomContextMenu.vue";
import { CONNECTION_ATTEMPT_CANCELLED_MESSAGE, useConnectionStore } from "@/stores/connectionStore";
@@ -316,6 +317,7 @@ const emit = defineEmits<{
"open-ddl": [node: TreeNode];
"open-object-source": [node: TreeNode, initialEditing: boolean];
"open-procedure": [node: TreeNode];
"open-settings": [initialTab: string];
"open-data": [node: TreeNode, requireSelection: boolean, openMode: DataTabOpenMode, runner: (node: TreeNode, request: SidebarDataOpenRequest) => Promise<void>];
"open-visible-databases": [node: TreeNode];
"open-visible-schemas": [node: TreeNode];
@@ -1508,12 +1510,38 @@ async function refreshDropTableChildObjectPreviewSql() {
function openObjectSourceDialog(initialEditing: boolean) {
const node = activeNode.value;
if (!node.connectionId || !node.database) return;
const connectionId = node.connectionId;
const database = node.database;
const objectType = objectSourceKindForTreeNode(node.type);
if (!objectType) return;
const openMode = settingsStore.editorSettings.routineSourceOpenMode;
if (openMode === "query-tab") {
void connectionStore
.ensureConnected(connectionId)
.then(async () => {
connectionStore.activeConnectionId = connectionId;
const schema = node.schema || database;
const result = await api.getObjectSource(connectionId, database, schema, node.objectName || node.label, objectType as any, node.signature);
const tabId = queryStore.createTab(connectionId, database, `Source - ${node.label}`, "query", schema, result.source, node.catalog, { forceNew: true });
const sourceIsEditable = result.editable !== false && !["SEQUENCE", "TRIGGER", "TYPE", "TYPE_BODY"].includes(objectType);
if (sourceIsEditable) {
queryStore.setObjectSource(tabId, {
schema,
name: node.objectName || node.label,
objectType,
signature: node.signature,
});
}
})
.catch((e: any) => {
toast(e?.message || String(e), 5000);
});
return;
}
void connectionStore
.ensureConnected(node.connectionId)
.ensureConnected(connectionId)
.then(() => {
connectionStore.activeConnectionId = node.connectionId!;
connectionStore.activeConnectionId = connectionId;
emit("open-object-source", node, initialEditing);
})
.catch((e: any) => {
@@ -4150,6 +4178,7 @@ function buildObjectSidebarMenu(context: SidebarMenuFactoryContext): boolean {
action: () => emit("open-ddl", node),
icon: FileCode,
});
items.push({ label: t("contextMenu.changeOpenMode"), action: () => emit("open-settings", "navigation"), icon: Settings2 });
}
if (canOpenStructureEditor.value) {
items.push({ label: t("contextMenu.editStructure"), action: openStructureEditor, icon: PencilRuler });
@@ -4314,6 +4343,8 @@ function buildObjectSidebarMenu(context: SidebarMenuFactoryContext): boolean {
});
}
items.push({ label: "", separator: true });
items.push({ label: t("contextMenu.changeOpenMode"), action: () => emit("open-settings", "navigation"), icon: Settings2 });
items.push({ label: "", separator: true });
items.push({
label: deleteMenuLabel(node.type === "procedure" ? t("contextMenu.dropProcedure") : t("contextMenu.dropFunction")),
action: deleteMenuAction(requestDropObject),
@@ -4326,15 +4357,15 @@ function buildObjectSidebarMenu(context: SidebarMenuFactoryContext): boolean {
if (node.type === "sequence") {
items.push({ label: t("contextMenu.viewSource"), action: () => openObjectSourceDialog(false), icon: Code2 });
items.push({ label: "", separator: true });
items.push({ label: t("contextMenu.copyName"), action: copyName, icon: Copy, shortcut: shortcutCopyName.value });
items.push({ label: t("contextMenu.changeOpenMode"), action: () => emit("open-settings", "navigation"), icon: Settings2 });
return true;
}
if (node.type === "trigger" || node.type === "package" || node.type === "package-body" || node.type === "type" || node.type === "type-body") {
items.push({ label: t("contextMenu.viewSource"), action: () => openObjectSourceDialog(false), icon: Code2 });
items.push({ label: "", separator: true });
items.push({ label: t("contextMenu.copyName"), action: copyName, icon: Copy, shortcut: shortcutCopyName.value });
items.push({ label: t("contextMenu.changeOpenMode"), action: () => emit("open-settings", "navigation"), icon: Settings2 });
return true;
}
return false;