fix(structure): default edit view to DDL

This commit is contained in:
gggaiitx authored and GitHub committed 2026-07-10 18:14:18 +08:00
1 parent 34cf69132d
commit 2f3d1de46a
4 files changed
+139 -31

No files matched your search

@@ -25,7 +25,7 @@ import { queryTimeoutSecsForConnection } from "@/lib/sql/queryTimeout";
import { safeLocalStorageGet, safeLocalStorageSet } from "@/lib/backend/safeStorage";
import { type EditableStructureColumn, type EditableStructureForeignKey, type EditableStructureIndex, type EditableStructureTrigger } from "@/lib/table/tableStructureEditorSql";
import { PRESET_FIELDS_TEMPLATE_ID, createTableColumnTemplateDrafts } from "@/lib/table/tableColumnTemplates";
import { getTableMetadataCapabilities } from "@/lib/table/tableMetadataCapabilities";
import { getTableMetadataCapabilities, firstStructureMetadataTab, isStructureMetadataTabSupported } from "@/lib/table/tableMetadataCapabilities";
import { canAddTableStructureColumn, getTableStructureCapabilities } from "@/lib/table/tableStructureCapabilities";
import { connectionObjectTreeQuerySchema, tableStructureDatabaseTypeForConnection } from "@/lib/database/jdbcDialect";
import type { TableInfoTab, TableStructureEditorDraft, TableStructureEditorTarget, TableStructureEditorViewport } from "@/types/database";
@@ -107,7 +107,7 @@ const emit = defineEmits<{
openSettings: [initialTab?: string, initialSection?: string];
}>();
const activeTab = ref<TableInfoTab>("columns");
const activeTab = ref<TableInfoTab>("ddl");
const loading = ref(false);
const saving = ref(false);
const postSaveRefreshing = ref(false);
@@ -117,6 +117,19 @@ const foreignKeysLoading = ref(false);
const triggersLoading = ref(false);
const ddlContent = ref("");
const ddlLoading = ref(false);
const ddlPreRef = ref<HTMLPreElement | null>(null);
function onDdlKeydown(e: KeyboardEvent) {
if ((e.ctrlKey || e.metaKey) && e.key === "a") {
e.preventDefault();
const el = ddlPreRef.value;
if (!el) return;
const range = document.createRange();
range.selectNodeContents(el);
const sel = window.getSelection();
sel?.removeAllRanges();
sel?.addRange(range);
}
}
const ddlFetched = ref(false);
async function fetchDdl() {
@@ -1095,7 +1108,6 @@ function clearDraft() {
}
function resetState() {
activeTab.value = "columns";
loading.value = false;
saving.value = false;
postSaveRefreshing.value = false;
@@ -2075,7 +2087,8 @@ onMounted(() => {
void loadDynamicDataTypeOptions();
if (props.draft?.initialized) {
restoreDraft(props.draft);
applyInitialStructureTab();
// A restored draft owns its saved tab unless navigation explicitly requested another one.
applyInitialStructureTab(false);
applyInitialStructureTarget();
void hydrateRestoredDraftFromDatabase().then(() => applyInitialStructureTarget());
} else if (isCreateMode.value) {
@@ -2106,27 +2119,25 @@ onBeforeUnmount(() => {
persistStructureDensity();
});
function firstStructureMetadataTab(capabilities = tableMetadataCapabilities.value) {
if (capabilities.columns) return "columns";
if (capabilities.indexes) return "indexes";
if (capabilities.foreignKeys) return "foreignKeys";
if (capabilities.triggers) return "triggers";
if (capabilities.ddl && !isCreateMode.value) return "ddl";
return "columns";
function localFirstStructureMetadataTab(capabilities = tableMetadataCapabilities.value) {
return firstStructureMetadataTab(capabilities, isCreateMode.value);
}
function isStructureMetadataTabSupported(tab: TableInfoTab, capabilities = tableMetadataCapabilities.value) {
return (tab === "columns" && capabilities.columns) || (tab === "indexes" && capabilities.indexes) || (tab === "foreignKeys" && capabilities.foreignKeys) || (tab === "triggers" && capabilities.triggers) || (tab === "ddl" && capabilities.ddl && !isCreateMode.value);
function localIsStructureMetadataTabSupported(tab: TableInfoTab, capabilities = tableMetadataCapabilities.value) {
return isStructureMetadataTabSupported(tab, capabilities, isCreateMode.value);
}
function resolveStructureMetadataTab(tab: TableInfoTab | undefined, capabilities = tableMetadataCapabilities.value): TableInfoTab {
if (tab && isStructureMetadataTabSupported(tab, capabilities)) return tab;
return firstStructureMetadataTab(capabilities);
if (tab && localIsStructureMetadataTabSupported(tab, capabilities)) return tab;
return localFirstStructureMetadataTab(capabilities);
}
function applyInitialStructureTab() {
if (!props.initialTab) return;
activeTab.value = resolveStructureMetadataTab(props.initialTab);
function applyInitialStructureTab(useDefault = true) {
if (props.initialTab) {
activeTab.value = resolveStructureMetadataTab(props.initialTab);
} else if (useDefault) {
activeTab.value = resolveStructureMetadataTab(undefined);
}
}
function initialTargetKey(target: TableStructureEditorTarget): string {
@@ -2166,7 +2177,7 @@ function applyInitialStructureTarget() {
}
watch(tableMetadataCapabilities, (capabilities) => {
if (!isStructureMetadataTabSupported(activeTab.value, capabilities)) activeTab.value = firstStructureMetadataTab(capabilities);
if (!localIsStructureMetadataTabSupported(activeTab.value, capabilities)) activeTab.value = localFirstStructureMetadataTab(capabilities);
});
watch([() => props.initialTab, () => props.initialTabRequestId, () => props.initialTarget], () => {
@@ -2218,9 +2229,21 @@ watch(refreshVersion, (version, previous) => {
void loadStructure(true);
});
watch(activeTab, (tab) => {
if (tab === "ddl") {
void fetchDdl();
watch(
activeTab,
(tab) => {
if (tab === "ddl") {
void fetchDdl();
}
},
{ immediate: true },
);
watch([activeTab, ddlLoading], ([tab, loading]) => {
if (tab === "ddl" && !loading) {
void nextTick(() => {
ddlPreRef.value?.focus();
});
}
});
</script>
@@ -2263,11 +2286,11 @@ watch(activeTab, (tab) => {
<Tabs v-model="activeTab" class="flex h-full min-h-0 flex-col">
<div class="flex shrink-0 items-center justify-between gap-2 border-b px-2 py-[var(--structure-header-py)]">
<TabsList>
<TabsTrigger v-if="tableMetadataCapabilities.ddl && !isCreateMode" value="ddl">DDL</TabsTrigger>
<TabsTrigger v-if="tableMetadataCapabilities.columns" value="columns">{{ t("structureEditor.columns") }}</TabsTrigger>
<TabsTrigger v-if="tableMetadataCapabilities.indexes" value="indexes">{{ t("structureEditor.indexes") }}</TabsTrigger>
<TabsTrigger v-if="tableMetadataCapabilities.foreignKeys" value="foreignKeys">{{ t("structureEditor.foreignKeys") }}</TabsTrigger>
<TabsTrigger v-if="tableMetadataCapabilities.triggers" value="triggers">{{ t("structureEditor.triggers") }}</TabsTrigger>
<TabsTrigger v-if="tableMetadataCapabilities.ddl && !isCreateMode" value="ddl">DDL</TabsTrigger>
</TabsList>
<div class="flex shrink-0 items-center gap-1.5">
<div class="flex items-center gap-1.5">
@@ -2896,7 +2919,7 @@ watch(activeTab, (tab) => {
<Loader2 class="h-4 w-4 animate-spin" />
{{ t("common.loading") }}
</div>
<pre v-else class="m-0 min-h-0 flex-1 whitespace-pre p-3 font-mono text-xs leading-5 select-text" v-html="ddlContent ? (sqlHighlighter?.(ddlContent) ?? ddlContent) : t('structureEditor.emptyReadonly')"></pre>
<pre v-else ref="ddlPreRef" tabindex="0" class="m-0 min-h-0 flex-1 whitespace-pre p-3 font-mono text-xs leading-5 select-text outline-none" v-html="ddlContent ? (sqlHighlighter?.(ddlContent) ?? ddlContent) : t('structureEditor.emptyReadonly')" @keydown="onDdlKeydown"></pre>
</TabsContent>
</Tabs>
</div>