feat(dameng): show view validity and support recompilation

This commit is contained in:
guan xin authored and GitHub committed 2026-09-17 19:30:44 +08:00
1 parent e4bda693fb
commit 6b81a98453
71 files changed
+1040 -38

No files matched your search

@@ -124,6 +124,7 @@ import { isCancelSearchShortcut } from "@/lib/editor/keyboardShortcuts";
import { executeWithProductionSqlGuard } from "@/lib/database/productionExecutionGuard";
import { connectionIsEffectivelyReadOnly } from "@/lib/database/readOnlyWriteAccess";
import { buildXuguCompileSql } from "@/lib/database/xuguCompileSql";
import { buildDamengCompileViewSql } from "@/lib/database/damengCompileSql";
import { formatShortcut } from "@/lib/editor/shortcutRegistry";
import { batchTableEmptyFeedback, buildBatchTableEmptyPlan, runBatchTableEmpty, type BatchTableEmptyPlanItem } from "@/lib/sidebar/batchTableEmpty";
import { runBatchTableDrop } from "@/lib/table/batchTableDrop";
@@ -224,6 +225,9 @@ const sourceError = ref("");
const sourceRow = ref<ObjectBrowserRow | null>(null);
const sourceEditing = ref(false);
const sourceCanEdit = ref(true);
const showCompileErrorDialog = ref(false);
const compileErrorTitle = ref("");
const compileErrorMessage = ref("");
// --- Right-side panel state ---
// Unified panel: either "table-info" (for tables) or "source" (for views/procedures/etc.)
const sidePanelRow = ref<ObjectBrowserRow | null>(null);
@@ -2570,6 +2574,24 @@ async function compileXuguObject(row: ObjectBrowserRow) {
}
}
async function compileDamengView(row: ObjectBrowserRow) {
if (effectiveDatabaseType.value !== "dameng" || row.type !== "VIEW") return;
const schema = row.schema || selectedSchema.value;
const sql = buildDamengCompileViewSql({ schema, name: row.name });
if (!sql) return;
try {
const executed = await executeObjectBrowserSqlWithProductionGuard(sql, () => api.executeQuery(props.connection.id, props.database, sql, schema));
if (!executed) return;
toast(t("contextMenu.compileObjectSuccess", { name: row.name }));
await reload();
await connectionStore.refreshObjectListTreeNode(props.connection.id, props.database, schema);
} catch (e: any) {
compileErrorTitle.value = t("contextMenu.compileObjectFailedTitle");
compileErrorMessage.value = t("contextMenu.compileObjectFailedMessage", { name: row.name, message: e?.message || String(e) });
showCompileErrorDialog.value = true;
}
}
async function refreshTruncatePreviewSql(row: ObjectBrowserRow) {
truncatePreviewSql.value = "";
truncatePreviewSql.value = await buildTruncateTableSql(tableAdminSqlOptions(row, { cascade: canTruncateTargetCascade.value && truncateTableCascade.value })).catch(() => "");
@@ -3244,6 +3266,7 @@ function getViewMenuItems(item: ObjectBrowserRow): ContextMenuItem[] {
{ label: t("contextMenu.viewData"), action: () => openViewData(item), icon: Table2 },
{ label: t("contextMenu.editView"), action: () => openSource(item), icon: PencilLine },
{ label: t("contextMenu.viewSource"), action: () => openSource(item), icon: Code2 },
...(effectiveDatabaseType.value === "dameng" && item.type === "VIEW" && buildDamengCompileViewSql({ schema: item.schema || selectedSchema.value, name: item.name }) ? [{ label: t("contextMenu.compileObject"), action: () => compileDamengView(item), icon: Wrench }] : []),
{
label: t("contextMenu.viewDdl"),
action: () => openTableInfo(item, "ddl"),
@@ -3633,7 +3656,12 @@ function getObjectBrowserMenuItems(item: ObjectBrowserRow): ContextMenuItem[] {
{{ t("objects.partitions", { count: item.partitionCount }) }}
</span>
</div>
<div class="truncate text-xs text-muted-foreground">{{ typeLabel(item) }}</div>
<div class="flex min-w-0 items-center gap-1.5 truncate text-xs text-muted-foreground">
<span class="truncate">{{ typeLabel(item) }}</span>
<span v-if="item.type === 'VIEW' && item.valid != null" class="shrink-0 rounded border px-1 py-px text-[10px] font-medium" :class="item.valid ? 'border-emerald-500/30 text-emerald-600' : 'border-destructive/30 text-destructive'">
{{ t(item.valid ? "objects.validStatus" : "objects.invalidStatus") }}
</span>
</div>
<div v-if="showObjectRowStats" class="truncate text-xs tabular-nums text-muted-foreground" :title="item.estimatedRows == null ? '' : formatObjectBrowserCount(item.estimatedRows)">
{{ formatObjectBrowserCount(item.estimatedRows) }}
</div>
@@ -3679,6 +3707,9 @@ function getObjectBrowserMenuItems(item: ObjectBrowserRow): ContextMenuItem[] {
<span class="w-full truncate text-sm font-medium leading-tight text-foreground">{{ item.displayName }}</span>
<div class="flex items-center gap-1.5">
<span class="text-xs text-muted-foreground">{{ typeLabel(item) }}</span>
<span v-if="item.type === 'VIEW' && item.valid != null" class="rounded border px-1 py-px text-[10px] font-medium" :class="item.valid ? 'border-emerald-500/30 text-emerald-600' : 'border-destructive/30 text-destructive'">
{{ t(item.valid ? "objects.validStatus" : "objects.invalidStatus") }}
</span>
<span v-if="showObjectRowStats && item.estimatedRows != null && item.estimatedRows > 0" class="object-browser-stat-badge object-browser-stat-badge-rows rounded-full bg-primary/10 px-1.5 py-0.5 text-[10px] font-medium tabular-nums text-primary">{{
formatObjectBrowserCount(item.estimatedRows)
}}</span>
@@ -4058,6 +4089,18 @@ function getObjectBrowserMenuItems(item: ObjectBrowserRow): ContextMenuItem[] {
</DialogContent>
</Dialog>
<Dialog v-model:open="showCompileErrorDialog">
<DialogContent class="sm:max-w-[560px]">
<DialogHeader>
<DialogTitle>{{ compileErrorTitle }}</DialogTitle>
</DialogHeader>
<pre class="max-h-72 overflow-auto whitespace-pre-wrap break-words rounded bg-destructive/5 p-3 text-sm text-destructive">{{ compileErrorMessage }}</pre>
<DialogFooter>
<Button @click="showCompileErrorDialog = false">{{ t("common.close") }}</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<DangerConfirmDialog
v-model:open="showVacuumConfirm"
:title="t('contextMenu.vacuumTableTitle')"