feat(xugu): add programmable object compile actions

* feat(xugu): add programmable object compile actions

* chore(i18n): autofill new translations

---------

Co-authored-by: mapan <pan.anarkh1994@gmail.com>
Co-authored-by: dbx-i18n-bot <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2026-08-07 03:30:52 +08:00
1 parent c3bb16f93e
commit 352403d79e
11 files changed
+136

No files matched your search

@@ -44,6 +44,7 @@ import {
Trash2,
WrapText,
X,
Wrench,
} from "@lucide/vue";
import { useI18n } from "vue-i18n";
import i18n from "@/i18n";
@@ -94,6 +95,7 @@ import QueryEditor from "@/components/editor/QueryEditor.vue";
import { sqlFormatDialectForDbType, type SqlFormatDialect } from "@/lib/sql/sqlFormatter";
import { isCancelSearchShortcut } from "@/lib/editor/keyboardShortcuts";
import { executeWithProductionSqlGuard } from "@/lib/database/productionExecutionGuard";
import { buildXuguCompileSql } from "@/lib/database/xuguCompileSql";
import { formatShortcut } from "@/lib/editor/shortcutRegistry";
import { batchTableEmptyFeedback, buildBatchTableEmptyPlan, runBatchTableEmpty, type BatchTableEmptyPlanItem } from "@/lib/sidebar/batchTableEmpty";
import { runBatchTableDrop } from "@/lib/table/batchTableDrop";
@@ -2199,6 +2201,21 @@ async function executeObjectBrowserSqlWithProductionGuard<T>(sql: string, execut
});
}
async function compileXuguObject(row: ObjectBrowserRow) {
if (effectiveDatabaseType.value !== "xugu") return;
const sql = buildXuguCompileSql({ objectType: row.type, schema: row.schema || selectedSchema.value, name: row.name });
if (!sql) return;
try {
const executed = await executeObjectBrowserSqlWithProductionGuard(sql, () => api.executeQuery(props.connection.id, props.database, sql, row.schema || selectedSchema.value));
if (!executed) return;
toast(t("contextMenu.compileObjectSuccess", { name: row.name }));
await reload();
await connectionStore.refreshObjectListTreeNode(props.connection.id, props.database, row.schema || selectedSchema.value);
} catch (e: any) {
toast(t("contextMenu.tableOperationFailed", { message: e?.message || String(e) }), 5000);
}
}
async function refreshTruncatePreviewSql(row: ObjectBrowserRow) {
truncatePreviewSql.value = "";
truncatePreviewSql.value = await buildTruncateTableSql(tableAdminSqlOptions(row, { cascade: canTruncateTargetCascade.value && truncateTableCascade.value })).catch(() => "");
@@ -2704,6 +2721,7 @@ function getViewMenuItems(item: ObjectBrowserRow): ContextMenuItem[] {
function getProcFuncMenuItems(item: ObjectBrowserRow): ContextMenuItem[] {
return [
...(item.type === "PROCEDURE" ? [{ label: t("contextMenu.executeProcedure"), action: () => openProcedureExecution(item), icon: Play }] : []),
...(effectiveDatabaseType.value === "xugu" && buildXuguCompileSql({ objectType: item.type, schema: item.schema || selectedSchema.value, name: item.name }) ? [{ label: t("contextMenu.compileObject"), action: () => compileXuguObject(item), icon: Wrench }] : []),
{ label: t("contextMenu.viewSource"), action: () => openSource(item), icon: Code2 },
...(canRename(item) ? [{ label: t("contextMenu.renameObject"), action: () => requestRename(item), icon: Pencil }] : []),
{ label: "", separator: true },
@@ -2720,6 +2738,7 @@ function getProcFuncMenuItems(item: ObjectBrowserRow): ContextMenuItem[] {
function getPackageMenuItems(item: ObjectBrowserRow): ContextMenuItem[] {
return [
...(effectiveDatabaseType.value === "xugu" && buildXuguCompileSql({ objectType: item.type, schema: item.schema || selectedSchema.value, name: item.name }) ? [{ label: t("contextMenu.compileObject"), action: () => compileXuguObject(item), icon: Wrench }] : []),
{ label: t("contextMenu.viewSource"), action: () => openSource(item), icon: Code2 },
{ label: "", separator: true },
{ label: t("contextMenu.copyName"), action: () => copyName(item), icon: Copy },
@@ -40,6 +40,7 @@ import {
Plus,
ScrollText,
Code2,
Wrench,
ListFilter,
Clipboard,
UsersRound,
@@ -154,6 +155,7 @@ import { isSqlServerLinkedNode } from "@/lib/database/sqlServerLinkedServers";
import { flattenTree } from "@/composables/useFlatTree";
import { createDatabaseCollationOptionsForCharset, nextCreateDatabaseCollation, normalizeCreateDatabaseCharset, parseCreateDatabaseCharsetMetadata } from "@/lib/database/createDatabaseCharsetOptions";
import { executeWithProductionContextGuard, executeWithProductionSqlGuard } from "@/lib/database/productionExecutionGuard";
import { buildXuguCompileSql } from "@/lib/database/xuguCompileSql";
import type { SidebarDataOpenRequest } from "@/lib/sidebar/sidebarDataOpenCoordinator";
import { createSidebarActionTarget, findSidebarActionTarget, releaseRemovedSidebarActionTarget, type SidebarActionTarget } from "@/lib/sidebar/sidebarActionTarget";
import { createSidebarMenuContext, normalizeSidebarMenuDescriptors } from "@/lib/sidebar/sidebarTreeMenuDescriptors";
@@ -1684,6 +1686,22 @@ function openProcedureExecution() {
emit("open-procedure", node);
}
async function compileXuguObject() {
const node = activeNode.value;
if (currentDatabaseType() !== "xugu" || !node.connectionId || !node.database) return;
const sql = buildXuguCompileSql({ objectType: node.type, schema: node.schema, name: node.objectName || node.label });
if (!sql) return;
try {
await connectionStore.ensureConnected(node.connectionId);
const executed = await executeTreeNodeSqlWithProductionGuard(node, sql, { database: node.database, schema: node.schema });
if (!executed) return;
toast(t("contextMenu.compileObjectSuccess", { name: node.label }), 3000);
await connectionStore.refreshTreeNode(node);
} catch (e: any) {
toast(t("contextMenu.tableOperationFailed", { message: e?.message || String(e) }), 5000);
}
}
function requestDropObject() {
void refreshDropObjectPreviewSql();
showDropObjectConfirm.value = true;
@@ -4545,6 +4563,9 @@ function buildObjectSidebarMenu(context: SidebarMenuFactoryContext): boolean {
if (node.type === "index" || node.type === "fkey" || (node.type === "trigger" && !!node.tableName)) {
items.push({ label: t("contextMenu.copyName"), action: copyName, icon: Copy, shortcut: shortcutCopyName.value });
if (currentDatabaseType() === "xugu" && buildXuguCompileSql({ objectType: node.type, schema: node.schema, name: node.objectName || node.label })) {
items.push({ label: t("contextMenu.compileObject"), action: compileXuguObject, icon: Wrench });
}
if (node.type === "index" && canOpenStructureEditor.value) {
items.push({ label: "", separator: true });
items.push({ label: t("contextMenu.editIndex"), action: openStructureEditor, icon: PencilRuler });
@@ -4576,6 +4597,9 @@ function buildObjectSidebarMenu(context: SidebarMenuFactoryContext): boolean {
if (node.type === "procedure") {
items.push({ label: t("contextMenu.executeProcedure"), action: openProcedureExecution, icon: Play });
}
if (currentDatabaseType() === "xugu" && buildXuguCompileSql({ objectType: node.type, schema: node.schema, name: node.objectName || node.label })) {
items.push({ label: t("contextMenu.compileObject"), action: compileXuguObject, icon: Wrench });
}
items.push({ label: t("contextMenu.viewSource"), action: () => openObjectSourceDialog(false), icon: Code2 });
if (canRenameObject.value) {
items.push({
@@ -4606,6 +4630,9 @@ function buildObjectSidebarMenu(context: SidebarMenuFactoryContext): boolean {
}
if (node.type === "trigger" || node.type === "package" || node.type === "package-body" || node.type === "type" || node.type === "type-body") {
if (currentDatabaseType() === "xugu" && buildXuguCompileSql({ objectType: node.type, schema: node.schema, name: node.objectName || node.label })) {
items.push({ label: t("contextMenu.compileObject"), action: compileXuguObject, icon: Wrench });
}
items.push({ label: t("contextMenu.viewSource"), action: () => openObjectSourceDialog(false), icon: Code2 });
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 });