feat(oracle): show table constraints in structure editor

This commit is contained in:
Melody Ruch authored and GitHub committed 2026-08-15 23:28:53 +08:00
1 parent 76b8f2f54b
commit f9c4f290f5
19 files changed
+413 -20

No files matched your search

@@ -40,7 +40,7 @@ import { canAddTableStructureColumn, getTableStructureCapabilities, hasLocalTabl
import { orderedColumnIndexes, uniqueDataGridColumnOrderKeys } from "@/lib/dataGrid/dataGridColumnOrder";
import { loadTableDataGridColumnOrder, notifyTableDataGridColumnOrderChanged, removeTableDataGridColumnOrder, saveTableDataGridColumnOrder, tableDataGridColumnOrderScopeKey } from "@/lib/dataGrid/dataGridColumnLayoutStorage";
import { connectionObjectTreeQuerySchema, tableStructureDatabaseTypeForConnection } from "@/lib/database/jdbcDialect";
import type { TableInfoTab, TableStructureEditorDraft, TableStructureEditorTarget, TableStructureEditorViewport } from "@/types/database";
import type { ConstraintInfo, TableInfoTab, TableStructureEditorDraft, TableStructureEditorTarget, TableStructureEditorViewport } from "@/types/database";
import {
applyManticoreDdlColumnExtras,
buildStructureTargetLabel,
@@ -95,6 +95,7 @@ type StructureScrollerRef = HTMLElement | { $el?: HTMLElement };
const columnsScrollerRef = ref<StructureScrollerRef>();
const indexesScrollerRef = ref<StructureScrollerRef>();
const foreignKeysScrollerRef = ref<StructureScrollerRef>();
const constraintsScrollerRef = ref<StructureScrollerRef>();
const triggersScrollerRef = ref<StructureScrollerRef>();
const ddlScrollerRef = ref<StructureScrollerRef>();
const dynamicDataTypeOptionsCache = new Map<string, string[]>();
@@ -141,6 +142,7 @@ const sqlPreviewLoading = ref(false);
const sqlPreviewPending = ref(false);
const indexesLoading = ref(false);
const foreignKeysLoading = ref(false);
const constraintsLoading = ref(false);
const triggersLoading = ref(false);
const ddlContent = ref("");
const ddlLoading = ref(false);
@@ -192,9 +194,11 @@ const pendingStatements = ref<string[]>([]);
const warnings = ref<string[]>([]);
const sqliteSchemaRevision = ref<string>();
const foreignKeys = ref<EditableStructureForeignKey[]>([]);
const constraints = ref<ConstraintInfo[]>([]);
const constraintsLoaded = ref(false);
const triggers = ref<EditableStructureTrigger[]>([]);
const triggersLoaded = ref(false);
const secondaryMetadataLoading = computed(() => indexesLoading.value || foreignKeysLoading.value || triggersLoading.value);
const secondaryMetadataLoading = computed(() => indexesLoading.value || foreignKeysLoading.value || constraintsLoading.value || triggersLoading.value);
function sameList(left: string[] | null | undefined, right: string[] | null | undefined): boolean {
const a = left ?? [];
@@ -262,6 +266,10 @@ function captureStructureRefreshScope(): TableStructureRefreshScope {
columns: columns.value.some(columnChanged),
indexes: indexes.value.some(indexChanged),
foreignKeys: foreignKeys.value.some(foreignKeyChanged),
// Constraints have no editable draft of their own, but column/index/FK
// saves can change what constraints exist (e.g. toggling a primary key),
// so refresh the tab if it was ever loaded rather than leaving it stale.
constraints: constraintsLoaded.value,
triggers: triggers.value.some(triggerChanged),
tableComment: tableComment.value !== originalTableComment.value,
};
@@ -881,6 +889,7 @@ function structureScrollerForTab(tab: TableInfoTab): HTMLElement | undefined {
if (tab === "columns") return structureScrollerElement(columnsScrollerRef.value);
if (tab === "indexes") return structureScrollerElement(indexesScrollerRef.value);
if (tab === "foreignKeys") return structureScrollerElement(foreignKeysScrollerRef.value);
if (tab === "constraints") return structureScrollerElement(constraintsScrollerRef.value);
if (tab === "triggers") return structureScrollerElement(triggersScrollerRef.value);
if (tab === "ddl") return structureScrollerElement(ddlScrollerRef.value);
return undefined;
@@ -927,6 +936,8 @@ function createCurrentDraft(initialized = true): TableStructureEditorDraft {
columns: cloneDraftValue(columns.value),
indexes: cloneDraftValue(indexes.value),
foreignKeys: cloneDraftValue(foreignKeys.value),
constraints: cloneDraftValue(constraints.value),
constraintsLoaded: constraintsLoaded.value,
triggers: cloneDraftValue(triggers.value),
triggersLoaded: triggersLoaded.value,
loadedMetadataFacets: [...loadedMetadataFacets],
@@ -953,6 +964,9 @@ function restoreDraft(draft: TableStructureEditorDraft) {
columns.value = cloneDraftValue(draft.columns || []);
indexes.value = cloneDraftValue(draft.indexes || []);
foreignKeys.value = cloneDraftValue(draft.foreignKeys || []);
constraints.value = cloneDraftValue(draft.constraints || []);
// Drafts created before constraint loading existed have no saved facet.
constraintsLoaded.value = draft.constraintsLoaded ?? false;
triggers.value = cloneDraftValue(draft.triggers || []);
// Drafts created before lazy trigger loading always contained live trigger metadata.
triggersLoaded.value = draft.triggersLoaded ?? true;
@@ -964,6 +978,7 @@ function restoreDraft(draft: TableStructureEditorDraft) {
if (activeScope.columns) loadedMetadataFacets.add("columns");
if (activeScope.indexes || draft.indexes?.length) loadedMetadataFacets.add("indexes");
if (activeScope.foreignKeys || draft.foreignKeys?.length) loadedMetadataFacets.add("foreign-keys");
if (activeScope.constraints || constraintsLoaded.value) loadedMetadataFacets.add("constraints");
if (activeScope.triggers || triggersLoaded.value) loadedMetadataFacets.add("triggers");
if (activeScope.tableComment) loadedMetadataFacets.add("comment");
}
@@ -1226,6 +1241,7 @@ function resetState() {
sqlPreviewPending.value = false;
indexesLoading.value = false;
foreignKeysLoading.value = false;
constraintsLoading.value = false;
triggersLoading.value = false;
errorMessage.value = "";
columns.value = [];
@@ -1234,6 +1250,8 @@ function resetState() {
warnings.value = [];
sqliteSchemaRevision.value = undefined;
foreignKeys.value = [];
constraints.value = [];
constraintsLoaded.value = false;
triggers.value = [];
triggersLoaded.value = false;
selectedColumnId.value = null;
@@ -1259,6 +1277,10 @@ async function reloadStructureFromDatabase() {
triggers.value = [];
triggersLoaded.value = false;
}
if (activeTab.value !== "constraints") {
constraints.value = [];
constraintsLoaded.value = false;
}
const refreshDdl = activeTab.value === "ddl";
const metadataMatch = { connectionId: props.connectionId, database: props.database, schema: metadataSchema.value, tableName: props.tableName };
invalidateTableMetadataCache(metadataMatch);
@@ -1275,6 +1297,7 @@ async function reloadStructureFromDatabase() {
function setSecondaryMetadataLoading(scope: TableStructureRefreshScope, value: boolean) {
if (scope.indexes && tableMetadataCapabilities.value.indexes) indexesLoading.value = value;
if (scope.foreignKeys && tableMetadataCapabilities.value.foreignKeys) foreignKeysLoading.value = value;
if (scope.constraints && tableMetadataCapabilities.value.constraints) constraintsLoading.value = value;
if (scope.triggers && tableMetadataCapabilities.value.triggers) triggersLoading.value = value;
}
@@ -1330,6 +1353,11 @@ async function loadStructure(
? loadObjectMetadataFacet(metadataRequest, "foreign-keys", () => api.listForeignKeys(connectionId, database, schema, tableName, catalog).catch(() => []), { force: forceMetadata }).then((result) => result.value)
: Promise.resolve([])
: Promise.resolve(undefined);
const constraintsPromise = scope.constraints
? tableMetadataCapabilities.value.constraints
? loadObjectMetadataFacet(metadataRequest, "constraints", () => api.listConstraints(connectionId, database, schema, tableName, catalog).catch(() => []), { force: forceMetadata }).then((result) => result.value)
: Promise.resolve([])
: Promise.resolve(undefined);
const triggersPromise = scope.triggers
? tableMetadataCapabilities.value.triggers
? loadObjectMetadataFacet(metadataRequest, "triggers", () => api.listTriggers(connectionId, database, schema, tableName, catalog).catch(() => []), { force: forceMetadata }).then((result) => result.value)
@@ -1366,7 +1394,7 @@ async function loadStructure(
loadedMetadataFacets.add("comment");
}
const applySecondaryMetadata = async () => {
const [nextIndexes, nextForeignKeys, nextTriggers] = await Promise.all([indexesPromise, foreignKeysPromise, triggersPromise]);
const [nextIndexes, nextForeignKeys, nextConstraints, nextTriggers] = await Promise.all([indexesPromise, foreignKeysPromise, constraintsPromise, triggersPromise]);
if (requestId !== structureLoadRequestId) return;
if (nextIndexes) {
indexes.value = createIndexDrafts(nextIndexes);
@@ -1376,6 +1404,11 @@ async function loadStructure(
foreignKeys.value = createForeignKeyDrafts(nextForeignKeys);
loadedMetadataFacets.add("foreign-keys");
}
if (nextConstraints) {
constraints.value = nextConstraints;
constraintsLoaded.value = true;
loadedMetadataFacets.add("constraints");
}
if (nextTriggers) {
triggers.value = createTriggerDrafts(nextTriggers);
triggersLoaded.value = true;
@@ -2605,6 +2638,10 @@ watch(refreshVersion, (version, previous) => {
triggers.value = [];
triggersLoaded.value = false;
}
if (activeTab.value !== "constraints") {
constraints.value = [];
constraintsLoaded.value = false;
}
void loadStructure(true, visibleTableStructureRefreshScope(activeTab.value));
});
@@ -2674,6 +2711,7 @@ watch([activeTab, ddlLoading], ([tab, loading]) => {
<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.constraints" value="constraints">{{ t("structureEditor.constraints") }}</TabsTrigger>
<TabsTrigger v-if="tableMetadataCapabilities.triggers" value="triggers">{{ t("structureEditor.triggers") }}</TabsTrigger>
</TabsList>
<div class="flex shrink-0 items-center gap-1.5">
@@ -3302,6 +3340,29 @@ watch([activeTab, ddlLoading], ([tab, loading]) => {
</div>
</TabsContent>
<TabsContent ref="constraintsScrollerRef" v-if="tableMetadataCapabilities.constraints" value="constraints" class="m-0 min-h-0 flex-1 overflow-auto p-[var(--structure-cell-px)]" @scroll.passive="onStructureContentScroll('constraints', $event)">
<div v-if="constraintsLoading" class="flex items-center justify-center gap-2 py-10 text-muted-foreground">
<Loader2 class="h-4 w-4 animate-spin" />
{{ t("common.loading") }}
</div>
<div v-else-if="constraints.length === 0" class="py-10 text-center text-muted-foreground">
{{ t("structureEditor.emptyReadonly") }}
</div>
<div v-else class="space-y-1.5">
<div v-for="constraint in constraints" :key="constraint.name" class="rounded-md border px-[var(--structure-cell-px)] py-[var(--structure-header-py)] text-[length:var(--structure-font-size)]" :class="constraint.enabled ? '' : 'opacity-60'">
<div class="flex flex-wrap items-center gap-1.5">
<span class="font-mono font-medium">{{ constraint.name }}</span>
<Badge variant="outline" class="shrink-0">{{ constraint.constraint_type }}</Badge>
<Badge v-if="!constraint.enabled" variant="outline" class="shrink-0 text-muted-foreground">{{ t("structureEditor.constraintDisabled") }}</Badge>
<Badge v-else-if="!constraint.valid" variant="outline" class="shrink-0 text-muted-foreground">{{ t("structureEditor.constraintNotValidated") }}</Badge>
</div>
<div v-if="constraint.columns.length" class="mt-1 truncate font-mono text-muted-foreground">{{ constraint.columns.join(", ") }}</div>
<div v-if="constraint.ref_table" class="mt-1 truncate font-mono text-muted-foreground">-> {{ constraint.ref_schema ? `${constraint.ref_schema}.` : "" }}{{ constraint.ref_table }}{{ constraint.ref_columns.length ? `(${constraint.ref_columns.join(", ")})` : "" }}</div>
<div v-if="constraint.definition" class="mt-1 whitespace-pre-wrap break-words font-mono text-muted-foreground">{{ constraint.definition }}</div>
</div>
</div>
</TabsContent>
<TabsContent ref="triggersScrollerRef" v-if="tableMetadataCapabilities.triggers" value="triggers" class="m-0 min-h-0 flex-1 overflow-auto p-[var(--structure-cell-px)]" @scroll.passive="onStructureContentScroll('triggers', $event)">
<div v-if="triggersLoading" class="flex items-center justify-center gap-2 py-10 text-muted-foreground">
<Loader2 class="h-4 w-4 animate-spin" />
@@ -0,0 +1,11 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const source = readFileSync(new URL("../TableStructureEditor.vue", import.meta.url), "utf8");
describe("TableStructureEditor constraints", () => {
it("renders complete check expressions instead of truncating them", () => {
expect(source).toContain('class="mt-1 whitespace-pre-wrap break-words font-mono text-muted-foreground">{{ constraint.definition }}');
expect(source).not.toContain('class="mt-1 truncate font-mono text-muted-foreground">{{ constraint.definition }}');
});
});
+3
View File
@@ -3430,6 +3430,9 @@ export default {
columns: "Columns",
indexes: "Indexes",
foreignKeys: "Foreign Keys",
constraints: "Constraints",
constraintDisabled: "Disabled",
constraintNotValidated: "Not validated",
triggers: "Triggers",
ddl: "DDL",
addColumn: "Add Column",
+3
View File
@@ -3371,6 +3371,9 @@ export default withEnglishFallback({
columns: "Columnas",
indexes: "Índices",
foreignKeys: "Claves foráneas",
constraints: "Restricciones",
constraintDisabled: "Deshabilitada",
constraintNotValidated: "No validada",
triggers: "Disparadores",
ddl: "DDL",
addColumn: "Agregar columna",
+3
View File
@@ -3369,6 +3369,9 @@ export default withEnglishFallback({
columns: "Colonne",
indexes: "Indici",
foreignKeys: "Chiavi Esterne",
constraints: "Vincoli",
constraintDisabled: "Disabilitato",
constraintNotValidated: "Non convalidato",
triggers: "Trigger",
ddl: "DDL",
addColumn: "Aggiungi Colonna",
+3
View File
@@ -3430,6 +3430,9 @@ export default withEnglishFallback({
columns: "列",
indexes: "インデックス",
foreignKeys: "外部キー",
constraints: "制約",
constraintDisabled: "無効",
constraintNotValidated: "未検証",
triggers: "トリガー",
ddl: "DDL",
addColumn: "列を追加",
+3
View File
@@ -3256,6 +3256,9 @@ export default withEnglishFallback({
columns: "컬럼",
indexes: "인덱스",
foreignKeys: "외래 키",
constraints: "제약 조건",
constraintDisabled: "비활성화됨",
constraintNotValidated: "검증되지 않음",
triggers: "트리거",
ddl: "DDL",
addColumn: "컬럼 추가",
+3
View File
@@ -3371,6 +3371,9 @@ export default withEnglishFallback({
columns: "Colunas",
indexes: "Índices",
foreignKeys: "Chaves estrangeiras",
constraints: "Restrições",
constraintDisabled: "Desabilitada",
constraintNotValidated: "Não validada",
triggers: "Triggers",
ddl: "DDL",
addColumn: "Adicionar coluna",
+3
View File
@@ -3418,6 +3418,9 @@ export default withEnglishFallback({
columns: "字段",
indexes: "索引",
foreignKeys: "外键",
constraints: "约束",
constraintDisabled: "已禁用",
constraintNotValidated: "未验证",
triggers: "触发器",
ddl: "DDL",
addColumn: "新增字段",
+3
View File
@@ -3131,6 +3131,9 @@ export default withEnglishFallback({
columns: "欄位",
indexes: "索引",
foreignKeys: "外鍵",
constraints: "約束",
constraintDisabled: "已停用",
constraintNotValidated: "未驗證",
triggers: "觸發器",
ddl: "DDL",
addColumn: "新增欄位",
@@ -3,11 +3,12 @@ import { hasTableStructureRefreshWork, unloadedTableStructureRefreshScope, visib
describe("table structure metadata loading", () => {
it.each([
["columns", { columns: true, indexes: false, foreignKeys: false, triggers: false, tableComment: true }],
["indexes", { columns: true, indexes: true, foreignKeys: false, triggers: false, tableComment: true }],
["foreignKeys", { columns: true, indexes: false, foreignKeys: true, triggers: false, tableComment: true }],
["triggers", { columns: false, indexes: false, foreignKeys: false, triggers: true, tableComment: true }],
["ddl", { columns: false, indexes: false, foreignKeys: false, triggers: false, tableComment: false }],
["columns", { columns: true, indexes: false, foreignKeys: false, constraints: false, triggers: false, tableComment: true }],
["indexes", { columns: true, indexes: true, foreignKeys: false, constraints: false, triggers: false, tableComment: true }],
["foreignKeys", { columns: true, indexes: false, foreignKeys: true, constraints: false, triggers: false, tableComment: true }],
["constraints", { columns: false, indexes: false, foreignKeys: false, constraints: true, triggers: false, tableComment: true }],
["triggers", { columns: false, indexes: false, foreignKeys: false, constraints: false, triggers: true, tableComment: true }],
["ddl", { columns: false, indexes: false, foreignKeys: false, constraints: false, triggers: false, tableComment: false }],
] as const)("requests only the metadata required by the %s tab", (tab, expected) => {
expect(visibleTableStructureRefreshScope(tab)).toEqual(expected);
});
@@ -15,13 +16,18 @@ describe("table structure metadata loading", () => {
it("requests only index metadata after columns and comments are already loaded", () => {
const scope = unloadedTableStructureRefreshScope("indexes", new Set(["columns", "comment"]));
expect(scope).toEqual({ columns: false, indexes: true, foreignKeys: false, triggers: false, tableComment: false });
expect(scope).toEqual({ columns: false, indexes: true, foreignKeys: false, constraints: false, triggers: false, tableComment: false });
expect(hasTableStructureRefreshWork(scope)).toBe(true);
expect(hasTableStructureRefreshWork(unloadedTableStructureRefreshScope("indexes", new Set(["columns", "indexes", "comment"])))).toBe(false);
});
it("requests trigger metadata only until that facet is loaded", () => {
expect(unloadedTableStructureRefreshScope("triggers", new Set(["comment"]))).toEqual({ columns: false, indexes: false, foreignKeys: false, triggers: true, tableComment: false });
expect(unloadedTableStructureRefreshScope("triggers", new Set(["comment"]))).toEqual({ columns: false, indexes: false, foreignKeys: false, constraints: false, triggers: true, tableComment: false });
expect(hasTableStructureRefreshWork(unloadedTableStructureRefreshScope("triggers", new Set(["triggers", "comment"])))).toBe(false);
});
it("requests constraint metadata only until that facet is loaded", () => {
expect(unloadedTableStructureRefreshScope("constraints", new Set(["comment"]))).toEqual({ columns: false, indexes: false, foreignKeys: false, constraints: true, triggers: false, tableComment: false });
expect(hasTableStructureRefreshWork(unloadedTableStructureRefreshScope("constraints", new Set(["constraints", "comment"])))).toBe(false);
});
});
@@ -44,7 +44,7 @@ async function deleteSchemaCachePrefixSafe(prefix: string): Promise<void> {
}
}
export type ObjectMetadataFacet = "columns" | "indexes" | "foreign-keys" | "triggers" | "comment";
export type ObjectMetadataFacet = "columns" | "indexes" | "foreign-keys" | "constraints" | "triggers" | "comment";
function cacheSegment(value: string | undefined): string {
return encodeURIComponent(value ?? "");
@@ -7,8 +7,15 @@ describe("tableMetadataCapabilities", () => {
columns: false,
indexes: true,
foreignKeys: false,
constraints: false,
triggers: false,
ddl: false,
});
});
it("exposes structured constraints only for dialects that implement list_constraints", () => {
expect(getTableMetadataCapabilities("oracle").constraints).toBe(true);
expect(getTableMetadataCapabilities("mysql").constraints).toBe(false);
expect(getTableMetadataCapabilities(undefined).constraints).toBe(false);
});
});
@@ -4,6 +4,7 @@ export interface TableMetadataCapabilities {
columns: boolean;
indexes: boolean;
foreignKeys: boolean;
constraints: boolean;
triggers: boolean;
ddl: boolean;
}
@@ -12,11 +13,18 @@ const defaultCapabilities: TableMetadataCapabilities = {
columns: true,
indexes: true,
foreignKeys: true,
// Structured PK/UNIQUE/CHECK constraint metadata (list_constraints) is only
// implemented by a handful of agent-backed drivers today; leave it off by
// default so every other dialect doesn't grow a permanently empty tab.
constraints: false,
triggers: true,
ddl: true,
};
const capabilityByType: Partial<Record<DatabaseType, Partial<TableMetadataCapabilities>>> = {
oracle: {
constraints: true,
},
mongodb: {
columns: false,
foreignKeys: false,
@@ -108,11 +116,19 @@ export function firstStructureMetadataTab(capabilities: TableMetadataCapabilitie
if (capabilities.columns) return "columns";
if (capabilities.indexes) return "indexes";
if (capabilities.foreignKeys) return "foreignKeys";
if (capabilities.constraints) return "constraints";
if (capabilities.triggers) return "triggers";
if (!isCreateMode && capabilities.ddl) return "ddl";
return "columns";
}
export function isStructureMetadataTabSupported(tab: TableInfoTab, capabilities: TableMetadataCapabilities, isCreateMode: boolean): boolean {
return (tab === "columns" && capabilities.columns) || (tab === "indexes" && capabilities.indexes) || (tab === "foreignKeys" && capabilities.foreignKeys) || (tab === "triggers" && capabilities.triggers) || (tab === "ddl" && capabilities.ddl && !isCreateMode);
return (
(tab === "columns" && capabilities.columns) ||
(tab === "indexes" && capabilities.indexes) ||
(tab === "foreignKeys" && capabilities.foreignKeys) ||
(tab === "constraints" && capabilities.constraints) ||
(tab === "triggers" && capabilities.triggers) ||
(tab === "ddl" && capabilities.ddl && !isCreateMode)
);
}
@@ -5,6 +5,7 @@ export interface TableStructureRefreshScope {
columns: boolean;
indexes: boolean;
foreignKeys: boolean;
constraints: boolean;
triggers: boolean;
tableComment: boolean;
}
@@ -12,15 +13,17 @@ export interface TableStructureRefreshScope {
export function visibleTableStructureRefreshScope(activeTab: TableInfoTab): TableStructureRefreshScope {
switch (activeTab) {
case "columns":
return { columns: true, indexes: false, foreignKeys: false, triggers: false, tableComment: true };
return { columns: true, indexes: false, foreignKeys: false, constraints: false, triggers: false, tableComment: true };
case "indexes":
return { columns: true, indexes: true, foreignKeys: false, triggers: false, tableComment: true };
return { columns: true, indexes: true, foreignKeys: false, constraints: false, triggers: false, tableComment: true };
case "foreignKeys":
return { columns: true, indexes: false, foreignKeys: true, triggers: false, tableComment: true };
return { columns: true, indexes: false, foreignKeys: true, constraints: false, triggers: false, tableComment: true };
case "constraints":
return { columns: false, indexes: false, foreignKeys: false, constraints: true, triggers: false, tableComment: true };
case "triggers":
return { columns: false, indexes: false, foreignKeys: false, triggers: true, tableComment: true };
return { columns: false, indexes: false, foreignKeys: false, constraints: false, triggers: true, tableComment: true };
case "ddl":
return { columns: false, indexes: false, foreignKeys: false, triggers: false, tableComment: false };
return { columns: false, indexes: false, foreignKeys: false, constraints: false, triggers: false, tableComment: false };
}
}
@@ -30,11 +33,12 @@ export function unloadedTableStructureRefreshScope(activeTab: TableInfoTab, load
columns: visibleScope.columns && !loadedFacets.has("columns"),
indexes: visibleScope.indexes && !loadedFacets.has("indexes"),
foreignKeys: visibleScope.foreignKeys && !loadedFacets.has("foreign-keys"),
constraints: visibleScope.constraints && !loadedFacets.has("constraints"),
triggers: visibleScope.triggers && !loadedFacets.has("triggers"),
tableComment: visibleScope.tableComment && !loadedFacets.has("comment"),
};
}
export function hasTableStructureRefreshWork(scope: TableStructureRefreshScope): boolean {
return scope.columns || scope.indexes || scope.foreignKeys || scope.triggers || scope.tableComment;
return scope.columns || scope.indexes || scope.foreignKeys || scope.constraints || scope.triggers || scope.tableComment;
}
+1 -1
View File
@@ -1019,7 +1019,7 @@ function normalizeToolbarItems(items: Partial<ToolbarItems> | undefined): Toolba
};
}
const TABLE_INFO_TABS = new Set<TableInfoTab>(["ddl", "columns", "indexes", "foreignKeys", "triggers"]);
const TABLE_INFO_TABS = new Set<TableInfoTab>(["ddl", "columns", "indexes", "foreignKeys", "constraints", "triggers"]);
function normalizeTableInfoTab(value: unknown): TableInfoTab {
return typeof value === "string" && TABLE_INFO_TABS.has(value as TableInfoTab) ? (value as TableInfoTab) : DEFAULT_EDITOR_SETTINGS.tableInfoActiveTab;
+3 -1
View File
@@ -1037,7 +1037,7 @@ export interface TableNameFilter {
excludePatterns: string[];
}
export type TableInfoTab = "columns" | "indexes" | "foreignKeys" | "triggers" | "ddl";
export type TableInfoTab = "columns" | "indexes" | "foreignKeys" | "constraints" | "triggers" | "ddl";
export interface TableStructureEditorTarget {
kind: "column" | "index";
@@ -1053,6 +1053,8 @@ export interface TableStructureEditorDraft {
columns: import("@/lib/table/tableStructureEditorSql").EditableStructureColumn[];
indexes: import("@/lib/table/tableStructureEditorSql").EditableStructureIndex[];
foreignKeys: import("@/lib/table/tableStructureEditorSql").EditableStructureForeignKey[];
constraints?: ConstraintInfo[];
constraintsLoaded?: boolean;
triggers: import("@/lib/table/tableStructureEditorSql").EditableStructureTrigger[];
triggersLoaded?: boolean;
loadedMetadataFacets?: import("@/lib/metadata/objectMetadataCache").ObjectMetadataFacet[];